Commit Graph

463 Commits

Author SHA1 Message Date
hsiegeln
95a92ae9e5 feat: add vendor InfrastructureController for platform:admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 23:16:18 +02:00
hsiegeln
5aa8586940 feat: add InfrastructureService with PG and CH queries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 23:15:18 +02:00
hsiegeln
776a01d87b feat: set INFRASTRUCTUREENDPOINTS=false on tenant server containers
Adds CAMELEER_SERVER_SECURITY_INFRASTRUCTUREENDPOINTS=false to the env
var list injected into provisioned tenant server containers, disabling
the Database and ClickHouse admin endpoints (returns 404) on SaaS-
managed instances. The server defaults to true (standalone mode).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 23:13:28 +02:00
hsiegeln
0b736a92f9 docs: update env var references to new naming convention
All checks were successful
CI / build (push) Successful in 1m51s
CI / docker (push) Successful in 19s
architecture.md runtime/deployment section rewritten with correct
CAMELEER_SAAS_PROVISIONING_* and CAMELEER_SERVER_* env vars.
user-manual.md updated container resource env vars and removed
stale CAMELEER_TENANT_SLUG reference. HOWTO.md cleaned up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:56:21 +02:00
hsiegeln
df90814cc3 Update OIDC env vars for server's nested oidc.* grouping
All checks were successful
CI / build (push) Successful in 1m47s
CI / docker (push) Successful in 1m2s
Align DockerTenantProvisioner env vars with the server's new
cameleer.server.security.oidc.* namespace:
  CAMELEER_SERVER_SECURITY_OIDC_ISSUERURI
  CAMELEER_SERVER_SECURITY_OIDC_JWKSETURI
  CAMELEER_SERVER_SECURITY_OIDC_AUDIENCE
  CAMELEER_SERVER_SECURITY_OIDC_TLSSKIPVERIFY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:30:41 +02:00
hsiegeln
8cf44f6e2c Migrate config to cameleer.saas.* naming convention
All checks were successful
CI / build (push) Successful in 1m49s
CI / docker (push) Successful in 55s
Move all SaaS configuration properties under the cameleer.saas.*
namespace with all-lowercase dot-separated names and mechanical env var
mapping. Aligns with the server (cameleer.server.*) and agent
(cameleer.agent.*) conventions.

Changes:
- Move cameleer.identity.* → cameleer.saas.identity.*
- Move cameleer.provisioning.* → cameleer.saas.provisioning.*
- Move cameleer.certs.* → cameleer.saas.certs.*
- Rename kebab-case properties to concatenated lowercase
- Update all env vars to CAMELEER_SAAS_* mechanical mapping
- Update DockerTenantProvisioner to pass CAMELEER_SERVER_* env vars
  to provisioned server containers (matching server's new convention)
- Spring JWT config now derives from SaaS properties via cross-reference
- Clean up orphaned properties in application-local.yml
- Update docker-compose.yml, docker-compose.dev.yml, .env.example
- Update CLAUDE.md, HOWTO.md, architecture.md, user-manual.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:11:21 +02:00
hsiegeln
5e69628a51 docs: update CLAUDE.md with upgrade, password mgmt, TLS, cleanup
All checks were successful
CI / build (push) Successful in 1m50s
CI / docker (push) Successful in 19s
- VendorTenantService: upgrade server (force-pull + re-provision)
- TenantPortalService: password management, server upgrade
- DockerTenantProvisioner: upgrade(), full cleanup in remove(), GDPR
- Traefik TLS: default cert in dynamic config (v3 compatibility)
- CA trust: server entrypoint imports ca.pem into JVM truststore
- LogtoManagementClient: password updates via correct endpoint
- ServerApiClient: server admin password reset
- UI: tenant dashboard/settings password and upgrade controls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 12:07:41 +02:00
hsiegeln
9163f919c8 fix: move TLS default cert config to Traefik dynamic config
All checks were successful
CI / build (push) Successful in 1m17s
CI / docker (push) Successful in 13s
Traefik v3 ignores tls.stores.default in the static config, causing it
to serve its auto-generated fallback cert instead of the platform cert.
Moving the default certificate store to the dynamic config (file
provider) fixes this — Traefik now serves the correct cert and also
picks up cert rotations without a restart.

This was the root cause of OIDC PKIX failures: the server imported the
CA into its JVM truststore, but Traefik was serving a different cert
entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:45:02 +02:00
hsiegeln
3b8b76d53e chore: update @cameleer/design-system to 0.1.44
All checks were successful
CI / build (push) Successful in 1m10s
CI / docker (push) Successful in 55s
Error toasts now persist until manually dismissed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:01:44 +02:00
hsiegeln
e5523c969e fix: use correct Logto endpoint for password updates
All checks were successful
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 43s
PATCH /api/users/{id}/password, not /api/users/{id}. The general user
update endpoint rejected the password field with 422.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 10:57:28 +02:00
hsiegeln
e2e5c794a2 feat: add server upgrade action — force-pull latest images and re-provision
All checks were successful
CI / build (push) Successful in 1m19s
CI / docker (push) Successful in 48s
Restart only stops/starts existing containers with the same image. The new
upgrade action removes server + UI containers, force-pulls the latest
Docker images, then re-provisions (preserving app containers, volumes, and
networks). Available to both vendor (tenant detail) and tenant admin
(dashboard).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 10:45:45 +02:00
hsiegeln
d5eead888d feat: server admin password reset via tenant portal
All checks were successful
CI / build (push) Successful in 2m23s
CI / docker (push) Successful in 1m8s
- POST /api/tenant/server/admin-password — resets server's built-in
  admin password via M2M API call to the tenant's server
- Settings page: "Server Admin Password" card
- ServerApiClient.resetServerAdminPassword() calls server's password
  reset endpoint with M2M token

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 09:46:30 +02:00
hsiegeln
4121bd64b2 feat: password management for tenant portal
All checks were successful
CI / build (push) Successful in 1m15s
CI / docker (push) Successful in 47s
- POST /api/tenant/password — change own Logto password
- POST /api/tenant/team/{userId}/password — reset team member password
- Settings page: "Change Password" card with confirm field
- Team page: "Reset Password" button per member with inline form
- LogtoManagementClient.updateUserPassword() via Logto Management API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 09:19:48 +02:00
hsiegeln
dd8553a8b4 feat: full tenant cleanup on delete — Docker resources, PG schema, CH data (#55)
All checks were successful
CI / build (push) Successful in 2m23s
CI / docker (push) Successful in 1m6s
DockerTenantProvisioner.remove() now cleans up all tenant Docker resources:
containers (by cameleer.tenant label), env networks, tenant network, JAR volume.
TenantDataCleanupService drops the tenant's PostgreSQL schema and deletes all
ClickHouse data for GDPR compliance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 09:10:47 +02:00
hsiegeln
3284304c1f fix: remove dead /server/ fallback redirect
All checks were successful
CI / build (push) Successful in 1m14s
CI / docker (push) Successful in 46s
When no org is resolved, redirect to /tenant instead of the
non-existent /server/ path. Fixes login redirect loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 08:39:14 +02:00
hsiegeln
6f8b84fb1a fix: re-provision containers when restart finds them missing
All checks were successful
CI / build (push) Successful in 1m22s
CI / docker (push) Successful in 39s
When Docker containers have been removed (e.g. manual cleanup or image
update), restart now falls back to full re-provisioning instead of
failing with 404. Applies to both vendor and tenant portal restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 08:37:04 +02:00
hsiegeln
d2caa737b9 chore: update @cameleer/design-system to v0.1.43 (FileInput)
All checks were successful
CI / build (push) Successful in 1m10s
CI / docker (push) Successful in 29s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 08:07:39 +02:00
hsiegeln
875b07fb3a feat: use FileInput DS component for file uploads, fix certs volume perms
All checks were successful
CI / build (push) Successful in 1m24s
CI / docker (push) Successful in 1m12s
- Replace inline FileField and native <input type="file"> with
  FileInput from @cameleer/design-system (drag-and-drop, icons, clear)
- Update CertificatesPage and SsoPage to use FileInput + FormField
- Fix /certs volume permissions (chmod 775) so cameleer user can write

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 08:04:47 +02:00
hsiegeln
4fdf171912 fix: don't show stale CA banner when no CA bundle exists
Some checks failed
CI / build (push) Successful in 1m39s
CI / docker (push) Successful in 37s
SonarQube Analysis / sonarqube (push) Failing after 1m44s
The self-signed bootstrap cert has no CA bundle, so newly created tenants
with ca_applied_at=NULL are not actually stale. Skip the count when the
active cert has hasCa=false.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:21:26 +02:00
hsiegeln
2239d3d980 docs: update CLAUDE.md and HOWTO.md for fleet health and recent changes
All checks were successful
CI / build (push) Successful in 2m13s
CI / docker (push) Successful in 11s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:10:11 +02:00
hsiegeln
8eef7e170b feat: show agent/env counts in vendor tenant list
All checks were successful
CI / build (push) Successful in 1m20s
CI / docker (push) Successful in 48s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:02:46 +02:00
hsiegeln
d7ce0aaf8c feat: add agent/env counts to vendor tenant list endpoint
Extend VendorTenantSummary with agentCount, environmentCount, and
agentLimit fields. Fetch counts in parallel using CompletableFuture
per tenant, only calling server API for ACTIVE tenants with RUNNING
servers. Agent limit extracted from license limits JSONB.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:01:02 +02:00
hsiegeln
a0c12b8ee6 chore: update DS to v0.1.42
All checks were successful
CI / build (push) Successful in 2m3s
CI / docker (push) Successful in 1m14s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:02:32 +02:00
hsiegeln
a5445e332e fix: fetch actual agent/environment counts from server for tenant dashboard
All checks were successful
CI / build (push) Successful in 1m8s
CI / docker (push) Successful in 43s
The dashboard was showing hardcoded zeroes for agent and environment usage.
Now fetches real counts via M2M API from the tenant's server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 20:35:24 +02:00
hsiegeln
cab6e409b9 fix: show public endpoint instead of internal Docker URL in tenant settings
All checks were successful
CI / build (push) Successful in 1m21s
CI / docker (push) Successful in 38s
Closes #51

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 20:29:54 +02:00
hsiegeln
0fe084bcb2 fix: restrict key.pem file permissions to 0600 (owner-only)
All checks were successful
CI / build (push) Successful in 1m6s
CI / docker (push) Successful in 34s
All private key writes now use writeAtomicRestricted which sets POSIX
owner-read/write permissions after writing. Gracefully skips on
non-POSIX filesystems (Windows dev).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:49:07 +02:00
hsiegeln
3ae8fa18cd feat: support password-protected private keys
All checks were successful
CI / build (push) Successful in 1m8s
CI / docker (push) Successful in 42s
Encrypted PKCS#8 private keys are decrypted during staging using the
provided password. The decrypted key is stored for Traefik (which needs
cleartext PEM). Unencrypted keys continue to work without a password.

- CertificateManager.stage() accepts optional keyPassword
- DockerCertificateManager handles EncryptedPrivateKeyInfo decryption
- UI: password field in upload form (vendor CertificatesPage)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:44:09 +02:00
hsiegeln
82f62ca0ff docs: add tenant CA cert management to CLAUDE.md and HOWTO.md
All checks were successful
CI / build (push) Successful in 1m8s
CI / docker (push) Successful in 12s
- TenantCaCertEntity, TenantCaCertRepository, TenantCaCertService
- TenantPortalController CA endpoints
- V013 migration
- Tenant portal API reference updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:36:51 +02:00
hsiegeln
dd30ee77d4 feat: tenant CA certificate management with staging
Some checks failed
CI / build (push) Successful in 1m7s
CI / docker (push) Has been cancelled
Tenants can upload multiple CA certificates for enterprise SSO providers
that use private certificate authorities.

- New tenant_ca_certs table (V013) with PEM storage in DB
- Stage/activate/delete lifecycle per CA cert
- Aggregated ca.pem rebuild on activate/delete (atomic .wip swap)
- REST API: GET/POST/DELETE on /api/tenant/ca
- UI: CA Certificates section on SSO page with upload, activate, remove

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:35:04 +02:00
hsiegeln
a3a6f99958 fix: prevent vendor redirect to /tenant on hard refresh
All checks were successful
CI / build (push) Successful in 1m6s
CI / docker (push) Successful in 42s
RequireScope and LandingRedirect now wait for scopesReady flag before
evaluating, preventing the race where org-scoped tokens load before
global tokens and the vendor gets incorrectly redirected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:16:46 +02:00
hsiegeln
22752ffcb1 fix: polish CertificatesPage layout
All checks were successful
CI / build (push) Successful in 1m7s
CI / docker (push) Successful in 44s
- Truncate fingerprint with hover tooltip
- Remove duplicate warning icon in stale banner
- Style file inputs to match design system
- Bump grid min-width for better card spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:04:16 +02:00
hsiegeln
a48c4bfd08 docs: update CLAUDE.md and HOWTO.md for all session changes
All checks were successful
CI / build (push) Successful in 1m5s
CI / docker (push) Successful in 9s
- Certificate management (provider interface, lifecycle, bootstrap, UI)
- Async tenant provisioning with polling UX
- Server restart capability (vendor + tenant)
- Audit log actor name resolution from Logto
- SSO connector management, vendor audit page
- Updated API reference with all current endpoints
- Fixed architecture table (per-tenant containers are dynamic)
- Updated migration list through V012

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 18:41:41 +02:00
hsiegeln
45bcc954ac feat: certificate management with stage/activate/restore lifecycle
All checks were successful
CI / build (push) Successful in 1m8s
CI / docker (push) Successful in 45s
Provider-based architecture (Docker now, K8s later):
- CertificateManager interface + DockerCertificateManager (file-based)
- Atomic swap via .wip files for safe cert replacement
- Stage -> Activate -> Archive lifecycle with one-deep rollback
- Bootstrap supports user-supplied certs via CERT_FILE/KEY_FILE/CA_FILE
- CA bundle aggregates platform + tenant CAs, distributed to containers
- Vendor UI: Certificates page with upload, activate, restore, discard
- Stale tenant tracking (ca_applied_at) with restart banner
- Conditional TLS skip removal when CA bundle exists

Includes design spec, migration V012, service + controller tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 18:29:02 +02:00
hsiegeln
51a1aef10e fix: hide server dashboard link for vendor, remove fingerprint icon
All checks were successful
CI / build (push) Successful in 52s
CI / docker (push) Successful in 43s
Vendor persona doesn't need "Open Server Dashboard" in sidebar footer.
Removed inline Fingerprint icon from Identity (Logto) menu item.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:49:40 +02:00
hsiegeln
2607ef5dbe fix: resolve actor name from Logto for audit log entries
All checks were successful
CI / build (push) Successful in 50s
CI / docker (push) Successful in 32s
AuditService now looks up username/name/email from Logto Management API
when actorEmail is null, with an in-memory cache to avoid repeated calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:47:43 +02:00
hsiegeln
0a1e848ef7 fix: return 204 No Content from restart endpoints
All checks were successful
CI / build (push) Successful in 52s
CI / docker (push) Successful in 34s
Empty 200 responses caused JSON parse errors in the API client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:41:17 +02:00
hsiegeln
6dc5e558a3 chore: bump @cameleer/design-system to 0.1.41
All checks were successful
CI / build (push) Successful in 51s
CI / docker (push) Successful in 52s
Picks up Spinner animation fix (missing @keyframes in CSS module).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:38:40 +02:00
hsiegeln
a3a1643b37 fix: update VendorTenantServiceTest for async provisioning
All checks were successful
CI / build (push) Successful in 50s
CI / docker (push) Successful in 45s
Tests now mock tenantRepository.findById() since provisionAsync re-loads
the tenant entity, and assert on the entity directly rather than the
return value of createAndProvision().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:28:51 +02:00
hsiegeln
4447d79c92 fix: add missing TenantProvisioner mock to TenantPortalServiceTest
Some checks failed
CI / build (push) Failing after 40s
CI / docker (push) Has been skipped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:25:37 +02:00
hsiegeln
7e7a07470b feat: add restart server action for vendor and tenant
Some checks failed
CI / build (push) Failing after 36s
CI / docker (push) Has been skipped
Vendor: POST /api/vendor/tenants/{id}/restart (platform:admin scope)
Tenant: POST /api/tenant/server/restart (tenant:manage scope)

Both call TenantProvisioner.stop() then start() on the server + UI
containers. Restart button on vendor TenantDetailPage (Actions card)
and tenant TenantDashboardPage (Server card). Allowed in any status
including PROVISIONING.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:21:14 +02:00
hsiegeln
252c18bcff feat: async tenant provisioning with polling UX
Some checks failed
CI / build (push) Failing after 39s
CI / docker (push) Has been skipped
Backend: extract Docker provisioning into @Async method so the API
returns immediately with status=PROVISIONING. The tenant record, Logto
org, admin user, and license are created synchronously; container
provisioning, health check, license push, and OIDC config happen in a
background thread.

Frontend: navigate to tenant detail page immediately after creation.
Detail page polls every 3s while status=PROVISIONING and shows a
spinner indicator. Toast notification when provisioning completes.
Fixes #52.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:14:26 +02:00
hsiegeln
269c679e9c fix: remove server-specific providers now that TopBar is decomposed
All checks were successful
CI / build (push) Successful in 1m9s
CI / docker (push) Successful in 49s
Update to @cameleer/design-system@0.1.40 where TopBar no longer depends
on GlobalFilterProvider or CommandPaletteProvider. Remove these
unnecessary provider wrappers from main.tsx. Fixes #53.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:06:16 +02:00
hsiegeln
e559267f1e feat: replace tenant OIDC page with Enterprise SSO connector management
All checks were successful
CI / build (push) Successful in 1m3s
CI / docker (push) Successful in 46s
- Add LogtoManagementClient methods for SSO connector CRUD + org JIT
- Add TenantSsoService with tenant isolation (validates connector-org link)
- Add TenantSsoController at /api/tenant/sso with test endpoint
- Create SsoPage with provider selection, dynamic config form, test button
- Remove old OIDC config endpoints from tenant portal (server OIDC is
  now platform-managed, set during provisioning)
- Sidebar: OIDC -> SSO with Shield icon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:48:51 +02:00
hsiegeln
4341656a5e refactor: remove additionalScopes from OIDC config push
All checks were successful
CI / build (push) Successful in 1m34s
CI / docker (push) Successful in 56s
Server now hardcodes Logto org scopes in the auth flow, so the
provisioner no longer needs to push them via OIDC config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:37:53 +02:00
hsiegeln
2cda065c06 fix: register /platform/ as post-logout redirect URI, improve sidebar contrast
All checks were successful
CI / build (push) Successful in 52s
CI / docker (push) Successful in 44s
- Add /platform/ to SPA postLogoutRedirectUris in bootstrap (fixes #54)
- Use amber color + bold for active vendor sidebar items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:41:18 +02:00
hsiegeln
bcad83cc40 fix: use JdbcTemplate for audit queries (match server pattern)
All checks were successful
CI / build (push) Successful in 53s
CI / docker (push) Successful in 34s
Replace JPQL @Query with dynamic SQL via JdbcTemplate to avoid
Hibernate null parameter type issues (bytea vs text). Conditionally
appends WHERE clauses only for non-null filters, matching the proven
pattern from cameleer3-server's PostgresAuditRepository.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:31:02 +02:00
hsiegeln
0d47c2ec7c fix: avoid null bytea in audit search JPQL
All checks were successful
CI / build (push) Successful in 51s
CI / docker (push) Successful in 32s
Hibernate binds null String params as bytea, causing PostgreSQL
lower(bytea) error. Convert null search to empty string in service
layer, use empty-string check in JPQL instead of IS NULL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:26:18 +02:00
hsiegeln
247ec030e5 fix: use COALESCE in audit JPQL to prevent lower(bytea) error
All checks were successful
CI / build (push) Successful in 51s
CI / docker (push) Successful in 31s
Hibernate passes null search param as bytea type, causing PostgreSQL
to fail on LOWER(bytea). COALESCE converts null to empty string.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:21:20 +02:00
hsiegeln
a1acc0bc62 fix: permit SPA routes /vendor/** and /tenant/** for direct navigation
All checks were successful
CI / build (push) Successful in 49s
CI / docker (push) Successful in 32s
Without this, hard refresh on SPA routes returns 401 because Spring
Security intercepts before SpaController can forward to index.html.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:15:08 +02:00
hsiegeln
8b94937d38 feat: add audit log viewing for vendor and tenant personas
All checks were successful
CI / build (push) Successful in 52s
CI / docker (push) Successful in 40s
Vendor sees all audit events with tenant filter at /vendor/audit.
Tenant admin sees only their own events at /tenant/audit.
Both support pagination, action/result filters, and text search.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:07:18 +02:00