# dd0c/portal — Dual-Mode Deployment Addendum **Template:** Based on dd0c/route dual-mode pattern --- ## Cloud → Self-Hosted Service Mapping | Cloud Service | Self-Hosted Replacement | Notes | |--------------|----------------------|-------| | Aurora Serverless v2 | PostgreSQL container | Same schema, pgvector extension | | Step Functions | Temporal or simple cron | Discovery orchestration | | Lambda (scanners) | Scanner containers | Same code, containerized | | Cognito | Local JWT (HS256) | AuthProvider pattern | | Meilisearch (managed) | Meilisearch container | Already self-hostable | | S3 | Local FS or MinIO | Discovery artifacts | | SES | SMTP relay | Notifications | | CloudWatch | Prometheus + Grafana | Bundled | ## Self-Hosted Compose Services ```yaml services: api: # Dashboard API + discovery orchestrator image: ghcr.io/dd0c/portal-api:latest scanner-aws: # AWS discovery scanner image: ghcr.io/dd0c/portal-scanner-aws:latest scanner-github: # GitHub discovery scanner image: ghcr.io/dd0c/portal-scanner-github:latest dashboard: # React SPA with Cmd+K search image: ghcr.io/dd0c/portal-dashboard:latest postgres: # Catalog + pgvector image: pgvector/pgvector:pg16 meilisearch: # Full-text search image: getmeili/meilisearch:latest volumes: - meili_data:/meili_data redis: # Prefix cache for Cmd+K image: redis:7-alpine caddy: image: caddy:2-alpine ``` ## Key Difference: Step Functions → Cron Self-hosted replaces Step Functions with a simple cron scheduler inside the API container: - AWS scan: every 6 hours - GitHub scan: every 4 hours - Scans run as background tasks, progress streamed via WebSocket (same as cloud) ## Epic Impact | Epic | Change | Effort | |------|--------|--------| | 1 (AWS Scanner) | Lambda → container, Step Functions → cron | 3 pts | | 2 (GitHub Scanner) | Lambda → container | 2 pts | | 3 (Service Catalog) | Aurora → PostgreSQL container (same schema) | 1 pt | | 4 (Search) | Already Meilisearch — no change | 0 | | 5 (Dashboard UI) | Local login form | 2 pts | | 6 (Analytics) | No change | 0 | | 7 (Dashboard API) | LocalAuthProvider | 2 pts | | 8 (Infrastructure) | docker-compose.yml + install.sh | 5 pts | | 9 (Onboarding) | Local signup, remove Stripe req, WebSocket same | 3 pts | | 10 (TF Tenets) | No change | 0 | | **Total** | | **18 pts** |