Commit Graph

101 Commits

Author SHA1 Message Date
hsiegeln
bf3aa57274 feat: restructure frontend routes — vendor/tenant persona split
Splits the flat 3-page UI into /vendor/* (platform:admin) and /tenant/*
(all authenticated users) route trees, with stub pages, new API hooks,
updated Layout with persona-aware sidebar, and SpaController forwarding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:59 +02:00
hsiegeln
e56e3fca8a feat: tenant portal API (dashboard, license, OIDC, team, settings)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
127834ce4d feat: vendor tenant API with provisioning, suspend, delete
Adds VendorTenantService orchestrating full tenant lifecycle (create,
provision, license push, activate, suspend, delete, renew license),
VendorTenantController at /api/vendor/tenants with platform:admin guard,
LicenseResponse.from() factory, SecurityConfig vendor/tenant path rules,
and TenantIsolationInterceptor bypasses for vendor and tenant portal paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
6bdb02ff5a feat: add per-tenant health, OIDC, team methods to API clients
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
96a5b1d9f1 feat: implement DockerTenantProvisioner with container lifecycle
Replace stub with full Docker implementation using docker-java. Manages
per-tenant server and UI containers with Traefik labels, health checks,
image pull, network attachment, and full lifecycle (provision/start/stop/remove/status).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
771e9d1081 feat: add TenantProvisioner interface with auto-detection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
ebba021448 feat: add provisioning fields to tenants + license revoke
Adds server_endpoint and provision_error columns to tenants table (V011 migration),
updates TenantEntity and TenantResponse with new fields and a from() factory,
adds revokeLicense() to LicenseService, and updates TenantController to use the factory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:29:01 +02:00
hsiegeln
bad78e26a1 feat: add migration to drop migrated tables from SaaS database
- V010: drop deployments, apps, environments, api_keys tables
- Tables have been migrated to cameleer3-server

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 00:00:32 +02:00
hsiegeln
c254fbf723 feat: remove migrated environment/app/deployment/runtime code from SaaS
- Delete environment/, app/, deployment/, runtime/ packages (source + tests)
- Delete apikey/ package (tied to environments, table will be dropped)
- Strip AsyncConfig to empty @EnableAsync (no more deploymentExecutor bean)
- Remove EnvironmentService dependency from TenantService
- Remove environment/app isolation from TenantIsolationInterceptor
- Remove environment seeding from BootstrapDataSeeder
- Refactor ServerApiClient to use LogtoConfig instead of RuntimeConfig
- Add server-endpoint property to LogtoConfig (was in RuntimeConfig)
- Remove runtime config section and multipart config from application.yml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:59:53 +02:00
hsiegeln
160a989f9f feat: remove all ClickHouse dependencies from SaaS layer
- Delete log/ package (ClickHouseConfig, ContainerLogService, LogController)
- Delete observability/ package (AgentStatusService, AgentStatusController)
- Remove clickhouse-jdbc dependency from pom.xml
- Remove cameleer.clickhouse config section from application.yml
- Delete associated test files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:56:21 +02:00
hsiegeln
30aaacb5b5 fix: correct protocol version header, disable SQL logging, document deployment pipeline
All checks were successful
CI / build (push) Successful in 1m9s
CI / docker (push) Successful in 1m43s
SonarQube Analysis / sonarqube (push) Successful in 1m20s
- ServerApiClient: use X-Cameleer-Protocol-Version: 1 (server expects "1", not "2")
- Disable Hibernate show-sql in dev profile (too verbose)
- CLAUDE.md: document deployment pipeline architecture, M2M server role in bootstrap,
  runtime-base image in CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 18:58:27 +02:00
hsiegeln
617785baa7 fix: use full registry path for runtime base image default
All checks were successful
CI / build (push) Successful in 50s
CI / docker (push) Successful in 35s
The default cameleer-runtime-base:latest has no registry prefix, so
Docker can't pull it. Use the full gitea.siegeln.net/cameleer/ path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 18:23:26 +02:00
hsiegeln
d6f488199c fix: rename async executor bean to avoid clash with DeploymentExecutor
All checks were successful
CI / build (push) Successful in 49s
CI / docker (push) Successful in 36s
The @Bean named 'deploymentExecutor' (ThreadPoolTaskExecutor) collided
with the @Service class DeploymentExecutor. Rename the bean to
'deploymentTaskExecutor'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 18:06:10 +02:00
hsiegeln
3f0a27c96e fix: add lenient mock strictness to AgentStatusServiceTest
Some checks failed
CI / build (push) Successful in 1m46s
CI / docker (push) Failing after 45s
The serverApiClient.isAvailable() stubbing in setUp() is unused by
the observability test, causing UnnecessaryStubbingException in CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:48:08 +02:00
hsiegeln
5d04a154f9 refactor: deployment infrastructure cleanup (4 fixes)
Some checks failed
CI / build (push) Failing after 46s
CI / docker (push) Has been skipped
1. Docker socket security: remove root group from Dockerfile, use
   group_add in docker-compose.yml for runtime-only socket access

2. M2M server communication: create ServerApiClient using Logto
   client_credentials grant with API resource scope. Add M2M server
   role in bootstrap. Replace hacky admin/admin login in
   AgentStatusService.

3. Async deployment: extract DeploymentExecutor as separate @Service
   so Spring's @Async proxy works (self-invocation bypasses proxy).
   Deploy now returns immediately, health check runs in background.

4. Bootstrap: M2M server role (cameleer-m2m-server) with server:admin
   scope, idempotent creation outside the M2M app creation block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:08:37 +02:00
hsiegeln
8407d8b3c0 fix: deployment health check, container cleanup, and status reporting
Three fixes for the deployment pipeline:
1. Health check path: /health -> /cameleer/health (matches agent)
2. Container cleanup: stop AND remove old container before starting
   new one, plus orphan cleanup by container name to prevent conflicts
3. Container status: read health.status instead of state.status so
   waitForHealthy correctly detects the "healthy" state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:20:33 +02:00
hsiegeln
ea04eeb6dc fix: switch to zerodep Docker transport for Unix socket support
The httpclient5 transport needs junixsocket for Unix domain sockets.
Switch to docker-java-transport-zerodep which has built-in Unix socket
support with zero external dependencies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:53:39 +02:00
hsiegeln
9c6ab77b72 fix: configure Docker client to use Unix socket
Default docker-java config resolved to localhost:2375 (TCP) inside the
container. Explicitly set docker host to unix:///var/run/docker.sock
which is volume-mounted from the host.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:40:57 +02:00
hsiegeln
00a3f2fd3f feat: runtime base image CI, bootstrap token, and deploy plumbing
Add CI step to build cameleer-runtime-base image by downloading the
agent shaded JAR from Gitea Maven registry and pushing the image.
Wire CAMELEER_AUTH_TOKEN from docker-compose into RuntimeConfig so
deployed containers authenticate with cameleer3-server. Add agent.jar
to gitignore for local builds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:32:42 +02:00
hsiegeln
1a0f1e07be fix: JAR upload — increase multipart limit and fix storage permissions
Spring Boot defaults to 1MB max file size which rejected all JAR
uploads. Set to 200MB to match the configured max-jar-size. Also
create /data/jars with cameleer user ownership in the Dockerfile
so the non-root process can write uploaded JARs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:10:35 +02:00
hsiegeln
8febdba533 feat: per-app resource limits, auto-slug, and polished create dialogs
Add per-app memory limit and CPU shares (stored on AppEntity, used by
DeploymentService with fallback to global defaults). JAR upload is now
optional at creation time. Both create modals show the computed slug in
the dialog title and use consistent Cancel-left/Action-right button
layout with inline styles to avoid Modal CSS conflicts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:53:57 +02:00
hsiegeln
2f7d4bd71c feat: use cameleer3-logo.svg from design-system v0.1.36 everywhere
All checks were successful
CI / build (push) Successful in 1m7s
CI / docker (push) Successful in 3m34s
- Sidebar, sign-in page, and favicons all use the single SVG
- Postinstall copies SVG for SaaS HTML favicon (gitignored)
- Sign-in favicon committed (baked into Logto Docker image)
- Remove old PNG favicon references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:03:18 +02:00
hsiegeln
2e87667734 refactor: import brand icons directly from design-system package
Some checks failed
CI / build (push) Failing after 20s
CI / docker (push) Has been skipped
- Sidebar and sign-in logos use Vite import from @cameleer/design-system
- HTML favicons copied by postinstall script (gitignored)
- Remove manually copied PNGs from repo
- Clean up SecurityConfig permitAll (bundled assets under /_app/**)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:39:29 +02:00
hsiegeln
3a33324b2a fix: permit cameleer-logo-48.png without auth
Some checks failed
CI / build (push) Successful in 48s
CI / docker (push) Has been cancelled
Browser img tags don't send Bearer tokens, so the sidebar logo
needs to be in the permitAll list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:32:16 +02:00
hsiegeln
29daf51ee3 feat: replace icons with brand assets from design-system v0.1.32
All checks were successful
CI / build (push) Successful in 1m29s
CI / docker (push) Successful in 3m22s
- Replace favicon SVG with official camel-logo.svg from design-system
- Add PNG favicons (32px, 192px) with proper link tags in index.html
- Replace sidebar logo with 48px brand icon (cameleer-logo-48.png)
- Replace sign-in page logo with 48px brand icon
- Permit favicon PNGs in SecurityConfig

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:09:13 +02:00
hsiegeln
f81cd740b7 fix: security hardening — remove dead routes, add JWT audience validation
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 2m49s
- Remove broken observe/dashboard Traefik routes (server accessed via /server only)
- Remove unused acme volume
- Add JWT audience claim validation (https://api.cameleer.local) in SecurityConfig
- Secure bootstrap output file with chmod 600
- Add dev-only comments on TLS_SKIP_VERIFY and credential logging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:15:03 +02:00
hsiegeln
9013740b83 fix: mount custom sign-in UI over Logto experience dist
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 33s
CUSTOM_UI_PATH is a Logto Cloud feature, not available in OSS.
The correct approach for self-hosted Logto is to volume-mount
over /etc/logto/packages/experience/dist/.

- Use init container (sign-in-ui) to copy dist to shared volume
  as root (fixes permission denied with cameleer user)
- Logto mounts signinui volume at experience/dist path
- Logto depends on sign-in-ui init container completion
- Remove saas-entrypoint.sh approach (no longer needed)
- Revert Dockerfile entrypoint to direct java -jar
- Permit /favicon.svg in SecurityConfig for sign-in page logo

Tested: full OIDC flow works end-to-end via Playwright.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:24:33 +02:00
hsiegeln
51cdca95c4 feat: server role mapping, Logto admin access, sign-in branding
Some checks failed
CI / build (push) Successful in 38s
CI / docker (push) Has been cancelled
- Add server:admin/operator/viewer scopes to bootstrap and org roles
- Grant SaaS admin Logto console access via admin:admin role
- Configure sign-in experience with Cameleer branding (colors + logos)
- Add rolesClaim and audience to server OIDC config
- Add server scopes to PublicConfigController for token inclusion
- Permit logo SVGs in SecurityConfig (fix 401 on /platform/logo.svg)
- Add cameleer3 logo SVGs (light + dark) to ui/public/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:45:19 +02:00
hsiegeln
4997f7a6a9 feat: move SaaS app to /platform base path, Logto becomes catch-all
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 41s
Eliminates all Logto path enumeration in Traefik. Routing is now:
- /platform/* → cameleer-saas (SPA + API)
- /server/* → server-ui
- /* (catch-all) → Logto (sign-in, OIDC, assets, everything)

Spring context-path handles backend prefix transparently. No changes
needed in controllers, SecurityConfig, or interceptors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:06:41 +02:00
hsiegeln
bc384a6d2d fix: permit /_app/** static assets in SecurityConfig
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 31s
SPA assets moved from /assets/ to /_app/ for single-domain routing,
but SecurityConfig still permitted the old path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:40:41 +02:00
hsiegeln
9b77f810c1 fix: use correct health endpoint and HTTP method for server integration
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 31s
ConnectivityHealthCheck: /actuator/health → /api/v1/health (actuator
now requires auth on cameleer3-server after OIDC was added).

Bootstrap: POST → PUT for /api/v1/admin/oidc (server expects PUT,
POST returned 405 causing OIDC config to silently fail).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:59:24 +02:00
hsiegeln
1ef8c9dceb refactor: merge tenant isolation into single HandlerInterceptor
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 37s
Replace TenantResolutionFilter + TenantOwnershipValidator (15 manual
calls across 5 controllers) with a single TenantIsolationInterceptor
that uses Spring HandlerMapping path variables for fail-closed tenant
isolation. New endpoints with {tenantId}, {environmentId}, or {appId}
path variables are automatically isolated without manual code.

Simplify OrgResolver from dual-token fetch to single token — Logto
merges all scopes into either token type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:48:04 +02:00
hsiegeln
051f7fdae9 feat: auth hardening — scope enforcement, tenant isolation, and docs
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 39s
Add @PreAuthorize annotations to all API controllers (14 endpoints
across 6 controllers) enforcing OAuth2 scopes: apps:manage, apps:deploy,
billing:manage, observe:read, platform:admin.

Enforce tenant isolation: TenantResolutionFilter now rejects cross-tenant
access on /api/tenants/{id}/* paths. New TenantOwnershipValidator checks
environment/app ownership for paths without tenantId. Platform admins
bypass both layers.

Fix frontend: OrgResolver split into two useEffect hooks so scopes
refresh on org switch. Scopes now served from /api/config (single source
of truth). Bootstrap cleaned — standalone org permissions removed.

Update docs/architecture.md, docs/user-manual.md, and CLAUDE.md to
reflect all auth hardening changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:32:53 +02:00
hsiegeln
298f6e3e71 feat: scope-based authorization — read standard scope claim, remove custom roles extraction
Some checks failed
CI / build (push) Failing after 18s
CI / docker (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:04:16 +02:00
hsiegeln
cfa989bd5e fix: allow JwtDecoder bean override in test context
- Add @Primary + @ConditionalOnMissingBean so TestSecurityConfig.jwtDecoder()
  wins over SecurityConfig.jwtDecoder() without needing a real OIDC endpoint
- Add spring.main.allow-bean-definition-overriding=true and
  cameleer.clickhouse.enabled=false to src/test/resources/application-test.yml
  so Testcontainers @ServiceConnection can supply the datasource
- Disable ClickHouse in test profile (src/main/resources/application-test.yml)
  so the explicit ClickHouseConfig DataSource bean is not created, allowing
  @ServiceConnection to wire the Testcontainers Postgres datasource
- Fix TenantControllerTest and LicenseControllerTest to explicitly grant
  ROLE_platform-admin authority via .authorities() on the test JWT, since
  spring-security-test does not run the custom JwtAuthenticationConverter
- Fix EnvironmentService.createDefaultForTenant() to use an internal
  bootstrap path that skips license enforcement (chicken-and-egg: no license
  exists at tenant creation time yet)
- Remove now-unnecessary license stub from EnvironmentServiceTest

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:06:31 +02:00
hsiegeln
5326102443 feat: remove bootstrap_token from EnvironmentEntity — API keys managed separately
Remove bootstrapToken field/getter/setter from EnvironmentEntity and drop
the RuntimeConfig dependency from EnvironmentService. DeploymentService and
AgentStatusService now use a TODO-api-key placeholder until the ApiKeyService
wiring is complete. All test references to setBootstrapToken removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:42:47 +02:00
hsiegeln
5f43394b00 refactor: remove getUserRoles from LogtoManagementClient — roles come from JWT 2026-04-05 12:40:58 +02:00
hsiegeln
bd2a6a601b test: update TestSecurityConfig with org and role claims for Logto tokens 2026-04-05 12:40:49 +02:00
hsiegeln
4b5a1cf2a2 feat: add API key entity, repository, and service with SHA-256 hashing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:39:50 +02:00
hsiegeln
b8b0c686e8 feat: replace manual Logto role check with @PreAuthorize in TenantController
Remove LogtoManagementClient dependency from TenantController; gate
listAll and create with @PreAuthorize("hasRole('platform-admin')"),
relying on the JWT roles claim already mapped by JwtAuthenticationConverter.
Update TenantControllerTest to supply the platform-admin role via jwt()
on all POST requests that expect 201/409.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:39:40 +02:00
hsiegeln
d4408634a6 feat: rewrite MeController — read from JWT claims, Management API only for cold start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:38:39 +02:00
hsiegeln
48a5035a2c fix: remove Ed25519 license signing — replace with UUID token placeholder
Drop JwtConfig dependency from LicenseService; generate license tokens as
random UUIDs instead. Add findByToken to LicenseRepository and update
verifyLicenseToken to do a DB lookup. Update LicenseServiceTest to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:37:32 +02:00
hsiegeln
396c00749e feat: rewrite SecurityConfig — single filter chain, Logto OAuth2 Resource Server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:35:45 +02:00
hsiegeln
f89be09e04 chore: greenfield migrations — remove user/role tables, add api_keys, drop bootstrap_token
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:33:52 +02:00
hsiegeln
3929bbb95e chore: delete dead auth code — users/roles/JWTs/ForwardAuth live in Logto now
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:32:18 +02:00
hsiegeln
51c73d64a4 fix: read M2M credentials from bootstrap JSON when env vars empty
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
The bootstrap dynamically creates the M2M app and writes credentials
to the JSON file. LogtoConfig now falls back to the bootstrap file
when LOGTO_M2M_CLIENT_ID/SECRET env vars are not set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:23:02 +02:00
hsiegeln
34aadd1e25 fix: accept Logto at+jwt token type in Spring Security
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 30s
Logto issues access tokens with typ "at+jwt" (RFC 9068) but Spring
Security's default NimbusJwtDecoder only allows "JWT". Custom decoder
accepts any type. Also removed hard 401 redirect from API client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:17:25 +02:00
hsiegeln
00ee8876c1 fix: move DB seeding from bootstrap script to Java ApplicationRunner
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 33s
SonarQube Analysis / sonarqube (push) Successful in 1m21s
The bootstrap script runs before cameleer-saas (Flyway), so tenant
tables don't exist yet. Moved DB seeding to BootstrapDataSeeder
ApplicationRunner which runs after Flyway migrations complete.
Reads bootstrap JSON and creates tenant/environment/license if missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 02:55:43 +02:00
hsiegeln
827e388349 feat: bootstrap 2 users, tenant, org-scoped tokens, platform admin UI
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 39s
Bootstrap script now creates:
- SaaS Owner (admin/admin) with platform-admin role
- Tenant Admin (camel/camel) in Example Tenant org
- Traditional Web App for cameleer3-server OIDC
- DB records: tenant, default environment, license
- Configures cameleer3-server OIDC via its admin API
All credentials configurable via env vars.

Backend:
- Fix LogtoManagementClient resource URL (https://default.logto.app/api)
- Add getUserRoles/getUserOrganizations to LogtoManagementClient
- Add GET /api/me endpoint (user info, platform admin status, tenants)
- Add GET /api/tenants list-all for platform admins
- Remove insecure X-header forwarding from Traefik

Frontend:
- Org-scoped tokens: getAccessToken(resource, orgId) for tenant context
- OrgResolver component populates org store from /api/me
- useOrganization Zustand store (currentOrgId + currentTenantId)
- Platform admin sidebar section + AdminTenantsPage
- View Dashboard link points to cameleer3-server on port 8081

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 02:50:51 +02:00
hsiegeln
84667170f1 fix: register API resource in Logto for JWT access tokens
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 39s
Logto returns opaque access tokens when no resource is specified.
Added API resource creation to bootstrap, included resource indicator
in /api/config, and SPA now passes resource parameter in auth request.
Also fixed issuer-uri to match Logto's public endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:01:32 +02:00