Commit Graph

613 Commits

Author SHA1 Message Date
hsiegeln
1066101e8a fix: add Gitea Maven repository for cameleer-license-minter resolution
All checks were successful
CI / build (push) Successful in 2m31s
CI / docker (push) Successful in 1m25s
CI needs to resolve com.cameleer:cameleer-license-minter from the
Gitea package registry. Without this repository declaration, the
dependency only resolved from the local Maven cache.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 19:31:27 +02:00
hsiegeln
ffb7ef0839 feat(ui): add license minting form, verify tool, and update all pages
Some checks failed
CI / build (push) Successful in 2m42s
CI / docker (push) Failing after 51s
Vendor UI:
- TenantDetailPage: full minting form with tier presets, 13 configurable
  limits, expiry/grace period, label. Mint & Push or Mint & Copy actions.
  License bundle display with all three env vars for standalone deployment.
- LicenseVerifyPage: paste token to decode + validate signature, shows
  envelope details and state badge. Public key viewer with copy button.
- Layout: added "License Tools" nav item under Vendor section.
- vendor-hooks: useMintLicense, useLicensePresets, useVerifyLicense, usePublicKey

Tenant UI:
- TenantLicensePage: replaced features card with full 13-key limits display,
  added grace period and label fields
- TenantDashboardPage: fixed limit keys (agents→max_agents, environments→max_environments)

Common:
- Updated types (dropped features, added label/gracePeriodDays/bundle types)
- Updated tier colors for STARTER/TEAM/BUSINESS/ENTERPRISE
- Updated CreateTenantPage tier dropdown

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:41:40 +02:00
hsiegeln
4dea1c6764 feat: push Ed25519 public key to tenant server containers
DockerTenantProvisioner now injects CAMELEER_SERVER_LICENSE_PUBLICKEY
env var on provisioned server containers, enabling cryptographic
license validation. SigningKeyService passed through auto-config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:36:06 +02:00
hsiegeln
6c3f21d4db test: update all tests for Ed25519 license minting and tier rename
- LicenseServiceTest: mock SigningKeyService, assert signed token format
- VendorTenantServiceTest: add SigningKeyService mock, update mintLicense stubs
- All tests: LOW→STARTER, MID→TEAM, HIGH→BUSINESS, BUSINESS→ENTERPRISE
- Remove all features-related test assertions
- 80/80 tests passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:33:10 +02:00
hsiegeln
7a8960ca46 feat: add vendor license minting, presets, and verify endpoints
- POST /vendor/tenants/{id}/license now accepts MintLicenseRequest body
  with custom limits, expiresAt, gracePeriodDays, label, pushToServer
- Returns LicenseBundleResponse with token + public key + tenant slug
- GET /vendor/license-presets returns tier preset limits
- POST /vendor/license/verify decodes and validates signed tokens
- GET /vendor/signing-key/public returns the Ed25519 public key
- VendorTenantService.mintLicense() supports configurable minting
- Updated portal DTOs to drop features, add label + gracePeriodDays

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:24:23 +02:00
hsiegeln
fdc7187424 feat: rewrite LicenseService to mint Ed25519-signed tokens
Replaces UUID token generation with LicenseMinter.mint() from
cameleer-license-minter. Adds full-control generateLicense() overload
accepting custom limits, expiry, grace period, and label.
Adds verifyToken() and verifyTokenSignature() using LicenseValidator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:22:05 +02:00
hsiegeln
2fd14165bc feat: add SigningKeyService for Ed25519 keypair management
Entity, repository, and service for generating and storing Ed25519
signing keys. Lazy-initializes on first call — generates keypair
and persists to signing_keys table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:21:16 +02:00
hsiegeln
13bd03997a refactor: rename tiers and rewrite LicenseDefaults to 13-key cap matrix
- Tier enum: LOW→STARTER, MID→TEAM, HIGH→BUSINESS, BUSINESS→ENTERPRISE
- LicenseDefaults: 13-key limits per tier matching server handoff cap matrix
- Drop features concept from LicenseEntity, LicenseResponse, portal DTOs
- Add label and gracePeriodDays to LicenseEntity
- Fix agent limit key from 'agents' to 'max_agents' in VendorTenantController

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:20:22 +02:00
hsiegeln
e64bf4f0d1 feat: add cameleer-license-minter dependency and V002 migration
Adds Ed25519 license minting library, signing_keys table,
renames tiers (LOW→STARTER, MID→TEAM, HIGH→BUSINESS, BUSINESS→ENTERPRISE),
adds label + grace_period_days to licenses, drops features column.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 17:17:44 +02:00
hsiegeln
883e10ba7c feat: test SMTP connection on save and retain password on edit
All checks were successful
CI / build (push) Successful in 2m20s
CI / docker (push) Successful in 1m36s
Adds testSmtpConnection() that performs EHLO + auth via JavaMailSender
before persisting to Logto — saves fail fast with a clear error if
SMTP credentials are wrong. Password is now optional when editing:
if left blank the backend fetches the existing password from Logto's
connector config, so users can update host/port/fromEmail without
re-entering the password every time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 16:23:42 +02:00
hsiegeln
0413a5b882 fix: remove HTML document wrapper from email templates for GMX compat
All checks were successful
CI / build (push) Successful in 2m12s
CI / docker (push) Successful in 1m5s
GMX webmail broke after adding <!DOCTYPE html><html><head><body>
wrappers — the Logto SMTP connector sets these as nodemailer's html
field, and GMX's sanitizer chokes on a full document inside its own
page shell. Reverts to bare HTML fragments (the format that worked
before 12:17 commit 484a388) while keeping the extra text paragraphs
added for mail checker text-to-HTML ratio compliance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 16:08:04 +02:00
hsiegeln
c6b6bafc0f fix: revert email templates to inline styles for GMX webmail compat
All checks were successful
CI / build (push) Successful in 1m59s
CI / docker (push) Successful in 1m52s
GMX webmail strips <head> content including <style> blocks, rendering
emails as unstyled plain text. Reverts to inline styles (the only
reliable approach for email HTML) while keeping the proper HTML document
structure and extra text content added for mail checker compliance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 15:56:10 +02:00
hsiegeln
988035b952 fix: handle MFA binding skip during registration submit
The registration flow hit a 422 on /api/experience/submit when MFA
policy is UserControlled. Adds the same trySubmit + skipMfaBinding
pattern already used in the sign-in flow — Logto confirms mfa-skipped
works for both SignIn and Register interaction events.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 15:52:46 +02:00
hsiegeln
c55427c22b fix: restore watermark image in email templates
All checks were successful
CI / build (push) Successful in 2m18s
CI / docker (push) Successful in 1m10s
The previous commit incorrectly removed the watermark — only the
style extraction into <style> blocks was requested. Restores the
watermark <img>, {{watermarkUrl}} placeholder resolution in both
EmailConnectorService and PasswordResetNotificationService, and
the corresponding test assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 15:14:35 +02:00
hsiegeln
f681784e7e fix: move email styles to <style> block and remove watermark image
Some checks failed
CI / build (push) Successful in 1m59s
CI / docker (push) Has been cancelled
Extracts repeated inline styles into <head> <style> to improve the
text-to-HTML ratio flagged by mail checkers. Removes the decorative
watermark <img> (opacity 0.07, barely visible) which was the only
image element and triggered the "too many images" classification.
Cleans up the now-unused ProvisioningProperties dependency from
EmailConnectorService and PasswordResetNotificationService.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 15:11:53 +02:00
hsiegeln
7b57ee8246 fix: add proper HTML document structure and more text to email templates
All checks were successful
CI / build (push) Successful in 2m35s
CI / docker (push) Successful in 1m6s
Mail checkers flagged missing <html> tag and insufficient text content.
Wraps all 5 templates in DOCTYPE/html/head/body, adds Outlook conditional
comments, and includes a descriptive paragraph to improve text-to-image ratio.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 14:57:47 +02:00
hsiegeln
6e6e4218c9 fix: skip MFA binding prompt for UserControlled policy during sign-in
All checks were successful
CI / build (push) Successful in 2m1s
CI / docker (push) Successful in 59s
Logto returns 422 with an MFA recommendation when policy is
UserControlled. Call POST /profile/mfa/mfa-skipped to skip the
binding prompt, then re-submit. Users who already have MFA enrolled
still get the TOTP verification flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 14:43:55 +02:00
hsiegeln
469b36613b fix: resolve CI type errors in TeamPage and install qrcode.react
All checks were successful
CI / build (push) Successful in 2m52s
CI / docker (push) Successful in 2m16s
- Change Button size="small" to size="sm" (design system API)
- Remove unsupported style prop from Card component
- Ensure qrcode.react is properly installed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 14:29:59 +02:00
hsiegeln
bcb8a040f4 docs: add MFA handoff document for cameleer-server team
Some checks failed
CI / build (push) Failing after 38s
CI / docker (push) Has been skipped
Covers JWT mfa_enrolled claim, enforcement model (APP_MFA_REQUIRED),
Logto Management API contract for TOTP enrollment and backup codes,
UX requirements, and error states.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 14:07:27 +02:00
hsiegeln
d52084a081 feat: add Reset MFA action for team members
Adds a Reset MFA button in the Actions column and an inline confirmation
card (with warning Alert) that calls useResetTeamMemberMfa on confirm.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:06:20 +02:00
hsiegeln
7e7407b137 feat: add MFA enrollment and enforcement toggle to Settings page
Adds two new sections to the tenant Settings page:
- MfaSection: TOTP authenticator setup with QR code, 6-digit verification,
  backup code display (2-column grid with copy/download), and MFA removal
- MfaEnforcementToggle: tenant admin control to require MFA for all members,
  with confirmation dialog before enabling

Installs qrcode.react for QR code rendering. Uses existing MFA hooks from
tenant-hooks.ts and design-system components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 14:04:28 +02:00
hsiegeln
0a77080bca feat: add MFA types, hooks, and APP_MFA_REQUIRED interceptor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:01:04 +02:00
hsiegeln
a5b30cd1ea feat: add password reset security notification email endpoint
Adds POST /api/password-reset-notification (public, rate-limited 3/10min)
that sends a branded HTML security notification email via the runtime-
configured Logto SMTP connector. Uses spring-boot-starter-mail with a
programmatic JavaMailSender built from the connector's live credentials.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:59:23 +02:00
hsiegeln
ffb65edcec feat: add MFA enforcement filter with APP_MFA_REQUIRED error code
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:56:25 +02:00
hsiegeln
8b8909e488 feat: add MFA enrollment, removal, and settings endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 13:53:44 +02:00
hsiegeln
94de4c2a5b feat: add MFA Management API methods to LogtoManagementClient
Add 5 new methods for MFA operations via Logto Management API:
- getUserMfaVerifications: list all MFA factors for a user
- createTotpVerification: create TOTP MFA verification
- createBackupCodes: generate backup codes
- deleteMfaVerification: delete a specific MFA verification
- deleteAllMfaVerifications: delete all MFA verifications (admin reset)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 13:48:29 +02:00
hsiegeln
66477ff575 feat: configure MFA factors + mfa_enrolled JWT claim in Logto bootstrap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:46:10 +02:00
hsiegeln
6c70efcb54 feat: add MFA verification (TOTP + backup code) to sign-in flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:44:28 +02:00
hsiegeln
1f3a9551c5 feat: add forgot-password UI flow to custom sign-in page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:42:51 +02:00
hsiegeln
08a3ad03b7 feat: add forgot-password and MFA verification Experience API functions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:39:31 +02:00
hsiegeln
cfcf852e2d docs: add password reset and MFA implementation plan
12-task plan covering:
- Password reset Experience API + sign-in UI
- MFA verification at sign-in (TOTP + backup codes)
- Logto bootstrap MFA config + mfa_enrolled JWT claim
- LogtoManagementClient MFA methods
- MFA enrollment endpoints + Settings page UI
- MFA enforcement filter (APP_MFA_REQUIRED)
- Password reset security notification email
- Team page Reset MFA action
- Server handoff document

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 13:35:42 +02:00
hsiegeln
67f7d634c9 docs: refine password reset + MFA spec from review feedback
- Add security notification email after password reset (warns MFA
  was not required, recommends enabling it)
- Use distinct APP_MFA_REQUIRED error code + X-Cameleer-Error header
  for MFA enforcement 403s to avoid collision with generic access denied
- Make backup code fallback prominent in MFA verification UI (visible
  secondary action, not a subtle link)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 13:26:55 +02:00
hsiegeln
6f984c6b78 docs: add password reset and MFA design spec
Covers self-service password reset via Logto Experience API,
TOTP + backup code MFA with per-tenant enforcement via JWT claims,
and a server handoff document for cameleer-server MFA enrollment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 13:20:48 +02:00
hsiegeln
5754b0ca81 fix: set Logto display name from email during onboarding
All checks were successful
CI / build (push) Successful in 2m12s
CI / docker (push) Successful in 1m3s
Email-registered users have no name field in Logto, causing empty OIDC
name claims. After adding user to org, derive display name from email
local part (john.doe@acme.com -> john.doe) if name is not already set.

Also adds updateUserProfile() to LogtoManagementClient.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 12:31:12 +02:00
hsiegeln
484a388b62 fix: prevent grey bar when webmail blocks watermark image
All checks were successful
CI / build (push) Successful in 2m3s
CI / docker (push) Successful in 1m10s
Remove width/height HTML attributes and add border:0;outline:none to
the watermark img tag so broken-image placeholders collapse gracefully
when email clients block remote images.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 12:17:51 +02:00
hsiegeln
d720c0500f fix: force fresh OIDC sign-in after onboarding to pick up new org membership
All checks were successful
CI / build (push) Successful in 1m55s
CI / docker (push) Successful in 1m22s
After creating a tenant, the existing Logto tokens don't include the new
org membership/scopes. A hard page reload reused stale tokens, causing
the SDK to either lose auth state (redirect loop to login) or fail to
resolve org scopes (falling through to server UI instead of tenant UI).

Replace window.location.href with signIn() to trigger a fresh OIDC flow.
The existing Logto session cookie means auto-approval — no login form.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 12:06:39 +02:00
hsiegeln
cfa9d41b36 docs: add email template polish spec, plan, and update GitNexus index
All checks were successful
CI / build (push) Successful in 1m54s
CI / docker (push) Successful in 1m2s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 10:37:41 +02:00
hsiegeln
b974f233f4 feat: load email templates from classpath with watermark URL resolution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 10:35:16 +02:00
hsiegeln
3741ac2658 feat: add branded HTML email templates with desert/caravan copy 2026-04-26 10:31:50 +02:00
hsiegeln
e8a726af80 feat: permit /assets/** for unauthenticated access (email watermark) 2026-04-26 10:30:33 +02:00
hsiegeln
53f0e55e93 feat: add pre-faded logo watermark for email templates 2026-04-26 10:24:02 +02:00
hsiegeln
06d114b46b feat: validate slug uniqueness during onboarding
All checks were successful
CI / build (push) Successful in 1m50s
CI / docker (push) Successful in 1m22s
Add GET /api/onboarding/slug-available endpoint to check if a slug is
already taken. Frontend checks availability with 400ms debounce as the
user types and shows inline feedback. Submit button disabled when slug
is taken. POST /api/onboarding/tenant now returns 409 instead of 500
for duplicate slugs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 09:40:17 +02:00
hsiegeln
171ed1a6ab fix: provisioning race condition and noisy ClickHouse logs
Some checks failed
CI / build (push) Successful in 2m3s
CI / docker (push) Successful in 1m30s
SonarQube Analysis / sonarqube (push) Failing after 2m22s
Defer provisionAsync() until after the transaction commits using
TransactionSynchronization.afterCommit(). Previously the @Async thread
raced the @Transactional commit — findById returned null because the
tenant INSERT wasn't visible yet.

Downgrade ClickHouse UNKNOWN_TABLE errors to DEBUG level in
InfrastructureService. These are expected on fresh installs before any
cameleer-server has created the tables.

Make the onboarding slug field read-only (derived from org name).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 22:05:48 +02:00
hsiegeln
dee1f39554 fix: align button icons and polish vendor sidebar
All checks were successful
CI / build (push) Successful in 2m8s
CI / docker (push) Successful in 1m41s
Fix vertical alignment of Lucide icons inside Button children across
all pages by adding verticalAlign offsets (-3px for 16px icons, -2px
for 14px icons). The design system Button wraps children in an inline
span, so SVG icons defaulted to baseline alignment.

Hide the redundant top-right "Create Tenant" button on VendorTenantsPage
when no tenants exist — the EmptyState already provides that action.

Add icons to all vendor sidebar sub-items for consistency (previously
only Email Connector had one).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 21:30:37 +02:00
hsiegeln
adb4ef1af8 fix: enable email sign-in method alongside username in all modes
All checks were successful
CI / build (push) Successful in 1m50s
CI / docker (push) Successful in 59s
The sign-in experience must always include both email+password and
username+password methods. The admin user signs in with their email
(admin@company.com) which the sign-in UI detects as email type.
With only username method enabled, Logto rejects it with "this
sign-in method is not activated."

Fixes both bootstrap Phase 8c and EmailConnectorService disable path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 21:11:07 +02:00
hsiegeln
4cc3e096b5 fix: bootstrap extracts username from admin email for Logto
All checks were successful
CI / build (push) Successful in 1m47s
CI / docker (push) Successful in 20s
Logto rejects @ in usernames. Extract local part (before @) as the
Logto username, use full email as primaryEmail. Also validates admin
user creation succeeded (logs error instead of silently continuing
with null ID).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 21:03:54 +02:00
hsiegeln
1d26ae481e docs: update user manual for current UI and identity model
All checks were successful
CI / build (push) Successful in 1m58s
CI / docker (push) Successful in 21s
- Sign-in instructions: "Enter your email" (not "email or username")
- Troubleshooting: remove reference to deleted "Sign in with Logto" button
- Sidebar navigation: replace outdated single table with vendor console
  and tenant portal sections reflecting current sidebar structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 20:53:19 +02:00
hsiegeln
8fe18c7f83 feat: unify admin identity — SAAS_ADMIN_USER is the email in SaaS mode
All checks were successful
CI / build (push) Successful in 1m56s
CI / docker (push) Successful in 1m32s
In SaaS mode, SAAS_ADMIN_USER must be an email address. It's used as
both the Logto username and primaryEmail. No separate SAAS_ADMIN_EMAIL.
Installer enforces email format in SaaS mode (moved deployment mode
question before admin credentials), accepts any username in standalone.
Sign-in form label changed to "Login".

Removes SAAS_ADMIN_EMAIL from bootstrap, compose template, installers,
and all documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 20:46:24 +02:00
hsiegeln
929e7d5aed chore: update installer submodule (add SAAS_ADMIN_EMAIL to both installers)
All checks were successful
CI / build (push) Successful in 1m57s
CI / docker (push) Successful in 20s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 20:26:57 +02:00
hsiegeln
3ab6408258 feat: enforce email as primary user identity in SaaS mode
All checks were successful
CI / build (push) Successful in 2m23s
CI / docker (push) Successful in 53s
All users in SaaS mode must have an email address. The bootstrap creates
the admin user with primaryEmail set to SAAS_ADMIN_EMAIL (defaults to
<SAAS_ADMIN_USER>@<PUBLIC_HOST>). This prevents the admin from being
locked out when self-service registration (which requires email) is
enabled via the Email Connector UI.

Documentation updated across all CLAUDE.md files, .env.example,
user-manual.md, and installer submodule (README, .env.example, compose).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 20:23:30 +02:00