78 lines
2.8 KiB
Markdown
78 lines
2.8 KiB
Markdown
|
|
# 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** |
|