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
Failure Expected outcome
Repeated request_key Return the original order; do not reserve again
Insufficient stock on any line No order, line, audit event, or reservation remains
Address owned by another customer Reject before durable changes
Concurrent reservation BEGIN IMMEDIATE serializes writers; predicate rechecks available stock
Unexpected exception Rollback 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

Workload Predicate/order shape Candidate index
Customer lookup email = ? UNIQUE customer(email) already supplies it
Customer order history customer_id = ? ORDER BY ordered_at DESC, order_id DESC (customer_id, ordered_at DESC, order_id DESC)
Global recent-order pagination ORDER BY ordered_at DESC, order_id DESC (ordered_at DESC, order_id DESC)
Fulfillment queue status IN (...) ORDER BY ordered_at, order_id partial or composite status/order index
Product sales joins order_item.product_id = ? (product_id, order_id)
Payment reconciliation payment.order_id = ? (order_id, status)
Shipment lookup shipment.order_id = ? (order_id, status)
Audit investigation entity_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;
Principal Allowed Denied by design
Application runtime Bound operational reads/writes needed by services DDL, role management, unrestricted deletes, backup administration
Customer service Approved views and procedures Raw payment/audit tables and bulk exports
Analyst Curated reporting views Operational mutation and sensitive raw attributes
Migration role Versioned DDL during controlled deployment Normal application login
Backup operator Backup/restore capabilities and encrypted storage access Application 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 field Capstone value
Recovery point objective Maximum accepted data loss: 24 hours for the local capstone; production target must reflect business value
Recovery time objective Restore and verification completed within 30 minutes in the exercise environment
Backup schedule Daily logical/copy backup plus pre-migration backup
Retention Seven daily and four weekly copies for the exercise; encryption and off-host storage required in production
Restore target Always restore into a separate path/database first
Verification Integrity check, foreign-key check, row counts, reconciliation queries, application smoke test
Ownership Named 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.