RDS Postgres
After this you can answer: Where does the data live, who can reach it, and what happens when it is down?
Picture it
Section titled “Picture it”flowchart TB API["api task<br/>uses api-sg"] -->|"TCP 5432, TLS"| DB[("minitickets-dev-db<br/>Postgres 17")] MIG["migration task<br/>uses api-sg"] -->|"TCP 5432"| DB SM["RDS master secret"] -.->|"DB_USER, DB_PASSWORD"| APIHow it works
Section titled “How it works”- Reach. The database sits in the private subnets. The api tasks reach it inside the VPC through the local route.
- Allowed.
db-sgallows TCP 5432 only fromapi-sg. - Password. The api gets the user and password from the RDS master secret at task start.
- TLS. RDS forces SSL (
rds.force_ssl), and the api checks the server’s certificate (rejectUnauthorized: true), so nobody in the middle can pretend to be the database.
In MiniTickets
Section titled “In MiniTickets”The instance is minitickets-dev-db: Postgres 17 on one db.t4g.micro (ARM, 1 GB RAM), 20 GB
gp3 storage, encrypted at rest, publiclyAccessible: false
(infra/src/data/postgres.ts → createPostgres).
Dev settings keep it cheap: single-AZ, backups kept for 1 day, no final snapshot and no deletion
protection. So switching dataEnabled off deletes the data.
The api’s connection pool holds at most 10 connections, waits 2 s for a free one and stops any
statement after 5 s (apps/api/src/db/client.ts). A slow database fails fast
instead of piling up requests.
| From → to | What happens | What allows it |
|---|---|---|
| RDS Postgres → Private subnetsonly when dataEnabled = true | the database lives in the private subnets |
|
| RDS Postgres → Database security grouponly when dataEnabled = true | the database uses the db security group |
|
| API ECS service → RDS Postgresonly when computeEnabled = true | SQL over TLS on port 5432 |
|
| Migration task definition → RDS Postgresonly when computeEnabled = true | runs node dist/migrate.js against the database |
|
| API app → RDS Postgresonly when dataEnabled = true | queries/*.ts run the SQL; a booking locks the event row (SELECT … FOR UPDATE) |
|
| Transactional outbox → RDS Postgresonly when dataEnabled = true | the outbox is a Postgres table |
|
See it in AWS
Section titled “See it in AWS”RDS → Databases → minitickets-dev-db → Connectivity & security: Endpoint, VPC security
groups, Publicly accessible: No.
aws rds describe-db-instances --db-instance-identifier minitickets-dev-db
Break it
Section titled “Break it”| Symptom | Cause | Where to look |
|---|---|---|
Timeouts on 5432, /ready fails | db-sg does not allow api-sg | db-sg → Inbound rules |
| Connection refused: no encryption | The client connected without SSL | apps/api/src/config/database.ts |
| All data gone after switching data on again | dataEnabled: false deleted it, no final snapshot | The CD run that switched it off |
Say it in an interview
Section titled “Say it in an interview”Follow-ups
Section titled “Follow-ups”What does Multi-AZ add?
A standby copy in a second availability zone, kept in sync. If the primary fails, RDS switches the endpoint to the standby in about a minute or two. It roughly doubles the cost, which is why dev is single-AZ.
What do users see when Postgres is down?
The events list may still come from the Valkey cache (served stale on error). Booking, sign-up and
log-in fail. /health still answers 200, so the ALB keeps the task, while /ready reports the
database down.
Why a relational database and not DynamoDB here?
A booking must check seats and write the booking in one transaction with a row lock. Postgres does that natively. DynamoDB is used where a simple key lookup is enough, like processed jobs.
Advanced: Connections and the pool
Ten connections per task is a deliberate cap: a db.t4g.micro allows only a limited number of
connections, and each waiting booking holds one while it waits for the row lock. The SSL settings
and the CA bundle are in apps/api/src/config/database.ts → DatabaseEnvSchema.
Checkpoint
Section titled “Checkpoint”Answer these without scrolling up. If one feels hard, reread that section.
- Which subnets hold the database, and why?
- Which rule lets the api in, and who else uses that group?
- What two settings make the connection safe from a fake database?
- What happens to the data when
dataEnabledis switched off? - Why does the pool stop a statement after 5 seconds?
Redraw it from memory: the api and migration tasks connecting to Postgres on 5432, and the secret beside them
Try this: on the map, play 'Why can the api connect to Postgres?' and name the security group rule it uses
Read this book online: https://book.theversehub.in/