From one EC2 with files on disk to a managed AWS stack: Postgres as the single source of truth, S3 for files, the wiki kept in sync within seconds and in order, and answers tuned to who is asking. Everything is defined in CloudFormation; CloudFront comes later.
The webhook returns in milliseconds and the work happens behind a queue, but each page change is applied exactly once, in the order the wiki made it, and Quorum can say for every page whether it is current. A change that goes missing is caught and repaired, never left to drift.
{page, version} to SQS FIFO with the page as message group and page+version as dedup id. Returns 200./api/v1, behind API Gateway with throttling.read:reports, used by a small Forge app or macro in the wiki.Each person has a profile: team, role, skills with a level (say Kubernetes 5, RF 2), areas they own, and how deep they like answers. People set it themselves; admins can adjust it; Quorum can suggest skills from activity, which the person confirms.
| Component | Job in Quorum | Replaces in the POC |
|---|---|---|
| VPC | 2 AZs, public and private subnets, NAT for outbound calls, VPC endpoints for S3, SQS, Secrets, ECR and Bedrock | default VPC |
| ALB + ACM + Route 53 | HTTPS and WebSocket entry, a real hostname and certificate | EC2 public IP, port 8000 |
| CloudFront + WAFlater | edge caching of static files, rate limits, IP rules | security group allow-list |
| Cognito | the existing pool, plus a machine client and scopes for the wiki | same pool |
| ECS Fargate + ECR | quorum-web (2+ tasks) and quorum-worker; images built by Bitbucket Pipelines | Docker Compose on EC2 |
| Aurora PostgreSQL Serverless v2 | system of record: users, profiles, skills, sessions, members, messages, documents, reports, wiki pages, audit; pgvector for retrieval | JSON files on EBS |
| S3 | uploaded files and every version, wiki attachments, exports; versioning, KMS, lifecycle rules | docs/vN.md on disk |
| ElastiCache (Valkey) | WebSocket fan-out across web tasks, presence, rate limits | in-process fan-out |
| API Gateway (HTTP API) | wiki webhooks in, Wiki API out, throttling, JWT authorizer | none |
| Lambda | webhook signature check and enqueue; also the Cognito password setter you already have | none |
| SQS FIFO + DLQ | ordered wiki changes per page; report and document jobs | debounce timer in the process |
| EventBridge Scheduler | 15-minute reconcile, nightly re-embed and cleanup | none |
| Bedrock | Claude for answers, an embeddings model for retrieval; IAM instead of an API key | OpenRouter key (keep as fallback) |
| Secrets Manager + KMS | DB credentials with rotation, wiki API token, webhook secret | same |
| SES | invitations from your own domain, no 50-a-day limit | Cognito default email |
| CloudWatch + X-Ray | logs, queue-age and DLQ alarms, traces, token usage per session | docker logs |
| AWS Backup | Aurora snapshots and S3 backup plans | EBS snapshots |
Check which Claude and embedding models Bedrock offers in eu-south-1 directly, and which need the EU cross-region inference profile.
One stack per layer, each exporting what the next one needs, so the app can be redeployed many times a day without touching the network or the data.
Separate dev and prod accounts (or at least stacks), with the same templates and different parameters.
Why Postgres with pgvector rather than a separate vector store: the page, its chunks, its vectors and its permissions change in one transaction. That is what makes the sync consistent instead of eventual.