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

5.5 KiB

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).

  • 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.