Files
cameleer-saas/HOWTO.md
hsiegeln 4c8c8efbe5
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
feat: add SPA controller, Traefik route, CI frontend build, and HOWTO update
- 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

12 KiB

Cameleer SaaS -- How to Install, Start & Bootstrap

Quick Start (Development)

# 1. Clone
git clone https://gitea.siegeln.net/cameleer/cameleer-saas.git
cd cameleer-saas

# 2. Create environment file
cp .env.example .env

# 3. Generate Ed25519 key pair
mkdir -p keys
ssh-keygen -t ed25519 -f keys/ed25519 -N ""
mv keys/ed25519 keys/ed25519.key

# 4. Start the stack
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# 5. Wait for services to be ready (~30s)
docker compose logs -f cameleer-saas --since 10s
# Look for: "Started CameleerSaasApplication"

# 6. Verify
curl http://localhost:8080/actuator/health
# {"status":"UP"}

Prerequisites

  • Docker Desktop (Windows/Mac) or Docker Engine 24+ (Linux)
  • Git
  • curl or any HTTP client (for testing)

Architecture

The platform runs as a Docker Compose stack with 6 services:

Service Image Port Purpose
traefik traefik:v3 80, 443 Reverse proxy, TLS, routing
postgres postgres:16-alpine 5432* Platform database + Logto database
logto ghcr.io/logto-io/logto 3001*, 3002* Identity provider (OIDC)
cameleer-saas cameleer-saas:latest 8080* SaaS API server
cameleer3-server cameleer3-server:latest 8081 Observability backend
clickhouse clickhouse-server:latest 8123* Trace/metrics/log storage

*Ports exposed to host only with docker-compose.dev.yml overlay.

Installation

1. Environment Configuration

cp .env.example .env

Edit .env and set at minimum:

# Change in production
POSTGRES_PASSWORD=<strong-password>
CAMELEER_AUTH_TOKEN=<random-string-for-agent-bootstrap>
CAMELEER_TENANT_SLUG=<your-tenant-slug>   # e.g., "acme" — tags all observability data

# Logto M2M credentials (get from Logto admin console after first boot)
LOGTO_M2M_CLIENT_ID=
LOGTO_M2M_CLIENT_SECRET=

2. Ed25519 Keys

The platform uses Ed25519 keys for license signing and machine token verification.

mkdir -p keys
ssh-keygen -t ed25519 -f keys/ed25519 -N ""
mv keys/ed25519 keys/ed25519.key

This creates keys/ed25519.key (private) and keys/ed25519.pub (public). The keys directory is mounted read-only into the cameleer-saas container.

If no key files are configured, the platform generates ephemeral keys on startup (suitable for development only -- keys change on every restart).

3. Start the Stack

Development (ports exposed for direct access):

docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Production (traffic routed through Traefik only):

docker compose up -d

4. Verify Services

# Health check
curl http://localhost:8080/actuator/health

# Check all containers are running
docker compose ps

Bootstrapping

First-Time Logto Setup

On first boot, Logto seeds its database automatically. Access the admin console to configure it:

  1. Open http://localhost:3002 (Logto admin console)
  2. Complete the initial setup wizard
  3. Create a Machine-to-Machine application:
    • Go to Applications > Create Application > Machine-to-Machine
    • Note the App ID and App Secret
    • Assign the Logto Management API resource with all scopes
  4. Update .env:
    LOGTO_M2M_CLIENT_ID=<app-id>
    LOGTO_M2M_CLIENT_SECRET=<app-secret>
    
  5. Restart cameleer-saas: docker compose restart cameleer-saas

Create Your First Tenant

With a Logto user token (obtained via OIDC login flow):

TOKEN="<your-logto-jwt>"

# Create tenant
curl -X POST http://localhost:8080/api/tenants \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Company", "slug": "my-company", "tier": "MID"}'

# A "default" environment is auto-created with the tenant

Generate a License

TENANT_ID="<uuid-from-above>"

curl -X POST "http://localhost:8080/api/tenants/$TENANT_ID/license" \
  -H "Authorization: Bearer $TOKEN"

Deploy a Camel Application

# List environments
curl "http://localhost:8080/api/tenants/$TENANT_ID/environments" \
  -H "Authorization: Bearer $TOKEN"

ENV_ID="<default-environment-uuid>"

# Upload JAR and create app
curl -X POST "http://localhost:8080/api/environments/$ENV_ID/apps" \
  -H "Authorization: Bearer $TOKEN" \
  -F 'metadata={"slug":"order-service","displayName":"Order Service"};type=application/json' \
  -F "file=@/path/to/your-camel-app.jar"

APP_ID="<app-uuid-from-response>"

# Deploy (async -- returns 202 with deployment ID)
curl -X POST "http://localhost:8080/api/apps/$APP_ID/deploy" \
  -H "Authorization: Bearer $TOKEN"

DEPLOYMENT_ID="<deployment-uuid>"

# Poll deployment status
curl "http://localhost:8080/api/apps/$APP_ID/deployments/$DEPLOYMENT_ID" \
  -H "Authorization: Bearer $TOKEN"
# Status transitions: BUILDING -> STARTING -> RUNNING (or FAILED)

# View container logs
curl "http://localhost:8080/api/apps/$APP_ID/logs?limit=50" \
  -H "Authorization: Bearer $TOKEN"

# Stop the app
curl -X POST "http://localhost:8080/api/apps/$APP_ID/stop" \
  -H "Authorization: Bearer $TOKEN"

Enable Inbound HTTP Routing

If your Camel app exposes a REST endpoint, you can make it reachable from outside the stack:

# Set the port your app listens on (e.g., 8080 for Spring Boot)
curl -X PATCH "http://localhost:8080/api/environments/$ENV_ID/apps/$APP_ID/routing" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"exposedPort": 8080}'

Your app is now reachable at http://{app-slug}.{env-slug}.{tenant-slug}.{domain} (e.g., http://order-service.default.my-company.localhost). Traefik routes traffic automatically.

To disable routing, set exposedPort to null.

View the Observability Dashboard

The cameleer3-server React SPA dashboard is available at:

http://localhost/dashboard

This shows execution traces, route topology graphs, metrics, and logs for all deployed apps. Authentication is required (Logto OIDC token via forward-auth).

Check Agent & Observability Status

# Is the agent registered with cameleer3-server?
curl "http://localhost:8080/api/apps/$APP_ID/agent-status" \
  -H "Authorization: Bearer $TOKEN"
# Returns: registered, state (ACTIVE/STALE/DEAD/UNKNOWN), routeIds

# Is the app producing observability data?
curl "http://localhost:8080/api/apps/$APP_ID/observability-status" \
  -H "Authorization: Bearer $TOKEN"
# Returns: hasTraces, lastTraceAt, traceCount24h

API Reference

Tenants

Method Path Description
POST /api/tenants Create tenant
GET /api/tenants/{id} Get tenant
GET /api/tenants/by-slug/{slug} Get tenant by slug

Licensing

Method Path Description
POST /api/tenants/{tid}/license Generate license
GET /api/tenants/{tid}/license Get active license

Environments

Method Path Description
POST /api/tenants/{tid}/environments Create environment
GET /api/tenants/{tid}/environments List environments
GET /api/tenants/{tid}/environments/{eid} Get environment
PATCH /api/tenants/{tid}/environments/{eid} Rename environment
DELETE /api/tenants/{tid}/environments/{eid} Delete environment

Apps

Method Path Description
POST /api/environments/{eid}/apps Create app + upload JAR
GET /api/environments/{eid}/apps List apps
GET /api/environments/{eid}/apps/{aid} Get app
PUT /api/environments/{eid}/apps/{aid}/jar Re-upload JAR
PATCH /api/environments/{eid}/apps/{aid}/routing Set/clear exposed port
DELETE /api/environments/{eid}/apps/{aid} Delete app

Deployments

Method Path Description
POST /api/apps/{aid}/deploy Deploy app (async, 202)
GET /api/apps/{aid}/deployments Deployment history
GET /api/apps/{aid}/deployments/{did} Get deployment status
POST /api/apps/{aid}/stop Stop current deployment
POST /api/apps/{aid}/restart Restart app

Logs

Method Path Description
GET /api/apps/{aid}/logs Query container logs

Query params: since, until (ISO timestamps), limit (default 500), stream (stdout/stderr/both)

Observability

Method Path Description
GET /api/apps/{aid}/agent-status Agent registration status
GET /api/apps/{aid}/observability-status Trace/metrics data health

Dashboard

Path Description
/dashboard cameleer3-server observability dashboard (forward-auth protected)

Health

Method Path Description
GET /actuator/health Health check (public)
GET /api/health/secured Authenticated health check

Tier Limits

Tier Environments Apps Retention Features
LOW 1 3 7 days Topology
MID 2 10 30 days + Lineage, Correlation
HIGH Unlimited 50 90 days + Debugger, Replay
BUSINESS Unlimited Unlimited 365 days All features

Frontend Development

The SaaS management UI is a React SPA in the ui/ directory.

Setup

cd ui
npm install

Dev Server

cd ui
npm run dev

The Vite dev server starts on http://localhost:5173 and proxies /api to http://localhost:8080 (the Spring Boot backend). Run the backend in another terminal with mvn spring-boot:run or via Docker Compose.

Environment Variables

Variable Purpose Default
VITE_LOGTO_ENDPOINT Logto OIDC endpoint http://localhost:3001
VITE_LOGTO_CLIENT_ID Logto application client ID (empty)

Create a ui/.env.local file for local overrides:

VITE_LOGTO_ENDPOINT=http://localhost:3001
VITE_LOGTO_CLIENT_ID=your-client-id

Production Build

cd ui
npm run build

Output goes to src/main/resources/static/ (configured in vite.config.ts). The subsequent mvn package bundles the SPA into the JAR. In Docker builds, the Dockerfile handles this automatically via a multi-stage build.

SPA Routing

Spring Boot serves index.html for all non-API routes via SpaController.java. React Router handles client-side routing. The SPA lives at /, while the observability dashboard (cameleer3-server) is at /dashboard.

Development

Running Tests

# Unit tests only (no Docker required)
mvn test -B -Dsurefire.excludes="**/*ControllerTest.java,**/AuditRepositoryTest.java,**/CameleerSaasApplicationTest.java"

# Integration tests (requires Docker Desktop)
mvn test -B -Dtest="EnvironmentControllerTest,AppControllerTest,DeploymentControllerTest"

# All tests
mvn verify -B

Building Locally

# Build JAR
mvn clean package -DskipTests -B

# Build Docker image
docker build -t cameleer-saas:local .

# Use local image
VERSION=local docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Troubleshooting

Logto fails to start: Check that PostgreSQL is healthy first. Logto needs the logto database created by docker/init-databases.sh. Run docker compose logs logto for details.

cameleer-saas won't start: Check docker compose logs cameleer-saas. Common issues:

  • PostgreSQL not ready (wait for healthcheck)
  • Flyway migration conflict (check for manual schema changes)

Ephemeral key warnings: No Ed25519 key files configured -- generating ephemeral keys (dev mode) is normal in development. For production, generate keys as described above.

Container deployment fails: Check that Docker socket is mounted (/var/run/docker.sock) and the cameleer-runtime-base image is available. Pull it with: docker pull gitea.siegeln.net/cameleer/cameleer-runtime-base:latest