# Cameleer SaaS User Manual

## 1. Introduction

Cameleer SaaS is a managed observability and runtime platform for Apache Camel applications. It lets you upload your Camel application JARs, deploy them as managed containers with the Cameleer agent automatically injected, and observe their behavior through route topology graphs, execution traces, processor metrics, and container logs -- all without running your own infrastructure.

### Who This Manual Is For

This manual is written for:

- **SaaS customers** who access a hosted Cameleer instance to deploy and monitor their Camel applications.
- **Self-hosted operators** who run the full Cameleer SaaS stack on their own infrastructure using Docker Compose.

Both audiences share the same UI and workflows. The self-hosted setup section at the end covers the additional steps needed to run the platform yourself.

### Two Deployment Modes

| Mode | You manage | We manage |
|------|-----------|-----------|
| **Managed SaaS** | Your Camel JARs | Infrastructure, upgrades, identity, storage |
| **Self-hosted** | Everything (Docker Compose stack) | Nothing -- you own it all |

---

## 2. Getting Started

### Logging In

Cameleer SaaS uses Logto for single sign-on (SSO). To log in:

1. Navigate to the Cameleer SaaS URL in your browser.
2. You will see the login screen with the title "Cameleer SaaS" and a subtitle "Managed Apache Camel Runtime."
3. Click **Sign in with Logto**.
4. Authenticate with your Logto credentials (username/password or any configured social login).
5. After successful authentication, you are redirected back to the dashboard.

![Login page](screenshots/login-page.png)

> **Tip:** If you are already authenticated, navigating to `/login` automatically redirects you to the dashboard.

### First-Time Experience

After your first login, you land on the **Dashboard**. What you see depends on whether your organization has been set up:

- If your account is linked to a tenant (organization), you see the tenant name, tier badge, and any existing environments.
- If your account is not linked to a tenant, you see a message: "No tenant associated. Please contact your administrator."

For self-hosted deployments, the bootstrap process creates a default tenant and organization automatically (see Section 10).

### Understanding the Dashboard

The dashboard provides an at-a-glance overview of your tenant:

- **Tenant header** -- Your organization name and license tier badge (LOW, MID, HIGH, or BUSINESS).
- **KPI strip** -- Four key metrics: total environments, total apps, running deployments, and stopped apps needing attention.
- **Environments list** -- Each environment shows its name, slug, number of apps, running count, and status (ACTIVE or INACTIVE).
- **Recent Deployments** -- A prompt to select an app to view its deployment history.

![Dashboard overview](screenshots/dashboard-overview.png)

### Sidebar Navigation

The sidebar provides access to all major sections:

| Section | Description |
|---------|-------------|
| **Dashboard** | Tenant overview and KPI metrics |
| **Environments** | Expandable tree showing all environments and their apps |
| **License** | License tier, features, limits, and token |
| **Platform** | Platform-wide tenant management (visible only to platform admins) |
| **View Dashboard** | Opens the observability dashboard (cameleer3-server) in a new tab |
| **Account** | Log out of the current session |

The Environments section in the sidebar renders as a collapsible tree: environments at the top level, with their applications nested underneath. Clicking any item navigates directly to its detail page.

---

## 3. Environments

### What Environments Are

An environment is an isolated runtime context within your tenant. Environments let you separate concerns -- for example, you might create `development`, `staging`, and `production` environments. Each environment has its own set of applications and deployments.

Every environment has:

- A **slug** (URL-safe identifier, e.g., `production`) -- immutable after creation.
- A **display name** (human-readable, e.g., "Production") -- can be renamed.
- A **status** -- typically `ACTIVE`.

### Creating an Environment

> **Note:** Creating environments requires the `apps:manage` scope. If you do not see the "Create Environment" button, contact your organization admin.

To create an environment:

1. Navigate to **Environments** from the sidebar or click **Create Environment** on the dashboard.
2. Click **Create Environment** in the top-right corner.
3. In the modal dialog, enter:
   - **Slug** -- A URL-safe identifier (e.g., `staging`). Cannot be changed later.
   - **Display Name** -- A human-readable name (e.g., "Staging").
4. Click **Create**.

![Create environment modal](screenshots/create-environment.png)

### Tier Limits on Environments

Your license tier determines how many environments you can create:

| Tier | Max Environments |
|------|-----------------|
| LOW | 1 |
| MID | 2 |
| HIGH | Unlimited |
| BUSINESS | Unlimited |

If you attempt to create an environment beyond your tier limit, the request will be rejected.

### Managing Environments

From the environment detail page you can:

- **Rename** the environment by clicking its display name (inline edit). Requires the `apps:manage` scope.
- **Delete** the environment using the "Delete Environment" button. An environment can only be deleted after all its apps have been removed. Requires the `apps:manage` scope.

---

## 4. Applications

### What an Application Represents

An application in Cameleer SaaS represents one of your Apache Camel applications. It tracks the uploaded JAR file, deployment state, routing configuration, and observability status. Applications live inside environments.

### Creating an Application

> **Note:** Creating applications requires the `apps:deploy` scope.

To create an application:

1. Navigate to the environment where you want to add the app.
2. Click **New App**.
3. In the modal dialog, fill in:
   - **Slug** -- A URL-safe identifier (e.g., `order-router`). Cannot be changed later.
   - **Display Name** -- A human-readable name (e.g., "Order Router").
   - **JAR File** (optional) -- Select your Camel application JAR. You can also upload or re-upload the JAR later.
4. Click **Create App**.

![New app modal](screenshots/new-app.png)

### Uploading a JAR File

You can upload a JAR at creation time or re-upload it later:

1. Navigate to the app detail page.
2. In the **Actions** card on the Overview tab, click **Re-upload JAR**.
3. Select the new JAR file and click **Upload**.

The platform stores the original filename, file size, and a checksum for each upload.

### Understanding Agent Injection

When you deploy an application, the platform builds a Docker image from your JAR with the Cameleer agent automatically injected as a `-javaagent`. This means:

- You do not need to modify your application code or build process.
- The agent instruments your Camel routes at runtime using bytecode manipulation.
- The agent connects to the observability server and begins reporting route topology, execution traces, and processor metrics.

---

## 5. Deployments

### Deploying an Application

> **Note:** Deploying requires the `apps:deploy` scope.

To deploy an application:

1. Navigate to the app detail page (via the sidebar tree or the environment's app list).
2. On the **Overview** tab, in the **Actions** card, click **Deploy**.
3. The deployment starts asynchronously. The status will transition through the deployment lifecycle.

### Viewing Deployment Status

After triggering a deployment, the **Current Deployment** card on the Overview tab shows:

- **Version** -- An incrementing deployment version number.
- **Status** -- The observed status of the deployment.
- **Image** -- The Docker image reference built for this deployment.
- **Deployed** -- The timestamp when the deployment started.
- **Error** -- If the deployment failed, the error message appears here.

The deployment lifecycle follows these status transitions:

```
BUILDING --> STARTING --> RUNNING
                |
                +--> FAILED
```

- **BUILDING** -- The Docker image is being built with your JAR and the Cameleer agent.
- **STARTING** -- The container has been created and is starting up.
- **RUNNING** -- The container is running and healthy.
- **FAILED** -- The deployment encountered an error (image build failure, container crash, etc.).

### Stopping and Restarting

From the **Actions** card:

- **Stop** -- Stops the running container. A confirmation dialog appears before stopping.
- **Restart** -- Stops and redeploys the application with the same JAR version.

Both actions require the `apps:deploy` scope and are only available when the app has an active deployment.

### Reading Container Logs

To view container logs:

1. Navigate to the app detail page.
2. Click the **Logs** tab.
3. Logs appear in a scrollable viewer with timestamps.
4. Filter by stream using the buttons at the top: **All**, **stdout**, or **stderr**.

![Container logs](screenshots/container-logs.png)

> **Tip:** If no logs appear, the app may not have been deployed yet or the container may have exited immediately.

### Deployment History

To view the full deployment history:

1. Navigate to the app detail page.
2. Click the **Deployments** tab.
3. A table shows all past and current deployments with: version, observed status, desired status, deployed timestamp, stopped timestamp, and any error message.

Failed deployments are highlighted with a red accent for quick identification.

---

## 6. Observability

### Accessing the Observability Dashboard

The observability dashboard is provided by cameleer3-server and opens in a separate browser tab:

1. In the sidebar footer, click **View Dashboard**.
2. The dashboard opens at the cameleer3-server URL.

Alternatively, from any app detail page, the **Agent Status** card includes a "View in Dashboard" link.

### What You Can See

The observability dashboard provides:

- **Route topology** -- Visual graph of your Camel routes showing processors, endpoints, and data flow.
- **Execution traces** -- Individual route execution traces with timing, payload snapshots, and processor-level detail.
- **Processor metrics** -- Throughput, latency, and error rates per processor node.

### Agent Connection Status

The **Agent Status** card on each app detail page shows:

- **Registration state** -- Whether the agent has registered with the observability server.
- **Connection state** -- `CONNECTED` (live, with a pulsing indicator) or `DISCONNECTED`.
- **Last heartbeat** -- Timestamp of the most recent agent heartbeat.
- **Routes** -- List of Camel route IDs discovered by the agent.
- **Observability data** -- Whether traces, metrics, and diagrams are being produced, with a 24-hour trace count.

---

## 7. Licenses

### Understanding Tiers

Cameleer SaaS uses four license tiers that control available features and resource limits:

| Tier | Features | Max Agents | Max Environments | Retention |
|------|----------|-----------|-----------------|-----------|
| **LOW** | Topology | 3 | 1 | 7 days |
| **MID** | Topology, Lineage, Correlation | 10 | 2 | 30 days |
| **HIGH** | All (including Debugger, Replay) | 50 | Unlimited | 90 days |
| **BUSINESS** | All | Unlimited | Unlimited | 365 days |

### Feature Gating

Each feature is either **Enabled** or **Disabled** based on your tier:

| Feature | LOW | MID | HIGH | BUSINESS |
|---------|-----|-----|------|----------|
| Topology | Enabled | Enabled | Enabled | Enabled |
| Lineage | Disabled | Enabled | Enabled | Enabled |
| Correlation | Disabled | Enabled | Enabled | Enabled |
| Debugger | Disabled | Disabled | Enabled | Enabled |
| Replay | Disabled | Disabled | Enabled | Enabled |

### Viewing License Status and Expiry

To view your license:

1. Click **License** in the sidebar.
2. The license page displays:
   - **Tier badge** -- Your current tier.
   - **Validity** -- Issue date, expiration date, and days remaining. The days-remaining badge turns yellow when 30 or fewer days remain and red when expired.
   - **Features** -- Which observability features are enabled or disabled.
   - **Limits** -- Max agents, retention days, and max environments.
   - **License token** -- Click "Show token" to reveal the token used for agent registration.

![License page](screenshots/license-page.png)

> **Warning:** If your license expires, deployed applications continue to run but new deployments and agent registrations may be restricted. Contact your administrator to renew.

---

## 8. Platform Administration

> **Note:** This section applies only to users with the `platform:admin` scope. The Platform section in the sidebar is not visible to regular users.

### Managing Tenants

Platform administrators can view and manage all tenants across the platform:

1. Click **Platform** in the sidebar.
2. The **All Tenants** page displays a table of every tenant with: name, slug, tier, status, and creation date.
3. Click on a tenant row to switch your active context to that tenant's dashboard.

![Admin tenants page](screenshots/admin-tenants.png)

### Creating Tenants

New tenants can be created via the API (the UI currently provides read-only access to the tenant list):

```
POST /api/tenants
Content-Type: application/json

{
  "name": "Acme Corp",
  "slug": "acme-corp",
  "tier": "MID"
}
```

This requires a valid token with the `platform:admin` scope. A default environment is automatically created with each new tenant.

### Creating Organizations in Logto

Each tenant in Cameleer SaaS corresponds to an organization in Logto. When you create a tenant, a corresponding Logto organization should be created and users assigned to it. For self-hosted deployments, the bootstrap script handles this automatically for the initial tenant.

To create additional organizations:

1. Open the Logto admin console.
2. Navigate to **Organizations** and create a new organization.
3. Add users to the organization and assign them the appropriate role (admin or member).
4. Create the corresponding tenant in Cameleer SaaS via the API with a matching slug.

---

## 9. Roles and Permissions

### Organization Roles

Cameleer SaaS uses two organization-level roles managed in Logto:

| Role | Description |
|------|-------------|
| **admin** | Full access to all tenant operations |
| **member** | Can deploy apps and view observability data |

### What Each Role Can Do

| Scope | Admin | Member | Description |
|-------|-------|--------|-------------|
| `tenant:manage` | Yes | No | Manage tenant settings |
| `billing:manage` | Yes | No | Manage billing |
| `team:manage` | Yes | No | Manage team members |
| `apps:manage` | Yes | No | Create/delete apps and environments |
| `apps:deploy` | Yes | Yes | Deploy, stop, and restart apps |
| `secrets:manage` | Yes | No | Manage secrets |
| `observe:read` | Yes | Yes | View observability data |
| `observe:debug` | Yes | Yes | Debug and replay operations |
| `settings:manage` | Yes | No | Manage settings |

In the UI, buttons and actions that require a scope you do not have are automatically hidden. For example, members will not see "Create Environment" or "Delete App" buttons.

### How Permissions Are Managed

All role and permission management happens in Logto, not in the Cameleer SaaS application itself:

- Organization roles and their scopes are configured in Logto during the bootstrap process.
- To change a user's role, update their organization role assignment in the Logto admin console.
- To add a user to a tenant, add them to the corresponding Logto organization and assign a role.

There is also a global `platform:admin` scope (separate from organization roles) that grants access to the Platform section for cross-tenant administration.

The full list of 10 scopes is also available programmatically via the `GET /api/config` endpoint, which the frontend uses to discover available scopes at runtime.

---

## 10. Self-Hosted Setup

### Prerequisites

- **Docker Desktop** (Windows/Mac) or **Docker Engine 24+** (Linux)
- **Docker Compose** v2 (included with Docker Desktop)
- **Git** for cloning the repository
- **curl** or any HTTP client for verification

### Quick Start

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

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

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

# 4. Wait for services (~30-60 seconds for first boot)
docker compose logs -f cameleer-saas --since 10s
# Look for: "Started CameleerSaasApplication"

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

### Environment Variables Reference

Copy `.env.example` to `.env` and configure as needed:

| Variable | Purpose | Default |
|----------|---------|---------|
| `VERSION` | Docker image tag | `latest` |
| `POSTGRES_USER` | PostgreSQL username | `cameleer` |
| `POSTGRES_PASSWORD` | PostgreSQL password | `change_me_in_production` |
| `POSTGRES_DB` | PostgreSQL database name | `cameleer_saas` |
| `LOGTO_ENDPOINT` | Internal Logto URL (container-to-container) | `http://logto:3001` |
| `LOGTO_PUBLIC_ENDPOINT` | Public-facing Logto URL | `http://localhost:3001` |
| `LOGTO_ISSUER_URI` | OIDC issuer URI | `http://localhost:3001/oidc` |
| `LOGTO_JWK_SET_URI` | OIDC JWK set URI | `http://logto:3001/oidc/jwks` |
| `LOGTO_M2M_CLIENT_ID` | Machine-to-machine client ID (auto-set by bootstrap) | _(empty)_ |
| `LOGTO_M2M_CLIENT_SECRET` | Machine-to-machine client secret (auto-set by bootstrap) | _(empty)_ |
| `LOGTO_SPA_CLIENT_ID` | SPA client ID for the frontend | _(empty)_ |
| `CAMELEER_AUTH_TOKEN` | Bootstrap token for agent registration | `change_me_bootstrap_token` |
| `CAMELEER_CONTAINER_MEMORY_LIMIT` | Memory limit for deployed containers | `512m` |
| `CAMELEER_CONTAINER_CPU_SHARES` | CPU shares for deployed containers | `512` |
| `CAMELEER_TENANT_SLUG` | Default tenant slug | `default` |
| `DOMAIN` | Domain for Traefik TLS and route URLs | `localhost` |
| `SAAS_ADMIN_USER` | Platform admin username | `admin` |
| `SAAS_ADMIN_PASS` | Platform admin password | `admin` |
| `TENANT_ADMIN_USER` | Tenant admin username | `camel` |
| `TENANT_ADMIN_PASS` | Tenant admin password | `camel` |

> **Warning:** Change all default passwords before running in production. The defaults (`admin`/`admin`, `camel`/`camel`) are for development only.

### The Services

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

| Service | Purpose | Dev Port |
|---------|---------|----------|
| **traefik** | Reverse proxy and TLS termination | 80, 443 |
| **postgres** | Database for platform data, Logto, and cameleer3-server | 5432 |
| **logto** | Identity provider (OIDC/SSO) | 3001, 3002 |
| **logto-bootstrap** | One-time setup (runs and exits) | -- |
| **cameleer-saas** | SaaS API server and frontend | 8080 |
| **cameleer3-server** | Observability backend | 8081 |
| **clickhouse** | Trace, metrics, and log storage | 8123 |

In production mode (`docker compose up`), only ports 80 and 443 are exposed via Traefik. In development mode (`docker compose -f docker-compose.yml -f docker-compose.dev.yml up`), individual service ports are exposed directly for debugging.

### The Bootstrap Process

On first boot, the `logto-bootstrap` container automatically:

1. Waits for Logto and cameleer3-server to be healthy.
2. Creates three Logto applications:
   - **Cameleer SaaS** (SPA) -- for the management UI frontend.
   - **Cameleer SaaS Backend** (Machine-to-Machine) -- for server-to-Logto API calls.
   - **Cameleer Dashboard** (Traditional Web App) -- for cameleer3-server OIDC login.
3. Creates an API resource (`https://api.cameleer.local`) with 10 OAuth2 scopes (see Section 9).
4. Creates organization roles with **API resource scopes** (not standalone org permissions):
   - `admin` -- 9 tenant scopes (all except `platform:admin`).
   - `member` -- 3 scopes: `apps:deploy`, `observe:read`, `observe:debug`.
5. Creates two users:
   - Platform admin (default: `admin` / `admin`) -- has the `admin` org role plus the global `platform-admin` role (which grants `platform:admin` scope).
   - Demo user (default: `camel` / `camel`) -- added to the default organization with the `member` role.
6. Creates a Logto organization ("Example Tenant") and assigns both users.
7. Configures cameleer3-server with Logto OIDC settings for dashboard authentication.
8. Writes all generated IDs and secrets to `/data/logto-bootstrap.json` for the SaaS backend to consume.

The bootstrap is idempotent -- re-running it will skip resources that already exist.

### Logto Admin Console Access

For self-hosted deployments, the Logto admin console is available at:

- **Development:** `http://localhost:3002`
- **Production:** Accessible only if you configure a Traefik route for port 3002.

Use the admin console to:

- Manage users and their roles.
- Configure social login connectors (Google, GitHub, etc.).
- View and manage applications and API resources.
- Create additional organizations for new tenants.

### Connecting to an External OIDC Provider

To use an external identity provider instead of Logto's built-in username/password:

1. Open the Logto admin console.
2. Navigate to **Connectors** > **Social** or **Enterprise SSO**.
3. Configure your provider (e.g., Google, Azure AD, Okta).
4. Users can then sign in through the configured provider on the Logto login page.

The Cameleer SaaS application itself does not need any changes -- all identity configuration is handled in Logto.

---

## 11. Troubleshooting

### Login Fails or Redirect Loop

**Symptoms:** Clicking "Sign in with Logto" redirects you in a loop, or you see an error page.

**Possible causes:**

- The Logto endpoint is unreachable. Verify that Logto is running: `docker compose ps logto`.
- The SPA client ID is incorrect. Check that `VITE_LOGTO_CLIENT_ID` (or the auto-configured value from bootstrap) matches the SPA application ID in Logto.
- The redirect URI is not registered. The SPA app in Logto must have your current URL's `/callback` path as an allowed redirect URI. The bootstrap registers `http://localhost/callback`, `http://localhost:8080/callback`, and `http://localhost:5173/callback` by default.

**Resolution:**

1. Check Logto logs: `docker compose logs logto`.
2. Open the Logto admin console and verify the SPA application's redirect URIs.
3. If running on a custom domain, add your callback URL to the SPA application's redirect URI list.

### 401 Errors After Login

**Symptoms:** You log in successfully but API calls return 401 Unauthorized.

**Possible causes:**

- Token audience mismatch. The backend expects tokens issued for `https://api.cameleer.local`.
- The Logto issuer URI configured in the backend does not match the actual Logto endpoint.
- Clock skew between the Logto container and the backend container.

**Resolution:**

1. Check backend logs: `docker compose logs cameleer-saas`.
2. Verify that `LOGTO_ISSUER_URI` and `LOGTO_JWK_SET_URI` in `.env` are correct.
3. If the issue persists, restart the services: `docker compose restart cameleer-saas logto`.

### Deployment Stuck in BUILDING

**Symptoms:** A deployment stays in `BUILDING` status indefinitely.

**Possible causes:**

- The Docker socket is not mounted. The `cameleer-saas` container needs access to `/var/run/docker.sock` to build images and create containers.
- The base runtime image is not available. The platform builds on top of `cameleer-runtime-base`.
- Insufficient disk space for the Docker image build.

**Resolution:**

1. Check backend logs: `docker compose logs cameleer-saas`.
2. Verify Docker socket access: `docker compose exec cameleer-saas ls -la /var/run/docker.sock`.
3. Pull the runtime base image manually: `docker pull gitea.siegeln.net/cameleer/cameleer-runtime-base:latest`.
4. Check available disk space: `docker system df`.

### Agent Not Connecting to Server

**Symptoms:** The app is running but the Agent Status card shows "Not registered."

**Possible causes:**

- The agent cannot reach the cameleer3-server endpoint. Check network connectivity between the deployed container and the observability server.
- The bootstrap token does not match. The agent uses `CAMELEER_AUTH_TOKEN` to register with the server.
- The cameleer3-server is not healthy.

**Resolution:**

1. Check cameleer3-server health: `docker compose logs cameleer3-server`.
2. Verify the app container's logs for agent connection errors (use the Logs tab on the app detail page).
3. Confirm that `CAMELEER_AUTH_TOKEN` is the same in both the `cameleer-saas` and `cameleer3-server` service configurations.

### Container Health Check Failing

**Symptoms:** A deployed container shows as unhealthy or keeps restarting.

**Possible causes:**

- The Camel application fails to start (missing dependencies, configuration errors).
- The application requires environment variables that are not set.
- The container runs out of memory (default limit is 512 MB).

**Resolution:**

1. Check the container logs from the Logs tab on the app detail page.
2. If the app crashes immediately, verify the JAR file is a valid executable Spring Boot or Camel application.
3. To increase memory limits, set `CAMELEER_CONTAINER_MEMORY_LIMIT` to a higher value (e.g., `1g`) in `.env` and restart the stack.

### Bootstrap Script Errors

**Symptoms:** The `logto-bootstrap` container exits with an error, and the `cameleer-saas` service fails to start.

**Possible causes:**

- PostgreSQL is not ready when the bootstrap runs. This is unusual because the bootstrap waits for Logto, which itself waits for PostgreSQL.
- Network issues between containers.
- Logto database is in an inconsistent state.

**Resolution:**

1. Check bootstrap logs: `docker compose logs logto-bootstrap`.
2. If the error is transient, re-run the bootstrap: `docker compose restart logto-bootstrap`.
3. For a fresh start, remove all volumes and restart:
   ```bash
   docker compose down -v
   docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
   ```

> **Warning:** The command above (`docker compose down -v`) destroys all data including databases. Only use it if you want a clean slate.
