Add dual-mode deployment addendums for all 6 products
P1 route: 16 pts (template, full docker-compose + install script) P2 drift: 17 pts (pgmq, local CA for mTLS) P3 alert: 19 pts (Lambda→Fastify, DynamoDB→PG JSONB) P4 portal: 18 pts (Step Functions→cron, Aurora→PG+pgvector) P5 cost: 19 pts (EventBridge→agent/polling, DynamoDB→PG JSONB) P6 run: 15 pts (easiest — already PG-native, no AWS deps in core) Total self-hosted effort: ~104 story points across all 6 products
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# dd0c/alert — Dual-Mode Deployment Addendum
|
||||
|
||||
**Template:** Based on dd0c/route dual-mode pattern
|
||||
|
||||
---
|
||||
|
||||
## Cloud → Self-Hosted Service Mapping
|
||||
|
||||
| Cloud Service | Self-Hosted Replacement | Notes |
|
||||
|--------------|----------------------|-------|
|
||||
| API Gateway + Lambda | Fastify/Express container | Webhook ingestion endpoint |
|
||||
| SQS | PostgreSQL pgmq | Between ingestion and correlation |
|
||||
| ECS Fargate (Correlation) | Docker container | Same Node.js code |
|
||||
| DynamoDB | PostgreSQL (JSONB) | Incidents stored as JSONB with GIN indexes |
|
||||
| TimescaleDB on RDS | TimescaleDB container | Analytics unchanged |
|
||||
| Cognito | Local JWT (HS256) | AuthProvider pattern |
|
||||
| S3 (raw payload archive) | Local FS or MinIO | ObjectStore trait |
|
||||
| SES | SMTP relay | Email notifications |
|
||||
| EventBridge | Cron container | Scheduled tasks |
|
||||
|
||||
## Self-Hosted Compose Services
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ingestion: # Webhook endpoint (replaces API Gateway + Lambda)
|
||||
image: ghcr.io/dd0c/alert-ingestion:latest
|
||||
correlation: # Correlation engine (replaces ECS Fargate)
|
||||
image: ghcr.io/dd0c/alert-correlation:latest
|
||||
api: # Dashboard API
|
||||
image: ghcr.io/dd0c/alert-api:latest
|
||||
dashboard: # React SPA
|
||||
image: ghcr.io/dd0c/alert-dashboard:latest
|
||||
postgres: # Incidents (JSONB) + config
|
||||
image: postgres:16-alpine
|
||||
timescaledb: # Analytics
|
||||
image: timescale/timescaledb:latest-pg16
|
||||
redis: # Sliding windows for correlation, circuit breakers
|
||||
image: redis:7-alpine
|
||||
caddy: # Reverse proxy + auto-TLS
|
||||
image: caddy:2-alpine
|
||||
```
|
||||
|
||||
## Key Difference: DynamoDB → PostgreSQL JSONB
|
||||
|
||||
DynamoDB Single-Table design maps to PostgreSQL JSONB with partition-like indexes:
|
||||
|
||||
```sql
|
||||
CREATE TABLE incidents (
|
||||
id UUID PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
data JSONB NOT NULL,
|
||||
severity TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'open',
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX idx_incidents_tenant ON incidents(tenant_id);
|
||||
CREATE INDEX idx_incidents_data ON incidents USING GIN(data);
|
||||
-- RLS policy
|
||||
ALTER TABLE incidents ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY tenant_isolation ON incidents USING (tenant_id = current_setting('app.tenant_id'));
|
||||
```
|
||||
|
||||
## Epic Impact
|
||||
|
||||
| Epic | Change | Effort |
|
||||
|------|--------|--------|
|
||||
| 1 (Webhook Ingestion) | Lambda → Fastify container | 3 pts |
|
||||
| 2 (Normalization) | No change — pure logic | 0 |
|
||||
| 3 (Correlation) | pgmq instead of SQS, same Redis | 2 pts |
|
||||
| 4 (Notifications) | SMTP fallback | 1 pt |
|
||||
| 5 (Slack Bot) | No change | 0 |
|
||||
| 6 (Dashboard API) | LocalAuthProvider, DynamoDB→PG | 3 pts |
|
||||
| 7 (Dashboard UI) | Local login form | 2 pts |
|
||||
| 8 (Infrastructure) | docker-compose.yml + install.sh | 5 pts |
|
||||
| 9 (Onboarding) | Local signup, remove Stripe req | 3 pts |
|
||||
| 10 (TF Tenets) | No change | 0 |
|
||||
| **Total** | | **19 pts** |
|
||||
Reference in New Issue
Block a user