Chapter 18 · Capstone: Design and Query a Complete Database

Add Transactions, Indexes, Security, and Backup Procedures

Correct tables and queries are not a production system. This lesson adds failure boundaries, concurrency-aware inventory reservation, duplicate-request protection, query-plan evidence, access controls, parameter binding, backup procedures, and restore tests.

Capstone200–245 minutesProduction hardening + reliability laboratoryLast reviewed: August 2026

Learning outcomes

Learning outcomes

01

Implement atomic, idempotent order placement with inventory reservation and explicit failure behavior.

02

Choose indexes from query predicates, joins, ordering, uniqueness, and measured plans.

03

Separate read, write, administrative, and analytical privileges in a production design.

04

Use parameter binding and allow-listed identifiers at the application boundary.

05

Create, restore, verify, and document backups against recovery objectives.

Production hardening model

TXN

Transaction boundary

All state changes that make one business action true commit together or roll back together.

IDX

Access path

Indexes support measured read patterns while adding write, storage, maintenance, and deployment cost.

SEC

Trust boundary

Roles, views, parameter binding, secrets, and audit evidence reduce what each actor can do.

REC

Recovery system

Backups matter only when restore procedures are tested against defined loss and downtime targets.

Request
Validate identity
Begin transaction
Check idempotency
Reserve stock
Write order
Commit
Return durable result

The request either reaches one durable state or leaves no partial business action.

Atomic and idempotent order placement

python · SQLite service transaction
import sqlite3from dataclasses import dataclass@dataclass(frozen=True)class Line:    product_id: int    quantity: intdef place_order(db: sqlite3.Connection, *, request_key: str,                order_number: str, customer_id: int,                address_id: int, warehouse_id: int,                lines: list[Line]) -> int:    db.execute('PRAGMA foreign_keys = ON')    db.execute('BEGIN IMMEDIATE')    try:        existing = db.execute(            'SELECT order_id FROM sales_order WHERE request_key = ?',            (request_key,),        ).fetchone()        if existing:            db.commit()            return existing[0]        address_owner = db.execute(            'SELECT customer_id FROM address WHERE address_id = ?',            (address_id,),        ).fetchone()        if not address_owner or address_owner[0] != customer_id:            raise ValueError('shipping address does not belong to customer')        if not lines:            raise ValueError('order requires at least one line')        order_id = db.execute(            '''INSERT INTO sales_order(                 order_number,customer_id,shipping_address_id,                 status,currency_code,ordered_at,request_key               ) VALUES(?,?,?,'submitted','USD',CURRENT_TIMESTAMP,?)               RETURNING order_id''',            (order_number, customer_id, address_id, request_key),        ).fetchone()[0]        for line_no, line in enumerate(lines, 1):            product = db.execute(                'SELECT unit_price_cents, active FROM product WHERE product_id = ?',                (line.product_id,),            ).fetchone()            if not product or product[1] != 1:                raise ValueError(f'product unavailable: {line.product_id}')            changed = db.execute(                '''UPDATE inventory                   SET reserved = reserved + ?, updated_at = CURRENT_TIMESTAMP                   WHERE warehouse_id = ? AND product_id = ?                     AND on_hand - reserved >= ?''',                (line.quantity, warehouse_id, line.product_id, line.quantity),            ).rowcount            if changed != 1:                raise ValueError(f'insufficient stock: {line.product_id}')            db.execute(                '''INSERT INTO order_item(                     order_id,line_no,product_id,quantity,unit_price_cents                   ) VALUES(?,?,?,?,?)''',                (order_id, line_no, line.product_id, line.quantity, product[0]),            )        db.execute(            '''INSERT INTO audit_event(                 entity_type,entity_id,action,actor,occurred_at,details               ) VALUES('sales_order',?,'created','api:checkout',CURRENT_TIMESTAMP,?)''',            (str(order_id), f'{{"request_key":"{request_key}"}}'),        )        db.commit()        return order_id    except Exception:        db.rollback()        raise
FailureExpected outcome
Repeated request_keyReturn the original order; do not reserve again
Insufficient stock on any lineNo order, line, audit event, or reservation remains
Address owned by another customerReject before durable changes
Concurrent reservationBEGIN IMMEDIATE serializes writers; predicate rechecks available stock
Unexpected exceptionRollback the complete unit of work and surface an observable error

Transaction tests

python · success, idempotency, and rollback
def test_order_transaction(db):    before = db.execute(        'SELECT reserved FROM inventory WHERE warehouse_id=2 AND product_id=12'    ).fetchone()[0]    first = place_order(        db,        request_key='req-capstone-1',        order_number='NS-2026-CAP-1',        customer_id=2,        address_id=201,        warehouse_id=2,        lines=[Line(12, 2)],    )    second = place_order(        db,        request_key='req-capstone-1',        order_number='ignored-on-retry',        customer_id=2,        address_id=201,        warehouse_id=2,        lines=[Line(12, 2)],    )    assert first == second    after = db.execute(        'SELECT reserved FROM inventory WHERE warehouse_id=2 AND product_id=12'    ).fetchone()[0]    assert after == before + 2    try:        place_order(            db,            request_key='req-capstone-fail',            order_number='NS-2026-CAP-X',            customer_id=2,            address_id=201,            warehouse_id=2,            lines=[Line(12, 999)],        )    except ValueError:        pass    assert db.execute(        "SELECT COUNT(*) FROM sales_order WHERE request_key='req-capstone-fail'"    ).fetchone()[0] == 0

Index workload from evidence

WorkloadPredicate/order shapeCandidate index
Customer lookupemail = ?UNIQUE customer(email) already supplies it
Customer order historycustomer_id = ? ORDER BY ordered_at DESC, order_id DESC(customer_id, ordered_at DESC, order_id DESC)
Global recent-order paginationORDER BY ordered_at DESC, order_id DESC(ordered_at DESC, order_id DESC)
Fulfillment queuestatus IN (...) ORDER BY ordered_at, order_idpartial or composite status/order index
Product sales joinsorder_item.product_id = ?(product_id, order_id)
Payment reconciliationpayment.order_id = ?(order_id, status)
Shipment lookupshipment.order_id = ?(order_id, status)
Audit investigationentity_type + entity_id ORDER BY occurred_at(entity_type, entity_id, occurred_at DESC)
sql · Chapter 18 indexes
CREATE INDEX idx_order_customer_history  ON sales_order(customer_id, ordered_at DESC, order_id DESC);CREATE INDEX idx_order_recent  ON sales_order(ordered_at DESC, order_id DESC);CREATE INDEX idx_order_fulfillment  ON sales_order(status, ordered_at, order_id)  WHERE status IN ('submitted','paid','packed');CREATE INDEX idx_order_item_product  ON order_item(product_id, order_id);CREATE INDEX idx_payment_order_status  ON payment(order_id, status);CREATE INDEX idx_shipment_order_status  ON shipment(order_id, status);CREATE INDEX idx_audit_entity_time  ON audit_event(entity_type, entity_id, occurred_at DESC);

Read the plans before and after

sql · plan evidence
EXPLAIN QUERY PLANSELECT order_id, order_number, status, ordered_atFROM sales_orderWHERE customer_id = 1ORDER BY ordered_at DESC, order_id DESCLIMIT 20;EXPLAIN QUERY PLANSELECT order_id, order_number, status, ordered_atFROM sales_orderWHERE status IN ('submitted','paid','packed')ORDER BY ordered_at, order_id;

Record the query, representative parameters, row counts, database version, plan before, plan after, and measured timing. An index is accepted because it improves an important workload at tolerable write cost—not because its column names look plausible.

Least-privilege production design

sql · PostgreSQL role sketch
CREATE ROLE northstar_readonly NOLOGIN;CREATE ROLE northstar_app NOLOGIN;CREATE ROLE northstar_analyst NOLOGIN;GRANT USAGE ON SCHEMA northstar TO northstar_readonly, northstar_app, northstar_analyst;GRANT SELECT ON ALL TABLES IN SCHEMA northstar TO northstar_readonly;GRANT SELECT, INSERT, UPDATE ON  northstar.sales_order,  northstar.order_item,  northstar.payment,  northstar.shipment,  northstar.audit_eventTO northstar_app;GRANT SELECT ON northstar.reporting_monthly_revenue TO northstar_analyst;REVOKE DELETE ON northstar.audit_event FROM northstar_app;REVOKE ALL ON SCHEMA public FROM PUBLIC;
PrincipalAllowedDenied by design
Application runtimeBound operational reads/writes needed by servicesDDL, role management, unrestricted deletes, backup administration
Customer serviceApproved views and proceduresRaw payment/audit tables and bulk exports
AnalystCurated reporting viewsOperational mutation and sensitive raw attributes
Migration roleVersioned DDL during controlled deploymentNormal application login
Backup operatorBackup/restore capabilities and encrypted storage accessApplication business operations

Parameterized access boundary

python · values bound, identifiers allow-listed
ALLOWED_SORTS = {    'newest': 'ordered_at DESC, order_id DESC',    'oldest': 'ordered_at ASC, order_id ASC',    'number': 'order_number ASC',}def list_orders(db, customer_id: int, sort_name: str, limit: int = 50):    order_by = ALLOWED_SORTS.get(sort_name)    if order_by is None:        raise ValueError('unsupported sort')    limit = max(1, min(limit, 100))    sql = f'''SELECT order_id, order_number, status, ordered_at              FROM sales_order              WHERE customer_id = ?              ORDER BY {order_by}              LIMIT ?'''    return db.execute(sql, (customer_id, limit)).fetchall()

Bind data values. SQL identifiers and syntax positions generally cannot be bound, so select them from a fixed allow-list rather than concatenating user input.

Backup and restore procedure

python · consistent SQLite backup and verification
import sqlite3from pathlib import Pathdef create_verified_backup(source_path: str, backup_path: str) -> None:    Path(backup_path).unlink(missing_ok=True)    with sqlite3.connect(source_path) as source, sqlite3.connect(backup_path) as target:        source.backup(target)    with sqlite3.connect(backup_path) as restored:        restored.execute('PRAGMA foreign_keys = ON')        assert restored.execute('PRAGMA integrity_check').fetchone()[0] == 'ok'        assert restored.execute('PRAGMA foreign_key_check').fetchall() == []        expected = {'customer': 4, 'product': 6, 'sales_order': 6}        for table_name, count in expected.items():            actual = restored.execute(f'SELECT COUNT(*) FROM {table_name}').fetchone()[0]            assert actual == count, (table_name, actual, count)create_verified_backup('northstar.db', 'backups/northstar-2026-08-05.db')
bash · PostgreSQL logical-backup pattern
set -euo pipefailstamp=$(date -u +%Y%m%dT%H%M%SZ)pg_dump --format=custom --no-owner --file="northstar-${stamp}.dump" northstarcreatedb northstar_restore_testpg_restore --exit-on-error --clean --if-exists   --dbname=northstar_restore_test "northstar-${stamp}.dump"psql northstar_restore_test -v ON_ERROR_STOP=1 -f db/queries/verification.sql

Recovery objectives and runbook evidence

Runbook fieldCapstone value
Recovery point objectiveMaximum accepted data loss: 24 hours for the local capstone; production target must reflect business value
Recovery time objectiveRestore and verification completed within 30 minutes in the exercise environment
Backup scheduleDaily logical/copy backup plus pre-migration backup
RetentionSeven daily and four weekly copies for the exercise; encryption and off-host storage required in production
Restore targetAlways restore into a separate path/database first
VerificationIntegrity check, foreign-key check, row counts, reconciliation queries, application smoke test
OwnershipNamed backup operator; incident commander authorizes production cutover

Hardening review

  1. Why is request_key part of the transaction design?
  2. Why is reserved <= on_hand insufficient by itself for concurrent order placement?
  3. When should an index proposal be rejected?
  4. Why is creating a backup not proof of recoverability?
Review the answers

The request key makes retries map to one durable business action. A transaction and conditional update are needed to serialize and re-check availability. Reject indexes that do not improve an important measured workload or whose write/storage cost is unjustified. Recoverability requires a separate restore plus integrity and business verification.

Lesson summary

  • Transactions define one durable business action and its all-or-nothing failure boundary.
  • Idempotency prevents retries from duplicating orders and reservations.
  • Indexes are workload evidence with ongoing costs, not decorations.
  • Least privilege separates runtime, analyst, migration, and backup capabilities.
  • Backups become reliable only through repeated restore verification and a named runbook.

References

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.