From b78dfa9a7ba2579341ba4a2bf03605c924832460 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:31:56 +0200 Subject: [PATCH] docs: add HOWTO.md with install, start, and bootstrap instructions 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) --- HOWTO.md | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 HOWTO.md diff --git a/HOWTO.md b/HOWTO.md new file mode 100644 index 0000000..8bf7a80 --- /dev/null +++ b/HOWTO.md @@ -0,0 +1,290 @@ +# Cameleer SaaS -- How to Install, Start & Bootstrap + +## Quick Start (Development) + +```bash +# 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 + +```bash +cp .env.example .env +``` + +Edit `.env` and set at minimum: + +```bash +# Change in production +POSTGRES_PASSWORD= +CAMELEER_AUTH_TOKEN= + +# 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. + +```bash +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): +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d +``` + +**Production** (traffic routed through Traefik only): +```bash +docker compose up -d +``` + +### 4. Verify Services + +```bash +# 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= + LOGTO_M2M_CLIENT_SECRET= + ``` +5. Restart cameleer-saas: `docker compose restart cameleer-saas` + +### Create Your First Tenant + +With a Logto user token (obtained via OIDC login flow): + +```bash +TOKEN="" + +# 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 + +```bash +TENANT_ID="" + +curl -X POST "http://localhost:8080/api/tenants/$TENANT_ID/license" \ + -H "Authorization: Bearer $TOKEN" +``` + +### Deploy a Camel Application + +```bash +# List environments +curl "http://localhost:8080/api/tenants/$TENANT_ID/environments" \ + -H "Authorization: Bearer $TOKEN" + +ENV_ID="" + +# 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="" + +# Deploy (async -- returns 202 with deployment ID) +curl -X POST "http://localhost:8080/api/apps/$APP_ID/deploy" \ + -H "Authorization: Bearer $TOKEN" + +DEPLOYMENT_ID="" + +# 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" +``` + +## 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 | +| 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) + +### 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 | + +## Development + +### Running Tests + +```bash +# 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 + +```bash +# 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`