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>
291 lines
8.7 KiB
Markdown
291 lines
8.7 KiB
Markdown
# 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=<strong-password>
|
|
CAMELEER_AUTH_TOKEN=<random-string-for-agent-bootstrap>
|
|
|
|
# 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=<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):
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
TENANT_ID="<uuid-from-above>"
|
|
|
|
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="<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"
|
|
```
|
|
|
|
## 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`
|