Track: C — Architecture and Platform Strategy
This document indexes every architecture decision record (ADR) and key technology choice in the platform. Use it as a decision rationale map: find the question, read the summary, click through to the full ADR for context/alternatives/consequences.
Each entry follows: Question → Decision → Rationale (1-2 lines) → ADR link.
For in-depth trade-off analysis ("why not X?"), open the linked ADR file.
Decision: Redpanda (Kafka-compatible, no Zookeeper) for local dev; MSK Serverless for AWS prod.
Rationale: Redpanda gives Kafka wire-protocol compatibility with a single binary (no Zookeeper). The event-log model (replay from any offset) enables CQRS read models. Switch to MSK Serverless in prod uses the same aiokafka code.
Decision: pgvector on a Postgres instance dedicated to inference (not shared with the ingestor). No Qdrant today — deferred pending a concrete need, not rejected.
Rationale: Real per-service database ownership without taking on a second database engine to operate. Supersedes ADR 002, which was written for an earlier, larger design that predates the current MVP scope and was never archived when the project pivoted.
→ ADR 015 (ADR 002, superseded: stub)
Decision: HTMX + Jinja2 for ops/admin workflows; React/Vite for rich client interaction; Next.js for SEO/public pages.
Rationale: HTMX keeps the server as source of truth without a JS build pipeline. React/Next.js adopted only when UX complexity or SEO requirements justify it.
Decision: BuildKit with cache mounts for 3-5x faster rebuilds; Trivy + pip-audit for scanning.
Rationale: BuildKit's --mount=type=cache persists apt/pip layers across builds. Trivy is free, fast, and integrates with GitHub Code Scanning via SARIF.
Decision: GitHub OIDC for CI/CD authentication; no AWS access keys in GitHub Secrets.
Rationale: OIDC generates short-lived credentials per workflow run. Compromised tokens expire in minutes. Full CloudTrail audit trail of every role assumption.
(ADR 005 not yet written up — this entry predates the ADR file existing.)
Decision: S3 backend + native lockfile locking (Terraform >= 1.9).
Rationale: Remote state with versioning enables audit trail and team collaboration. Lockfile locking eliminates DynamoDB dependency.
(ADR 006 not yet written up — this entry predates the ADR file existing.)
Decision: In-process migration runner at startup; not a separate init container or sidecar.
Rationale: Simpler deployment (no extra container), Alembic runs in the same process as the app, fail-fast on migration errors.
Decision: ECS Fargate for this project scale (1-10 microservices).
Rationale: ECS Fargate eliminates Kubernetes control-plane operations. Cost-optimized for small-to-medium service counts. Kubernetes is a separate learning path.
(ADR 008 not yet written up — this entry predates the ADR file existing.)
Decision: LangGraph StateGraph with dual-model routing (gpt-4o-mini for classify, gpt-4o for deep analysis).
Rationale: LangGraph gives structured state-machine control over agent flow. Dual-model routing saves ~10x cost by using the cheap model for 90% of calls.
Decision: Separate management plane (app-level RBAC, tenant admin) from ops plane (infrastructure, observability access).
Rationale: Clear separation of concerns between product administrators and SRE/DevOps roles. Each plane has independent auth boundaries.
| Question | Answer |
|---|---|
| I/O-bound or CPU-bound? | I/O → async; CPU → processes |
| API framework? | FastAPI (async JSON) / Django (full-stack) / Flask (simple) |
| Primary DB? | PostgreSQL almost always; MongoDB for genuinely varied document shapes |
| ORM vs raw SQL? | ORM for CRUD; raw SQL for analytics |
| Cache or not? | Only after measuring; fail-open pattern |
| Message broker? | Redpanda (learning/dev); MSK (prod) |
| Vector store? | pgvector (existing Postgres, <10M); Qdrant (scale + dedicated) |
| Frontend? | HTMX (backend devs, server-rendered); React (complex SPA) |
| Cloud compute? | ECS Fargate (managed, learning); EKS (K8s expertise required) |
| Cloud database? | RDS PostgreSQL (cost); Aurora (HA + replicas, 3x cost) |
| Cloud cache? | ElastiCache Cache (persistent); Memcached (simple, fast) |
| Cloud message queue? | MSK Serverless (managed, IAM auth); self-managed Kafka (control) |
| Infrastructure code? | Terraform (popular, HCL); CloudFormation (AWS-native, verbose) |
| Terraform state? | Remote S3 + lockfile (team-safe); local (solo, risky) |
| CI/CD secrets? | GitHub OIDC (no AWS keys, audit trail); AWS access keys (simple, risky) |
| Auth? | JWT (stateless, multi-service); Sessions (need immediate revocation) |
| Distributed txn? | Saga pattern (event choreography) |
| Schema migrations? | Alembic (production); create_all() (tests only) |
| Docker build system? | BuildKit with cache mounts (fast rebuilds); Legacy builder (simple) |
| Base image pinning? | Digest pinning (reproducible); version tags (auto-patch) |
| Container scanning? | Trivy (free, fast); Snyk (managed, compliance) |
| Dependency scanning? | pip-audit (Python CVEs); Bandit (code security issues) |
| Security gates? | Pre-commit hooks (local); GHA CI/CD (automated verification) |