Files
cameleer-saas/CLAUDE.md
hsiegeln b1c2832245
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 11s
docs: update architecture with bootstrap phases, scopes, branding
- CLAUDE.md: add bootstrap phase listing, document 13 scopes (10
  platform + 3 server), server role mapping via scope claim, admin
  console access, sign-in branding
- Mark server-role-mapping and logto-admin-branding specs as implemented

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

92 lines
5.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project
Cameleer SaaS — multi-tenant SaaS platform wrapping the Cameleer observability stack (Java agent + server) for Apache Camel applications. Customers get managed observability for their Camel integrations without running infrastructure.
## Ecosystem
This repo is the SaaS layer on top of two proven components:
- **cameleer3** (sibling repo) — Java agent using ByteBuddy for zero-code instrumentation of Camel apps. Captures route executions, processor traces, payloads, metrics, and route graph topology. Deploys as `-javaagent` JAR.
- **cameleer3-server** (sibling repo) — Spring Boot observability backend. Receives agent data via HTTP, pushes config/commands via SSE. PostgreSQL + OpenSearch storage. React SPA dashboard. JWT auth with Ed25519 config signing.
- **cameleer-website** — Marketing site (Astro 5)
- **design-system** — Shared React component library (`@cameleer/design-system` on Gitea npm registry)
Agent-server protocol is defined in `cameleer3/cameleer3-common/PROTOCOL.md`. The agent and server are mature, proven components — this repo wraps them with multi-tenancy, billing, and self-service onboarding.
## Architecture Context
The existing cameleer3-server already has single-tenant auth (JWT, RBAC, bootstrap tokens, OIDC). The SaaS layer must:
- Add multi-tenancy (tenant isolation of agent data, diagrams, configs)
- Provide self-service signup, billing, and team management
- Generate per-tenant bootstrap tokens for agent registration
- Proxy or federate access to tenant-specific cameleer3-server instances
- Enforce usage quotas and metered billing
### Routing (single-domain, path-based via Traefik)
All services on one hostname. Two env vars control everything: `PUBLIC_HOST` + `PUBLIC_PROTOCOL`.
| Path | Target | Notes |
|------|--------|-------|
| `/platform/*` | cameleer-saas:8080 | SPA + API (`server.servlet.context-path: /platform`) |
| `/server/*` | cameleer3-server-ui:80 | Server dashboard (strip-prefix + `BASE_PATH=/server`) |
| `/` | redirect → `/platform/` | Via `docker/traefik-dynamic.yml` |
| `/*` (catch-all) | logto:3001 (priority=1) | Sign-in, OIDC, interaction, assets |
- SPA assets at `/_app/` (Vite `assetsDir: '_app'`) to avoid conflict with Logto's `/assets/`
- Logto `ENDPOINT` = `${PUBLIC_PROTOCOL}://${PUBLIC_HOST}` (same domain, same origin)
- TLS: self-signed cert init container (`traefik-certs`) for dev, ACME for production
- Root `/``/platform/` redirect via Traefik file provider (`docker/traefik-dynamic.yml`)
### Auth enforcement
- All API endpoints enforce OAuth2 scopes via `@PreAuthorize("hasAuthority('SCOPE_xxx')")` annotations
- Tenant isolation enforced by `TenantIsolationInterceptor` (a single `HandlerInterceptor` on `/api/**` that resolves JWT org_id to TenantContext and validates `{tenantId}`, `{environmentId}`, `{appId}` path variables; fail-closed, platform admins bypass)
- 13 OAuth2 scopes on the Logto API resource (`https://api.cameleer.local`): 10 platform scopes + 3 server scopes (`server:admin`, `server:operator`, `server:viewer`), served to the frontend from `GET /platform/api/config`
- Server scopes map to server RBAC roles via JWT `scope` claim (server reads `rolesClaim: "scope"`)
- Org role `admin` gets `server:admin`, org role `member` gets `server:viewer`
- Custom `JwtDecoder` in `SecurityConfig.java` — ES384 algorithm, `at+jwt` token type, split issuer-uri (string validation) / jwk-set-uri (Docker-internal fetch)
### Server integration (cameleer3-server env vars)
| Env var | Value | Purpose |
|---------|-------|---------|
| `CAMELEER_OIDC_ISSUER_URI` | `${PUBLIC_PROTOCOL}://${PUBLIC_HOST}/oidc` | Token issuer claim validation |
| `CAMELEER_OIDC_JWK_SET_URI` | `http://logto:3001/oidc/jwks` | Docker-internal JWK fetch |
| `CAMELEER_OIDC_TLS_SKIP_VERIFY` | `true` | Skip cert verify for OIDC discovery (dev) |
| `CAMELEER_CORS_ALLOWED_ORIGINS` | `${PUBLIC_PROTOCOL}://${PUBLIC_HOST}` | Allow browser requests through Traefik |
| `BASE_PATH` (server-ui) | `/server` | React Router basename + `<base>` tag |
### Bootstrap (`docker/logto-bootstrap.sh`)
Idempotent script run via `logto-bootstrap` init container. Phases:
1. Wait for Logto + server health
2. Get Management API token (reads `m-default` secret from DB)
3. Create Logto apps (SPA, Traditional with `skipConsent`, M2M with Management API role)
3b. Create API resource scopes (10 platform + 3 server scopes)
4. Create roles (platform-admin, org admin/member with API resource scope assignments)
5. Create users (SaaS admin with platform-admin role + Logto console access, tenant admin)
6. Create organization, add users with org roles
7. Configure cameleer3-server OIDC (`rolesClaim: "scope"`, `audience`, `defaultRoles: ["VIEWER"]`)
8. Configure Logto sign-in branding (Cameleer colors `#C6820E`/`#D4941E`, logo from `/platform/logo.svg`)
9. Cleanup seeded Logto apps
10. Write bootstrap results to `/data/logto-bootstrap.json`
SaaS admin credentials (`SAAS_ADMIN_USER`/`SAAS_ADMIN_PASS`) work for both the SaaS platform and the Logto console (port 3002).
## Related Conventions
- Gitea-hosted: `gitea.siegeln.net/cameleer/`
- CI: `.gitea/workflows/` — Gitea Actions
- K8s target: k3s cluster at 192.168.50.86
- Docker builds: multi-stage, buildx with registry cache, `--provenance=false` for Gitea compatibility
- Design system: import from `@cameleer/design-system` (Gitea npm registry)
## Disabled Skills
- Do NOT use any `gsd:*` skills in this project. This includes all `/gsd:` prefixed commands.