378 lines
11 KiB
Markdown
378 lines
11 KiB
Markdown
|
|
# Plan 4: SaaS Cleanup — Strip to Vendor Management Plane
|
||
|
|
|
||
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
|
|
||
|
|
**Goal:** Remove all migrated code from the SaaS layer (environments, apps, deployments, ClickHouse access) and strip it down to a thin vendor management plane: tenant lifecycle, license generation, billing, and Logto organization management.
|
||
|
|
|
||
|
|
**Architecture:** The SaaS retains only vendor-level concerns. All runtime management, observability, and user management is now in the server. The SaaS communicates with server instances exclusively via REST API (ServerApiClient). ClickHouse dependency is removed entirely.
|
||
|
|
|
||
|
|
**Tech Stack:** Java 21, Spring Boot 3.4.3, PostgreSQL 16
|
||
|
|
|
||
|
|
**Repo:** `C:\Users\Hendrik\Documents\projects\cameleer-saas`
|
||
|
|
|
||
|
|
**Prerequisite:** Plans 1-3 must be implemented in cameleer3-server first.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Summary of Changes
|
||
|
|
|
||
|
|
### Files to DELETE (migrated to server or no longer needed)
|
||
|
|
|
||
|
|
```
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/environment/
|
||
|
|
├── EnvironmentEntity.java
|
||
|
|
├── EnvironmentService.java
|
||
|
|
├── EnvironmentController.java
|
||
|
|
├── EnvironmentRepository.java
|
||
|
|
├── EnvironmentStatus.java
|
||
|
|
└── dto/
|
||
|
|
├── CreateEnvironmentRequest.java
|
||
|
|
├── UpdateEnvironmentRequest.java
|
||
|
|
└── EnvironmentResponse.java
|
||
|
|
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/app/
|
||
|
|
├── AppEntity.java
|
||
|
|
├── AppService.java
|
||
|
|
├── AppController.java
|
||
|
|
├── AppRepository.java
|
||
|
|
└── dto/
|
||
|
|
├── CreateAppRequest.java
|
||
|
|
└── AppResponse.java
|
||
|
|
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/deployment/
|
||
|
|
├── DeploymentEntity.java
|
||
|
|
├── DeploymentService.java
|
||
|
|
├── DeploymentController.java
|
||
|
|
├── DeploymentRepository.java
|
||
|
|
├── DeploymentExecutor.java
|
||
|
|
├── DesiredStatus.java
|
||
|
|
├── ObservedStatus.java
|
||
|
|
└── dto/
|
||
|
|
└── DeploymentResponse.java
|
||
|
|
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/runtime/
|
||
|
|
├── RuntimeOrchestrator.java
|
||
|
|
├── DockerRuntimeOrchestrator.java
|
||
|
|
├── RuntimeConfig.java
|
||
|
|
├── BuildImageRequest.java
|
||
|
|
├── StartContainerRequest.java
|
||
|
|
├── ContainerStatus.java
|
||
|
|
└── LogConsumer.java
|
||
|
|
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/log/
|
||
|
|
├── ClickHouseConfig.java
|
||
|
|
├── ClickHouseProperties.java
|
||
|
|
├── ContainerLogService.java
|
||
|
|
├── LogController.java
|
||
|
|
└── dto/
|
||
|
|
└── LogEntry.java
|
||
|
|
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/observability/
|
||
|
|
├── AgentStatusService.java
|
||
|
|
├── AgentStatusController.java
|
||
|
|
└── dto/
|
||
|
|
├── AgentStatusResponse.java
|
||
|
|
└── ObservabilityStatusResponse.java
|
||
|
|
```
|
||
|
|
|
||
|
|
### Files to MODIFY
|
||
|
|
|
||
|
|
```
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/config/AsyncConfig.java — remove deploymentExecutor bean
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/tenant/TenantService.java — remove createDefaultForTenant() call
|
||
|
|
src/main/resources/application.yml — remove clickhouse + runtime config sections
|
||
|
|
docker-compose.yml — remove Docker socket mount from SaaS, update routing
|
||
|
|
```
|
||
|
|
|
||
|
|
### Files to KEEP (vendor management plane)
|
||
|
|
|
||
|
|
```
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/tenant/ — Tenant CRUD, lifecycle
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/license/ — License generation
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/identity/ — Logto org management, ServerApiClient
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/config/ — SecurityConfig, SpaController
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/audit/ — Vendor audit logging
|
||
|
|
src/main/java/net/siegeln/cameleer/saas/apikey/ — API key management (if used)
|
||
|
|
ui/ — Vendor management dashboard
|
||
|
|
```
|
||
|
|
|
||
|
|
### Flyway Migrations to KEEP
|
||
|
|
|
||
|
|
The existing migrations (V001-V009) can remain since they're already applied. Add a new cleanup migration:
|
||
|
|
|
||
|
|
```
|
||
|
|
src/main/resources/db/migration/V010__drop_migrated_tables.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 1: Remove ClickHouse Dependency
|
||
|
|
|
||
|
|
- [ ] **Step 1: Delete ClickHouse files**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/log/ClickHouseConfig.java
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/log/ClickHouseProperties.java
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/log/ContainerLogService.java
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/log/LogController.java
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/log/dto/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Remove ClickHouse from AgentStatusService**
|
||
|
|
|
||
|
|
Delete `AgentStatusService.java` and `AgentStatusController.java` entirely (agent status is now a server concern).
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/observability/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Remove ClickHouse config from application.yml**
|
||
|
|
|
||
|
|
Remove the entire `cameleer.clickhouse:` section.
|
||
|
|
|
||
|
|
- [ ] **Step 4: Remove ClickHouse JDBC dependency from pom.xml**
|
||
|
|
|
||
|
|
Remove:
|
||
|
|
```xml
|
||
|
|
<dependency>
|
||
|
|
<groupId>com.clickhouse</groupId>
|
||
|
|
<artifactId>clickhouse-jdbc</artifactId>
|
||
|
|
</dependency>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 5: Verify build**
|
||
|
|
|
||
|
|
Run: `cd /c/Users/Hendrik/Documents/projects/cameleer-saas && mvn compile`
|
||
|
|
Expected: BUILD SUCCESS. Fix any remaining import errors.
|
||
|
|
|
||
|
|
- [ ] **Step 6: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add -A
|
||
|
|
git commit -m "feat: remove all ClickHouse dependencies from SaaS layer"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 2: Remove Environment/App/Deployment Code
|
||
|
|
|
||
|
|
- [ ] **Step 1: Delete environment package**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/environment/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Delete app package**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/app/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Delete deployment package**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/deployment/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: Delete runtime package**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf src/main/java/net/siegeln/cameleer/saas/runtime/
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 5: Remove AsyncConfig deploymentExecutor bean**
|
||
|
|
|
||
|
|
In `AsyncConfig.java`, remove the `deploymentExecutor` bean (or delete AsyncConfig if it only had that bean).
|
||
|
|
|
||
|
|
- [ ] **Step 6: Update TenantService**
|
||
|
|
|
||
|
|
Remove any calls to `EnvironmentService.createDefaultForTenant()` from `TenantService.java`. The server now handles default environment creation.
|
||
|
|
|
||
|
|
- [ ] **Step 7: Remove runtime config from application.yml**
|
||
|
|
|
||
|
|
Remove the entire `cameleer.runtime:` section.
|
||
|
|
|
||
|
|
- [ ] **Step 8: Verify build**
|
||
|
|
|
||
|
|
Run: `cd /c/Users/Hendrik/Documents/projects/cameleer-saas && mvn compile`
|
||
|
|
Expected: BUILD SUCCESS. Fix any remaining import errors.
|
||
|
|
|
||
|
|
- [ ] **Step 9: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add -A
|
||
|
|
git commit -m "feat: remove migrated environment/app/deployment/runtime code from SaaS"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 3: Database Cleanup Migration
|
||
|
|
|
||
|
|
- [ ] **Step 1: Create cleanup migration**
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- V010__drop_migrated_tables.sql
|
||
|
|
-- Drop tables that have been migrated to cameleer3-server
|
||
|
|
|
||
|
|
DROP TABLE IF EXISTS deployments CASCADE;
|
||
|
|
DROP TABLE IF EXISTS apps CASCADE;
|
||
|
|
DROP TABLE IF EXISTS environments CASCADE;
|
||
|
|
DROP TABLE IF EXISTS api_keys CASCADE;
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add src/main/resources/db/migration/V010__drop_migrated_tables.sql
|
||
|
|
git commit -m "feat: drop migrated tables from SaaS database"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 4: Remove Docker Socket Dependency
|
||
|
|
|
||
|
|
- [ ] **Step 1: Update docker-compose.yml**
|
||
|
|
|
||
|
|
Remove from `cameleer-saas` service:
|
||
|
|
```yaml
|
||
|
|
volumes:
|
||
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
||
|
|
- jardata:/data/jars
|
||
|
|
group_add:
|
||
|
|
- "0"
|
||
|
|
```
|
||
|
|
|
||
|
|
The Docker socket mount now belongs to the `cameleer3-server` service instead.
|
||
|
|
|
||
|
|
- [ ] **Step 2: Remove docker-java dependency from pom.xml**
|
||
|
|
|
||
|
|
Remove:
|
||
|
|
```xml
|
||
|
|
<dependency>
|
||
|
|
<groupId>com.github.docker-java</groupId>
|
||
|
|
<artifactId>docker-java-core</artifactId>
|
||
|
|
</dependency>
|
||
|
|
<dependency>
|
||
|
|
<groupId>com.github.docker-java</groupId>
|
||
|
|
<artifactId>docker-java-transport-zerodep</artifactId>
|
||
|
|
</dependency>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add docker-compose.yml pom.xml
|
||
|
|
git commit -m "feat: remove Docker socket dependency from SaaS layer"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 5: Update SaaS UI
|
||
|
|
|
||
|
|
- [ ] **Step 1: Remove environment/app/deployment pages from SaaS frontend**
|
||
|
|
|
||
|
|
Remove pages that now live in the server UI:
|
||
|
|
- `EnvironmentsPage`
|
||
|
|
- `EnvironmentDetailPage`
|
||
|
|
- `AppDetailPage`
|
||
|
|
|
||
|
|
The SaaS UI retains:
|
||
|
|
- `DashboardPage` — vendor overview (tenant list, status)
|
||
|
|
- `AdminTenantsPage` — tenant management
|
||
|
|
- `LicensePage` — license management
|
||
|
|
|
||
|
|
- [ ] **Step 2: Update navigation**
|
||
|
|
|
||
|
|
Remove links to environments/apps/deployments. The SaaS UI should link to the tenant's server instance for those features (e.g., "Open Dashboard" link to `https://{tenant-slug}.cameleer.example.com/server/`).
|
||
|
|
|
||
|
|
- [ ] **Step 3: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add ui/
|
||
|
|
git commit -m "feat: strip SaaS UI to vendor management dashboard"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 6: Expand ServerApiClient
|
||
|
|
|
||
|
|
- [ ] **Step 1: Add provisioning-related API calls**
|
||
|
|
|
||
|
|
The `ServerApiClient` should gain methods for tenant provisioning:
|
||
|
|
|
||
|
|
```java
|
||
|
|
public void pushLicense(String serverEndpoint, String licenseToken) {
|
||
|
|
post(serverEndpoint + "/api/v1/admin/license")
|
||
|
|
.body(Map.of("token", licenseToken))
|
||
|
|
.retrieve()
|
||
|
|
.toBodilessEntity();
|
||
|
|
}
|
||
|
|
|
||
|
|
public Map<String, Object> getHealth(String serverEndpoint) {
|
||
|
|
return get(serverEndpoint + "/api/v1/health")
|
||
|
|
.retrieve()
|
||
|
|
.body(Map.class);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add src/main/java/net/siegeln/cameleer/saas/identity/ServerApiClient.java
|
||
|
|
git commit -m "feat: expand ServerApiClient with license push and health check methods"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 7: Write SAAS-INTEGRATION.md
|
||
|
|
|
||
|
|
- [ ] **Step 1: Create integration contract document**
|
||
|
|
|
||
|
|
Create `docs/SAAS-INTEGRATION.md` in the cameleer3-server repo documenting:
|
||
|
|
- Which server API endpoints the SaaS calls
|
||
|
|
- Required auth (M2M token with `server:admin` scope)
|
||
|
|
- License injection mechanism (`POST /api/v1/admin/license`)
|
||
|
|
- Health check endpoint (`GET /api/v1/health`)
|
||
|
|
- What the server exposes vs what the SaaS must never access directly
|
||
|
|
- Env vars the SaaS sets when provisioning a server instance
|
||
|
|
|
||
|
|
- [ ] **Step 2: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /c/Users/Hendrik/Documents/projects/cameleer3-server
|
||
|
|
git add docs/SAAS-INTEGRATION.md
|
||
|
|
git commit -m "docs: add SaaS integration contract documentation"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 8: Final Verification
|
||
|
|
|
||
|
|
- [ ] **Step 1: Build SaaS**
|
||
|
|
|
||
|
|
Run: `cd /c/Users/Hendrik/Documents/projects/cameleer-saas && mvn clean verify`
|
||
|
|
Expected: BUILD SUCCESS with reduced dependency footprint.
|
||
|
|
|
||
|
|
- [ ] **Step 2: Verify SaaS starts without ClickHouse**
|
||
|
|
|
||
|
|
The SaaS should start with only PostgreSQL (and Logto). No ClickHouse required.
|
||
|
|
|
||
|
|
- [ ] **Step 3: Verify remaining code footprint**
|
||
|
|
|
||
|
|
The SaaS source should now contain approximately:
|
||
|
|
- `tenant/` — ~4 files
|
||
|
|
- `license/` — ~5 files
|
||
|
|
- `identity/` — ~3 files (LogtoConfig, ServerApiClient, M2M token)
|
||
|
|
- `config/` — ~3 files (SecurityConfig, SpaController, TLS)
|
||
|
|
- `audit/` — ~3 files
|
||
|
|
- `ui/` — stripped dashboard
|
||
|
|
|
||
|
|
Total: ~20 Java files (down from ~75).
|
||
|
|
|
||
|
|
- [ ] **Step 4: Final commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git add -A
|
||
|
|
git commit -m "chore: finalize SaaS cleanup — vendor management plane only"
|
||
|
|
```
|