docs(openspec): add OpenSpec changes for FN-005, FN-006, FN-008, FN-009, FN-010
CI / Web CI (push) Failing after 12s
CI / API CI (push) Failing after 1m1s

- Add frontend-foundation change (FN-005) with 46 tasks
- Add deployment-config change (FN-006) with 27 tasks
- Add runfusion-poc/opencode-poc change (FN-008) with 25 tasks
- Add config-secrets change (FN-009) with 31 tasks
- Add codeserver-spawn change (FN-010) with 38 tasks
- Include project specsheet and configuration
- Archive completed deployment-config change
This commit is contained in:
2026-05-14 17:35:20 +02:00
parent 1539a67883
commit 78aaddb2b5
41 changed files with 1585 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-14
@@ -0,0 +1,67 @@
## Context
The platform routes tool instances via Traefik using subdomain patterns like `https://{tool}-{project}-{user}.{tool_domain}`. Currently, there's no automated label generation or production deployment configuration. This design establishes the deployment architecture.
Current state:
- `docker-compose.yml` for local dev only
- `docker-compose.traefik.yml` exists but is minimal
- `deploy/` directory has skeleton files
- No automated Traefik label generation
## Goals / Non-Goals
**Goals:**
- Generate Traefik labels automatically when spawning tools
- Provide production-ready Docker Compose stack
- Support Portainer-managed deployment
- Enable HTTPS with automatic certificate management
**Non-Goals:**
- Kubernetes deployment (deferred post-MVP)
- Multi-region or high-availability setup
- Custom reverse proxy (Traefik is the only supported option)
- Automatic DNS management
## Decisions
**1. Label generation in backend, not in Docker Compose**
- Rationale: Backend has all metadata (user slug, project slug, tool ID). Generating labels at spawn time is more flexible than static Compose files.
- Implementation: `TraefikLabelGenerator` service class
**2. Subdomain pattern: `{tool}-{project}-{user}.{domain}`**
- Rationale: Unique, deterministic, human-readable
- Example: `code-server-myapp-alice.headquarter.example.com`
**3. Separate Docker networks: `platform` and `tools`**
- Rationale: Network isolation between platform services and user tools
- Platform network: API, web, Traefik, database
- Tools network: Traefik + tool containers only
**4. Portainer as the deployment target**
- Rationale: Docker Compose-native, web UI for operators, supports stacks and webhooks
- Alternative: Raw Docker Compose on VM - less operator-friendly
**5. Let's Encrypt for HTTPS in production**
- Rationale: Free, automatic, Traefik has built-in support
- Alternative: Custom certificates - adds operational burden
## Risks / Trade-offs
**[Risk] Traefik label complexity grows with features**
→ Mitigation: Keep label generation centralized in one service class. Test label output against Traefik schema.
**[Risk] Portainer stack updates require downtime**
→ Mitigation: Use rolling updates where possible. Document blue-green deployment strategy.
**[Risk] Subdomain collision**
→ Mitigation: Enforce unique project slugs per user. Include user slug in subdomain.
## Migration Plan
No migration - new deployment stack is additive.
## Open Questions
1. Should we support custom domains per user/project in MVP?
2. Do we need basic auth or IP allow-listing for Traefik dashboard?
3. Should tool containers run on a separate Docker daemon for security?
@@ -0,0 +1,31 @@
## Why
The scaffold provides local Docker Compose development (FN-002) but lacks production deployment configuration. Without Traefik label generation and production stacks, tool instances cannot receive HTTPS subdomains, blocking the core value proposition of the platform.
## What Changes
- **Traefik label generator**: Backend service that generates Docker labels for subdomain routing based on tool instance metadata
- **Production Docker Compose stack**: `docker-compose.prod.yml` with API, web, Traefik, and PostgreSQL services
- **Portainer stack definition**: Docker Compose file optimized for Portainer deployment
- **Dynamic subdomain routing**: Automatic Traefik rule generation for spawned tool containers
- **HTTPS configuration**: Let's Encrypt or custom certificate support via Traefik
- **Network isolation**: Separate Docker networks for platform and tool containers
## Capabilities
### New Capabilities
- `traefik-label-generator`: Generate Traefik Docker labels for tool subdomain routing
- `production-compose-stack`: Production Docker Compose configuration
- `portainer-deployment`: Portainer-friendly stack definition and deployment guide
- `subdomain-routing`: Dynamic HTTPS subdomain allocation for tool instances
### Modified Capabilities
- None (this extends the existing deployment skeleton)
## Impact
- **apps/api/app/services/**: New Traefik label generation service
- **apps/api/app/routers/tool_instances.py**: Integrate label generation on spawn
- **deploy/**: New production deployment files
- **docker-compose.prod.yml**: Production stack definition
- **docs/deployment.md**: Updated deployment instructions
@@ -0,0 +1,22 @@
## ADDED Requirements
### Requirement: Stack deploys via Portainer
The system SHALL provide a Portainer-compatible stack definition.
#### Scenario: Portainer stack file
- **WHEN** an operator deploys via Portainer
- **THEN** they can paste the stack definition into Portainer's stack editor
- **AND** Portainer can pull and deploy all services
#### Scenario: Environment variables in Portainer
- **WHEN** the stack is deployed via Portainer
- **THEN** environment variables are configured in Portainer's UI
- **AND** the stack references these variables
### Requirement: Deployment documentation is complete
The system SHALL provide operator documentation for deployment.
#### Scenario: Deployment guide
- **WHEN** an operator reads docs/deployment.md
- **THEN** they find step-by-step instructions for Portainer deployment
- **AND** prerequisites and assumptions are clearly stated
@@ -0,0 +1,28 @@
## ADDED Requirements
### Requirement: Production stack includes all required services
The system SHALL provide a production Docker Compose stack with API, web, Traefik, and PostgreSQL.
#### Scenario: Stack services
- **WHEN** the production stack is deployed
- **THEN** the following services run: api, web, traefik, db
- **AND** Traefik routes requests to the appropriate service
- **AND** services communicate via isolated Docker networks
#### Scenario: Environment configuration
- **WHEN** the stack starts
- **THEN** it reads environment variables from .env
- **AND** sensitive values are not hardcoded
### Requirement: Production stack is secure by default
The system SHALL configure security headers and access controls in production.
#### Scenario: HTTPS only
- **WHEN** the stack runs in production
- **THEN** all traffic uses HTTPS
- **AND** HTTP redirects to HTTPS
#### Scenario: Network isolation
- **WHEN** the stack is deployed
- **THEN** platform services and tool containers are on separate networks
- **AND** tool containers cannot access the database directly
@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: Each tool instance gets a unique subdomain
The system SHALL assign a unique HTTPS subdomain to each running tool instance.
#### Scenario: Subdomain pattern
- **WHEN** a tool instance is spawned
- **THEN** its subdomain follows `{tool}-{project}-{user}.{domain}`
- **AND** the subdomain is deterministic based on instance metadata
#### Scenario: Subdomain accessibility
- **WHEN** a tool instance reaches running status
- **THEN** its subdomain resolves via DNS
- **AND** Traefik routes the subdomain to the container
- **AND** the user can access the tool via the subdomain URL
### Requirement: Subdomain is released on stop
The system SHALL remove Traefik routing when a tool instance stops.
#### Scenario: Stop removes routing
- **WHEN** a tool instance is stopped
- **THEN** Traefik labels are removed or disabled
- **AND** the subdomain no longer routes to the container
@@ -0,0 +1,24 @@
## ADDED Requirements
### Requirement: Tool spawn generates Traefik labels
The system SHALL generate Docker labels for Traefik when spawning a tool instance.
#### Scenario: Label generation on spawn
- **WHEN** a tool instance is spawned
- **THEN** the backend generates Traefik router and service labels
- **AND** labels include rule, service, port, and TLS configuration
- **AND** labels are stored with the tool instance metadata
#### Scenario: Label format
- **WHEN** labels are generated for a tool instance
- **THEN** router rule uses Host(`{subdomain}.{domain}`)
- **AND** service points to the container's exposed port
- **AND** TLS is enabled with certResolver
### Requirement: Label generation handles multiple instances
The system SHALL generate unique labels for each tool instance.
#### Scenario: Unique router names
- **WHEN** multiple instances of the same tool exist
- **THEN** each instance gets a unique router name
- **AND** no label collisions occur
@@ -0,0 +1,44 @@
## 1. Traefik Label Generator
- [x] 1.1 Create apps/api/app/services/traefik.py with TraefikLabelGenerator class
- [x] 1.2 Implement subdomain generation from tool_id, project_slug, user_slug
- [x] 1.3 Generate router labels (rule, service, tls)
- [x] 1.4 Generate service labels (loadBalancer, port)
- [x] 1.5 Add middleware labels for security headers
- [x] 1.6 Write unit tests for label generation
## 2. Backend Integration
- [x] 2.1 Integrate label generation into tool instance spawn endpoint
- [x] 2.2 Store generated labels in tool_instance metadata
- [x] 2.3 Remove/disable labels on tool instance stop
- [x] 2.4 Update ToolInstance model to store labels JSON
## 3. Production Docker Compose
- [x] 3.1 Create docker-compose.prod.yml with api, web, traefik, db services
- [x] 3.2 Configure Traefik service with Let's Encrypt certificates
- [x] 3.3 Set up platform and tools networks
- [x] 3.4 Add health checks for all services
- [x] 3.5 Configure logging (JSON format, rotation)
## 4. Portainer Deployment
- [x] 4.1 Create deploy/portainer-stack.yml
- [x] 4.2 Add Portainer-specific environment variable documentation
- [x] 4.3 Create deploy/.env.example for production
- [x] 4.4 Test stack deployment locally with docker compose -f docker-compose.prod.yml
## 5. Documentation
- [x] 5.1 Update docs/deployment.md with production deployment steps
- [x] 5.2 Add Traefik configuration guide
- [x] 5.3 Document subdomain scheme and DNS requirements
- [x] 5.4 Update README.md with deployment section
## 6. Testing & Verification
- [x] 6.1 Test label generation for all built-in tools
- [x] 6.2 Verify Traefik routes correctly in local stack
- [x] 6.3 Run backend tests: `cd apps/api && pytest`
- [x] 6.4 Run linters: `ruff check app/` and `mypy app/`