All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Adds complete media storage pipeline with GCS presigned uploads, AI image/video/text generation via queue-based workers, realtime SSE event streaming, and comprehensive skeleton packages (storage, mediagen, textgen, generation, realtime, persona, routing, ai-client). Includes security fixes for media delete authorization, nil pointer guards in handlers, video persistence via download-then-upload, consistent signed URLs, and Image→ImageIcon rename to avoid DOM collision. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
187 lines
6.3 KiB
Markdown
187 lines
6.3 KiB
Markdown
# Citadel Integration Plan
|
|
|
|
rdev integrates with a **partner-hosted Citadel** instance at `citadel-staging.orchard9.ai` for centralized log aggregation, querying, and alerting across both the platform and generated projects.
|
|
|
|
## Environment Architecture
|
|
|
|
```
|
|
Organization: orchard9 (on citadel-staging.orchard9.ai)
|
|
│
|
|
├── Environment: "rdev-platform"
|
|
│ ├── rdev-api logs (stdout via agent)
|
|
│ ├── rdev-worker logs (stdout via agent)
|
|
│ ├── claudebox logs (stdout via agent)
|
|
│ └── audit events (shipped from AuditLogger)
|
|
│
|
|
├── Environment: "<project-slug>" (auto-created per project)
|
|
│ └── Project pod logs (stdout via agent, routed by k8s labels)
|
|
│
|
|
├── Tenant Group: "platform" → rdev-platform
|
|
└── Tenant Group: "projects" → all project-* environments
|
|
```
|
|
|
|
Each project gets its own Citadel environment, matching rdev's isolation model (each project gets its own DB, Redis, DNS, registry namespace).
|
|
|
|
## Integration Points
|
|
|
|
### 1. Agent DaemonSet (Log Collection)
|
|
|
|
**What:** A `citadel-agent` DaemonSet on every k3s node collects container stdout/stderr and ships to Citadel via HTTPS.
|
|
|
|
**Why:** rdev already outputs structured JSON slog to stdout. Zero code changes needed.
|
|
|
|
**Routing:** Agent reads k8s labels to route logs to the correct Citadel environment:
|
|
- `citadel.io/environment` label → determines target environment
|
|
- `citadel.io/service` label → tags the service name in Citadel
|
|
|
|
**Manifests:** `deployments/k8s/base/citadel-agent/`
|
|
|
|
### 2. Citadel Client Adapter (API Integration)
|
|
|
|
**What:** Go HTTP client for Citadel's API, following rdev's hexagonal architecture (port interface + adapter).
|
|
|
|
**Why:** Needed for auto-provisioning environments and shipping audit logs.
|
|
|
|
**Files:**
|
|
- `internal/port/citadel.go` — Port interface
|
|
- `internal/adapter/citadel/client.go` — HTTP client implementation
|
|
- `internal/adapter/citadel/audit_shipper.go` — Audit log shipping
|
|
|
|
### 3. Project Provisioning Step
|
|
|
|
**What:** When `ProjectInfraService.CreateProject()` runs, a new step creates a Citadel environment for the project.
|
|
|
|
**Why:** Each project needs its own isolated log environment. Auto-provisioning eliminates manual setup.
|
|
|
|
**Where in the flow:**
|
|
```
|
|
CreateProject()
|
|
1. Generate slug
|
|
2. Create project in DB
|
|
3. Create git repo
|
|
4. Create DNS
|
|
5. Activate CI
|
|
6. Seed template
|
|
7. Provision DB + cache
|
|
8. *** Create Citadel environment *** ← NEW
|
|
9. Create initial deployment
|
|
10. Trigger CI build
|
|
```
|
|
|
|
**Rollback:** On project deletion, the Citadel environment is deleted too.
|
|
|
|
### 4. Skeleton Template Labels
|
|
|
|
**What:** Add `citadel.io/*` labels to the skeleton's k8s deployment templates.
|
|
|
|
**Why:** The agent uses these labels to route project logs to the correct Citadel environment.
|
|
|
|
**Template vars:** `{{CITADEL_TENANT_ID}}` injected during provisioning.
|
|
|
|
### 5. Audit Log Shipping
|
|
|
|
**What:** Hook into rdev's existing `AuditLogger` to also ship audit events to Citadel.
|
|
|
|
**Why:** Unified search across application logs and security events.
|
|
|
|
**Pattern:** Wrap the existing PostgreSQL `AuditLogger` with a multi-writer that sends to both PostgreSQL and Citadel.
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables (rdev-api)
|
|
|
|
| Variable | Description | Example |
|
|
|----------|-------------|---------|
|
|
| `CITADEL_URL` | Partner Citadel instance URL | `https://citadel-staging.orchard9.ai` |
|
|
| `CITADEL_API_KEY` | API key for environment management | `ck_live_...` |
|
|
| `CITADEL_TENANT_ID` | Platform environment tenant ID | `uuid` |
|
|
| `CITADEL_ENABLED` | Enable/disable Citadel integration | `true` |
|
|
|
|
### Secrets (k8s)
|
|
|
|
```yaml
|
|
# deployments/k8s/base/citadel-agent/secret.yaml
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: citadel-agent
|
|
namespace: observability
|
|
type: Opaque
|
|
stringData:
|
|
api-key: "ck_live_..."
|
|
tenant-id: "..."
|
|
```
|
|
|
|
## Queries (What You Get)
|
|
|
|
### Platform Operations
|
|
|
|
```bash
|
|
# All errors across platform
|
|
citadel query "level:error" --tenant rdev-platform --last 1h
|
|
|
|
# Track a project lifecycle
|
|
citadel query "project_id:my-project" --tenant rdev-platform --last 24h
|
|
|
|
# Build failures
|
|
citadel query "component:build level:error" --tenant rdev-platform
|
|
|
|
# Saga failures
|
|
citadel query "component:saga result:failure" --tenant rdev-platform
|
|
|
|
# Slow API requests
|
|
citadel query "duration_ms:>5000 component:http" --tenant rdev-platform
|
|
|
|
# Audit trail
|
|
citadel query "action:project.create" --tenant rdev-platform --last 7d
|
|
```
|
|
|
|
### Generated Projects
|
|
|
|
```bash
|
|
# Query a specific project's logs
|
|
citadel query "level:error" --tenant <project-slug> --last 1h
|
|
|
|
# All project errors at once
|
|
citadel query "level:error" --group projects --last 1h
|
|
|
|
# Correlate platform + project
|
|
citadel query "project_id:my-project" --last 24h # org-wide
|
|
```
|
|
|
|
## Implementation Order
|
|
|
|
| Phase | Task | Effort |
|
|
|-------|------|--------|
|
|
| 1 | Write Citadel client adapter (`internal/adapter/citadel/`) | 2h |
|
|
| 1 | Write port interface (`internal/port/citadel.go`) | 30m |
|
|
| 2 | Deploy agent DaemonSet (`deployments/k8s/base/citadel-agent/`) | 1h |
|
|
| 2 | Add citadel labels to existing rdev-api/worker manifests | 15m |
|
|
| 3 | Add Citadel env creation to `ProjectInfraService.CreateProject()` | 2h |
|
|
| 3 | Add Citadel env deletion to `ProjectInfraService.DeleteProject()` | 30m |
|
|
| 3 | Add migration for `citadel_tenant_id` column on projects table | 15m |
|
|
| 4 | Add `citadel.io/*` labels to skeleton k8s templates | 30m |
|
|
| 4 | Add `CITADEL_TENANT_ID` to template variables | 15m |
|
|
| 5 | Implement audit log shipper | 2h |
|
|
| 5 | Wire into main.go startup | 30m |
|
|
|
|
## Files Created/Modified
|
|
|
|
### New Files
|
|
- `internal/port/citadel.go`
|
|
- `internal/adapter/citadel/client.go`
|
|
- `internal/adapter/citadel/audit_shipper.go`
|
|
- `deployments/k8s/base/citadel-agent/kustomization.yaml`
|
|
- `deployments/k8s/base/citadel-agent/daemonset.yaml`
|
|
- `deployments/k8s/base/citadel-agent/serviceaccount.yaml`
|
|
- `deployments/k8s/base/citadel-agent/configmap.yaml`
|
|
- `internal/db/migrations/024_citadel_tenant_id.sql`
|
|
|
|
### Modified Files
|
|
- `deployments/k8s/base/kustomization.yaml` — include citadel-agent
|
|
- `deployments/k8s/base/rdev-api.yaml` — add citadel labels + env vars
|
|
- `internal/service/project_infra.go` — add CitadelClient field
|
|
- `internal/service/project_infra_crud.go` — add provisioning + cleanup steps
|
|
- `internal/adapter/templates/templates/skeleton/` — k8s template labels
|
|
- `cmd/rdev-api/main.go` — wire Citadel adapter
|