ADR-001: PostgreSQL over NoSQL for Appointment Bookings¶
Status: Accepted
Context¶
The Booking Service must store and manage appointment records for up to 50 million patients and 500,000 practitioners. At peak load the system handles 90 bookings/second, each of which involves reading a practitioner's availability, creating a booking, and atomically preventing any concurrent booking of the same slot.
The core requirement is strict consistency on the write path: two patients attempting to book the same practitioner at the same slot must result in exactly one confirmed booking and one failure — with no possibility of both succeeding.
The options evaluated were:
- Amazon RDS Aurora PostgreSQL (relational, ACID, strong consistency)
- Amazon DynamoDB (NoSQL, eventual consistency by default, optional strong reads)
- MongoDB Atlas (document store, tunable consistency)
Decision¶
Use Amazon RDS Aurora PostgreSQL for the Booking, Practitioner, and Patient services.
Double-booking prevention is implemented with a unique partial index:
CREATE UNIQUE INDEX idx_no_double_book
ON bookings (practitioner_id, slot_start)
WHERE status = 'confirmed';
This index makes it physically impossible at the storage engine level for two rows with the same (practitioner_id, slot_start) to both have status = 'confirmed'. The database enforces correctness without requiring application-level distributed locks.
Consequences¶
Positive:
- Double-booking prevention is a single database primitive — no distributed lock infrastructure to operate or reason about.
- ACID transactions allow cancellation and rescheduling to be atomic (cancel old + create new in one transaction).
country_codepartitioning provides multi-country data isolation at the storage level without separate clusters.- Aurora PostgreSQL is a fully managed service: automated backups, Multi-AZ failover, storage auto-scaling, and Secrets Manager credential rotation are all built-in.
- Reader replicas are available for reporting queries without impacting the write path.
Negative:
- Schema migrations require coordination (addressed by the DB migration pipeline — see CI/CD).
- Horizontal write scaling is limited to vertical instance sizing and connection pooling; the expected 90 bookings/sec is well within a
db.r6g.xlargewriter's capacity. - NoSQL alternatives (DynamoDB) would offer near-unlimited write throughput, but replicating the double-booking guarantee would require a conditional write pattern (
ConditionExpression) that is less ergonomic and harder to audit.
Trade-off accepted: PostgreSQL's write throughput ceiling is not a constraint at the projected load. The operational simplicity and correctness guarantees of a unique index outweigh the theoretical write scalability ceiling of a relational database.