Chapter 18 · Capstone: Design a Production-Ready Database

Add Transactions, Indexes, Security, and Evolution Plans

Complete the production design by adding transaction boundaries, concurrency controls, indexes, tenant/security rules, auditability, denormalized projections, and safe schema-evolution plans.

Beginner85–120 minutesProduction hardeningLast reviewed: August 2026

Learning outcomes

A normalized schema is necessary but not sufficient. Production design must also survive concurrent users, hot queries, tenant isolation, failures, schema evolution, and operational monitoring. This lesson turns the capstone schema into a production architecture.

01

Define transaction boundaries and concurrency controls.

02

Add indexes from measured access patterns.

03

Apply security, tenant isolation, audit, and data minimization.

04

Design denormalized projections and migration paths deliberately.

Command: OpenWorkOrder

Transaction:

  1. validate tenant, Asset, and current ownership/business rules;
  2. insert WorkOrder;
  3. insert initial status event;
  4. insert audit/outbox event;
  5. commit.

Command: AssignTechnician

Protect:

  • WorkOrder must accept assignments;
  • Technician belongs to same tenant;
  • Technician is active;
  • primary-assignment uniqueness;
  • optional scheduling overlap rule.

Command: RecordPartUsage

sql · example
BEGIN;UPDATE part_inventorySET available_qty = available_qty - :qtyWHERE tenant_id = :tenant  AND part_id = :part  AND available_qty >= :qty;-- verify one row changedINSERT INTO part_usage (...);INSERT INTO audit_event (...);COMMIT;

This avoids a lost-update inventory race.

Command: CloseWorkOrder

Check within one protected transaction:

  • current status allows closure;
  • no active assignments remain;
  • required fields/checklists complete;
  • closed_at is set;
  • status event and audit event are written.

Optimistic versioning

sql · example
UPDATE work_orderSET problem_description = :new_text,    version = version + 1WHERE tenant_id = :tenant  AND work_order_id = :id  AND version = :expected_version;

Use for user edits where conflicts are relatively rare.

Pessimistic coordination

For invariant-heavy commands, lock the WorkOrder parent row or use serializable isolation if appropriate. Keep transactions short and never wait on external APIs while holding database locks.

Index portfolio

Access patternCandidate index
WorkOrder by numberUNIQUE(tenant_id, work_order_number)
Asset history(tenant_id, asset_id, opened_at DESC)
Technician schedule(tenant_id, technician_id, started_at)
Active work queuePartial/composite active-status index
Part lookupUNIQUE(tenant_id, sku)

Index restraint

PartUsage may be write-heavy. Do not add every reporting index to the OLTP primary. Keep integrity/hot-path indexes and move heavy analytics to materialized/warehouse structures when needed.

Tenant isolation

Use defense in depth:

  • tenant_id on tenant-owned rows;
  • tenant-aware FKs;
  • tenant-scoped unique constraints;
  • tenant-first indexes;
  • application predicates;
  • row-level security where appropriate;
  • cross-tenant negative tests.

Least privilege

Separate service roles:

model · example
dispatch_serviceinventory_servicebilling_servicereporting_readonlymigration_admin

Do not give runtime services DDL privileges.

Sensitive data

Keep tax identifiers, credentials, and unrelated billing secrets out of WorkOrder/technician operational views. Minimize copies into audit and analytics systems.

Auditability

Audit events should capture:

model · example
tenantactoractionentityrequest/correlation IDtimereason where needed

Avoid unrestricted full-row sensitive snapshots.

Denormalized read projection

model · example
WorkOrderListProjection(  tenant_id,  work_order_id,  work_order_number,  asset_display,  customer_display,  status_display,  opened_at,  source_version)

Use an outbox/event stream and define a freshness SLA, e.g. ≤5 seconds.

Dashboard summary

model · example
DailyWorkOrderSummary(  tenant_id,  day,  status_code,  work_order_count)

Derived, rebuildable, and explicitly not the source of truth.

JSON strategy

For DiagnosticCapture:

  • store raw/versioned payload;
  • keep common fields typed;
  • index only proven hot JSON paths;
  • promote fields that become business-critical.

Retention plan

DatasetIllustrative policy
Diagnostic raw payloadShorter operational retention
WorkOrder/historyLonger business retention
AuditEventProtected policy-driven retention
Cache/search projectionRebuildable, delete with source lifecycle

Evolution plan: add service_region_id

  1. add nullable column;
  2. deploy writers;
  3. backfill in batches;
  4. add/index FK;
  5. validate;
  6. enforce NOT NULL;
  7. remove compatibility code.

Evolution plan: rename concept

Use expand-and-contract for a customer/account rename rather than direct destructive rename during a rolling deployment.

Observability

Monitor:

  • p95/p99 query latency;
  • lock waits/deadlocks;
  • serialization retries;
  • replication lag;
  • index usage and size;
  • projection freshness;
  • tenant-isolation policy failures.

Failure scenarios

Test:

  1. duplicate RecordPartUsage request;
  2. concurrent inventory decrement;
  3. two primary assignments concurrently;
  4. cache unavailable;
  5. projection lagging;
  6. backfill worker crash;
  7. old/new app versions overlapping.

Checkpoint

Reporting index request

An analyst asks for six new indexes on PartUsage to speed monthly reports. The table receives 40,000 inserts/minute. What should you do?

Review answer

Measure the reports and write impact first. Keep only indexes justified for operational integrity/hot paths on the OLTP table, and consider summaries, replicas, partitions, or a warehouse for scan-heavy monthly analytics.

Summary and next lesson

The capstone is now hardened around transactions, concurrency, indexes, tenant isolation, least privilege, auditability, projections, retention, and safe evolution. The final lesson tests and documents the design so it can be defended to engineers, stakeholders, and operators.

References

  • Course Chapters 10–17.
  • Martin Kleppmann, Designing Data-Intensive Applications.
  • DBMS documentation on transactions, indexes, roles, and online migrations.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.