Commit Graph

105 Commits

Author SHA1 Message Date
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
b83cfdcd49 fix: add all design-system providers (GlobalFilter + CommandPalette)
All checks were successful
CI / build (push) Successful in 41s
CI / docker (push) Successful in 38s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:30:18 +02:00
hsiegeln
a7dd026225 fix: add GlobalFilterProvider required by design-system DataTable
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 41s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:23:36 +02:00
hsiegeln
0843a33383 refactor: replace hand-rolled OIDC with @logto/react SDK
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 48s
The hand-rolled OIDC flow (manual PKCE, token exchange, URL
construction) was fragile and accumulated multiple bugs. Replaced
with the official @logto/react SDK which handles PKCE, token
exchange, storage, and refresh automatically.

- Add @logto/react SDK dependency
- Add LogtoProvider with runtime config in main.tsx
- Add TokenSync component bridging SDK tokens to API client
- Add useAuth hook replacing Zustand auth store
- Simplify LoginPage to signIn(), CallbackPage to useHandleSignInCallback()
- Delete pkce.ts and auth-store.ts (replaced by SDK)
- Fix react-router-dom → react-router imports in page files
- All 17 React Query hooks unchanged (token provider pattern)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:17:47 +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
hsiegeln
6764f981d2 fix: add PKCE support for Logto auth and fix Traefik routing
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 39s
Logto requires PKCE (Proof Key for Code Exchange) for SPA auth.
Added code_challenge/code_verifier to login and callback flow.

Also fixed Traefik router-service linking — when a container defines
multiple routers, each needs an explicit service binding or Traefik
v3 refuses to auto-link them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:48:21 +02:00
hsiegeln
537c2bbaf2 fix: use LOGTO_PUBLIC_ENDPOINT for Logto ENDPOINT config
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 6s
Logto's ENDPOINT must be the browser-accessible URL (not Docker
internal). When .env sets LOGTO_ENDPOINT=http://logto:3001, it was
overriding the default and causing Logto to redirect browsers to
an unreachable hostname.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:44:24 +02:00
hsiegeln
beb3442c07 fix: return browser-accessible Logto URL from /api/config
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
Separate LOGTO_PUBLIC_ENDPOINT (browser-facing, defaults to
http://localhost:3001) from LOGTO_ENDPOINT (Docker-internal).
Also fix bootstrap M2M verification by using correct Host header
for default tenant token endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:33:43 +02:00
hsiegeln
a20d36df38 fix: bootstrap script use curl with Host header for Logto tenant routing
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 6s
Logto routes requests by Host header to determine tenant. Inside Docker,
requests to logto:3001/3002 need Host: localhost:3001/3002 to match the
configured ENDPOINT/ADMIN_ENDPOINT.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:28:23 +02:00
hsiegeln
021b056bce feat: zero-config first-run experience with Logto bootstrap
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 37s
- logto-bootstrap.sh: API-driven init script that creates SPA app,
  M2M app, and default user (camel/camel) via Logto Management API.
  Reads m-default secret from DB, then removes seeded apps with
  known secrets (security hardening). Idempotent.
- PublicConfigController: /api/config public endpoint serves Logto
  client ID from bootstrap output file (runtime, not build-time)
- Frontend: LoginPage + CallbackPage fetch config from /api/config
  instead of import.meta.env (fixes Vite build-time baking issue)
- Docker Compose: logto-bootstrap init service with health-gated
  dependency chain, shared volume for bootstrap config
- SecurityConfig: permit /api/config without auth

Flow: docker compose up → bootstrap creates apps/user → SPA fetches
config → login page shows → sign in with Logto → camel/camel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:22:22 +02:00
hsiegeln
cda7dfbaa7 fix: permit SPA routes and static assets in Spring Security
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 32s
The SPA (index.html, /login, /callback, /assets/*) must be accessible
without authentication. API routes remain protected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:49:43 +02:00
hsiegeln
ad6805e447 fix: use standard dist/ output for Vite, copy to static/ explicitly
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 37s
The relative outDir '../src/main/resources/static' resolved
unpredictably in Docker. Use standard 'dist/' output, then:
- Dockerfile: COPY --from=frontend /ui/dist/ to static/
- CI: cp -r dist/ to src/main/resources/static/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:44:50 +02:00
hsiegeln
e5e14fbe32 fix: add CAMELEER_JWT_SECRET for cameleer3-server
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 7s
The server needs this to derive its Ed25519 signing key. Without it,
startup fails with 'Empty key'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:42:37 +02:00
hsiegeln
e10f80c298 fix: allow ClickHouse connections from Docker network
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 6s
The default ClickHouse image restricts the 'default' user to localhost
only. Override with clickhouse-users.xml to allow connections from any
IP (needed for inter-container communication on the Docker network).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:41:14 +02:00
hsiegeln
16acd145a3 fix: pg_isready healthcheck must specify database name
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 5s
Without -d, pg_isready connects to database matching the username
('cameleer'), which doesn't exist. Specify $POSTGRES_DB explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:38:02 +02:00
hsiegeln
d0fd2c49be fix: Docker Compose database initialization
Some checks failed
CI / build (push) Successful in 38s
CI / docker (push) Has been cancelled
- init-databases.sh: create cameleer3 DB for cameleer3-server, connect
  to $POSTGRES_DB explicitly (avoids 'database cameleer does not exist')
- clickhouse-init.sql: auto-create cameleer database on first start
- docker-compose.yml: fix cameleer3-server datasource to cameleer3 DB,
  add ClickHouse init script volume mount, pass credentials

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:37:19 +02:00
hsiegeln
567d92ca34 fix: let Flyway inherit datasource connection instead of separate URL
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 31s
Explicit spring.flyway.url/user/password used SPRING_DATASOURCE_URL env
var but Flyway resolves its own defaults independently, falling back to
localhost when the env var mapping doesn't match. Removing the explicit
Flyway connection config lets it inherit from the datasource, which is
correctly configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:20:04 +02:00
hsiegeln
fb4e1f57e5 docs: add Phase 9 Frontend React Shell implementation plan
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 5s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:10:25 +02:00
hsiegeln
032db410c7 fix: refactor ClickHouse config to match cameleer3-server pattern
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 32s
- Add ClickHouseProperties with @ConfigurationProperties
- @ConditionalOnProperty to toggle ClickHouse
- @Primary DataSource + JdbcTemplate for PostgreSQL (prevents Spring
  Boot from routing JPA/Flyway to ClickHouse)
- HikariDataSource for ClickHouse with explicit credentials
- Remove separate DataSourceConfig.java (merged into ClickHouseConfig)
- Remove database-platform override (no longer needed with @Primary)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:09:01 +02:00
hsiegeln
be4c882ef8 fix: configure Flyway to use explicit PostgreSQL datasource
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
With two DataSource beans (PostgreSQL + ClickHouse), Flyway was picking
up the ClickHouse DataSource and failing with auth errors. Explicitly
configure Flyway's url/user/password to target PostgreSQL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:58:54 +02:00
hsiegeln
64a5edac78 fix: add explicit datasource defaults to application.yml
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
Without an explicit spring.datasource.url, Spring Boot falls back to
jdbc:postgresql://localhost:5432 when the SPRING_DATASOURCE_URL env var
is missing or not picked up. Default now points to the docker-compose
service name (postgres:5432/cameleer_saas).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:54:18 +02:00
hsiegeln
806895fbd0 fix: separate dev and local profiles for Docker vs bare-metal
All checks were successful
CI / build (push) Successful in 37s
CI / docker (push) Successful in 29s
dev profile: activated inside Docker containers (show-sql only)
local profile: for running Maven outside Docker (localhost overrides)

Usage: mvn spring-boot:run -Dspring-boot.run.profiles=dev,local

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:45:07 +02:00
hsiegeln
c0e189a5c8 fix: add ClickHouse and cameleer3-server localhost overrides to dev profile
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 3m1s
Without these, `mvn spring-boot:run -Dspring-boot.run.profiles=dev` fails
because ClickHouse URL defaults to docker hostname 'clickhouse'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:34:02 +02:00
hsiegeln
aaa4af40c5 fix: use BUILDPLATFORM for native cross-compilation, remove broken cache mounts
Some checks failed
CI / build (push) Successful in 42s
CI / docker (push) Has been cancelled
Build and frontend stages now use --platform=$BUILDPLATFORM so Maven and
Node run natively on the ARM64 CI runner instead of under QEMU emulation.
Only the final JRE runtime stage targets amd64. Removed --mount=type=cache
which doesn't persist across CI runs with buildx --push; the registry layer
cache (--cache-from/--cache-to in CI) handles caching the dependency layer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:31:22 +02:00
hsiegeln
c4a4c9d2fc fix: cross-compile Docker image for amd64 and add npm registry auth
Some checks failed
CI / build (push) Successful in 40s
CI / docker (push) Has been cancelled
- CI docker job: QEMU + buildx + --platform linux/amd64 (runners are arm64)
- Dockerfile: REGISTRY_TOKEN build arg for @cameleer/design-system npm auth
- CI build job: npm auth token for frontend build step
- Registry cache for faster builds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:21:44 +02:00
050ff61e7a Merge pull request 'feat: Phase 9 — Frontend React Shell' (#35) from feat/phase-9-frontend-react-shell into main
All checks were successful
CI / build (push) Successful in 41s
CI / docker (push) Successful in 4s
Reviewed-on: #35
2026-04-04 22:12:53 +02:00
hsiegeln
e325c4d2c0 fix: correct Dockerfile frontend build output path
All checks were successful
CI / build (push) Successful in 1m10s
CI / build (pull_request) Successful in 1m9s
CI / docker (pull_request) Has been skipped
CI / docker (push) Successful in 23s
Vite's outDir is '../src/main/resources/static' (relative to ui/),
which resolves to /src/main/resources/static/ in the Docker build.
The COPY was looking at /ui/dist/ which doesn't exist.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:10:42 +02:00
hsiegeln
4c8c8efbe5 feat: add SPA controller, Traefik route, CI frontend build, and HOWTO update
Some checks failed
CI / build (push) Successful in 49s
CI / docker (push) Failing after 38s
CI / build (pull_request) Successful in 1m2s
CI / docker (pull_request) Has been skipped
- SpaController catch-all forwards non-API routes to index.html
- Traefik SPA route at priority=1 catches all unmatched paths
- CI pipeline builds frontend before Maven
- Dockerfile adds multi-stage frontend build
- HOWTO.md documents frontend development workflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:06:36 +02:00
hsiegeln
f6d3627abc feat: add license page with tier features and limits
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 22:04:55 +02:00
hsiegeln
fe786790e1 feat: add app detail page with deploy, logs, and status
Full AppDetailPage with tabbed layout (Overview / Deployments / Logs),
current deployment status with auto-poll, action bar (deploy/stop/restart/re-upload/delete),
agent status card, routing card with edit modal, deployment history table,
and container log viewer with stream filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 22:03:29 +02:00
hsiegeln
5eac48ad72 feat: add environments list and environment detail pages
Implements EnvironmentsPage with DataTable, create modal, and row navigation,
and EnvironmentDetailPage with app list, inline rename, new app form with JAR
upload, and delete confirmation — all gated by RBAC permissions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 22:00:14 +02:00
hsiegeln
02019e9347 feat: add dashboard page with tenant overview and KPI stats
Replaces placeholder DashboardPage with a full implementation: tenant
name + tier badge, KPI strip (environments, total apps, running, stopped),
environment list with per-env app counts, and a recent deployments
placeholder. Uses EnvApps helper component to fetch per-environment app
data without violating hook rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:57:53 +02:00
hsiegeln
91a4235223 feat: add sidebar layout, environment tree, and router
Wires up AppShell + Sidebar compound component, a per-environment
SidebarTree that lazy-fetches apps, React Router nested routes, and
provider-wrapped main.tsx with ThemeProvider/ToastProvider/BreadcrumbProvider.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:55:21 +02:00
hsiegeln
e725669aef feat: add RBAC hooks and permission-gated components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:51:38 +02:00
hsiegeln
d572926010 feat: add API client with auth middleware and React Query hooks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:50:19 +02:00
hsiegeln
e33818cc74 feat: add auth store, login, callback, and protected route
Adds Zustand auth store with JWT parsing (sub, roles, organization_id),
Logto OIDC login page, authorization code callback handler, and
ProtectedRoute guard. Also adds vite-env.d.ts for import.meta.env types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:48:56 +02:00
hsiegeln
146dbccc6e feat: scaffold React SPA with Vite, design system, and TypeScript types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:47:01 +02:00
hsiegeln
600985c913 docs: add Phase 9 Frontend React Shell spec
All checks were successful
CI / build (push) Successful in 28s
CI / docker (push) Successful in 4s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:36:45 +02:00
7aa331d73c Merge pull request 'feat: Phase 4 — Observability Pipeline + Inbound Routing' (#34) from feat/phase-4-observability-pipeline into main
All checks were successful
CI / build (push) Successful in 28s
CI / docker (push) Successful in 3s
Reviewed-on: #34
2026-04-04 21:20:46 +02:00
hsiegeln
9b1643c1ee docs: update HOWTO with observability dashboard, routing, and agent status
All checks were successful
CI / build (push) Successful in 29s
CI / build (pull_request) Successful in 48s
CI / docker (push) Successful in 47s
CI / docker (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:06:05 +02:00
hsiegeln
9f8d0f43ab feat: add dashboard Traefik route and CAMELEER_TENANT_ID config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:04:57 +02:00
hsiegeln
43cd2d012f feat: add cameleer3-server startup connectivity check 2026-04-04 21:03:41 +02:00
hsiegeln
210da55e7a feat: add Traefik routing labels for customer apps with exposed ports
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:03:04 +02:00
hsiegeln
08b87edd6e feat: add agent status and observability status endpoints
Implements AgentStatusService (TDD) that proxies cameleer3-server agent
registry API and queries ClickHouse for trace counts. Gracefully degrades
to UNKNOWN state when server is unreachable or DataSource is absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:01:43 +02:00
hsiegeln
024780c01e feat: add exposed port routing and route URL to app API
Adds domain config to RuntimeConfig/application.yml, expands AppResponse
with exposedPort and computed routeUrl, adds updateRouting to AppService,
and adds PATCH /{appId}/routing endpoint to AppController.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:57:37 +02:00
hsiegeln
d25849d665 feat: add labels support to StartContainerRequest and DockerRuntimeOrchestrator
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:55:16 +02:00
hsiegeln
b0275bcf64 feat: add exposed_port column to apps table 2026-04-04 20:53:56 +02:00
hsiegeln
f8d80eaf79 docs: add Phase 4 Observability Pipeline implementation plan
All checks were successful
CI / build (push) Successful in 28s
CI / docker (push) Successful in 4s
8 tasks: migration, labels support, routing API, agent/observability
status endpoints, Traefik routing labels, connectivity check,
Docker Compose + env, HOWTO update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:52:17 +02:00
hsiegeln
41629f3290 docs: add Phase 4 Observability Pipeline + Inbound Routing spec
All checks were successful
CI / build (push) Successful in 27s
CI / docker (push) Successful in 4s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:47:51 +02:00
hsiegeln
b78dfa9a7b docs: add HOWTO.md with install, start, and bootstrap instructions
All checks were successful
CI / build (push) Successful in 27s
CI / docker (push) Successful in 4s
Quick start, full installation guide, Logto setup, first tenant
creation, app deployment walkthrough, API reference, tier limits,
development commands, and troubleshooting.

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