Skip to content

DynamoDB deep dive: access patterns, financial authority, and recovery

Kinesis explained how records reach a consumer; this chapter asks what that consumer may safely commit and how the data will be queried. Start with the access-pattern inventory, follow each pattern into keys and indexes, then examine transactions, exact money, publication, capacity, and recovery. AP means access pattern, IDX names a key/index route, AMP names a write-amplification example, and L names a capacity lane. AP07 is the derived portfolio; AP12 is the authoritative balance/reservation boundary; AP16 is the semantic outbox.

Evidence notation: C identifies a claim in the claim register, A a dated AWS source, F a foundational source, and CS a finding in the repository case study. The source index supplies the full source details. These labels are lookup aids, not facts to memorize.

This chapter designs DynamoDB from explicit questions and invariants, not from an entity diagram or a one-table slogan. Alex DeBrie's method is the primary modeling authority: enumerate access patterns, shape item collections and indexes to answer them, then account for the operational trade-offs. The original Dynamo paper and the DynamoDB USENIX paper explain the distributed systems lineage; current AWS documentation controls mutable API behavior. The local SSE notes are prompts only and are corrected where they overreach.

The case used below is an intended repair target for the repository, not a claim that its current tables already implement this design. Canonical defects remain in the repository evidence map.

Access-pattern inventory: contract before schema

Section titled “Access-pattern inventory: contract before schema”

Inference: Every proposed key below must answer one of these stable IDs. P95 rates are design inputs for a workload test, not AWS guarantees. Size includes names, types, keys, and projected attributes—not just the JSON payload. Key conditions select the narrow set; filters may only reduce the returned set after read work has occurred (C81; A111, F21,F22,F33–F35, retrieved 2026-08-22).

APOperationKey predicatesSort, filter, orderConsistency / freshnessCardinality and item sizePeak rateOwnerInvariantFailure response
AP01get ordertenant+orderIdexact/no filterstrong command;eventual history1x1.2KiB2000 read/sOrderstenant+versionretry/reconcile by ID
AP02list account orderstenant+account+timedescending/no filtereventual<=2s100x0.45KiB/page1200 query/sOrdersdeterministic order;not snapshotcontinue LEK/surface lag
AP03list status orderstenant+account+status+timedescending/sparseeventual<=5sactive subset 0.35KiB400 query/sOrdersterminal membership removedverify base before action
AP04read order tradestenant+orderIdascending/no filterstrong for remaining qty1-20x0.9KiB1500 query/sExecutionfills<=accepted qtystop/reconcile
AP05list account tradestenant+account+timedescending/no filtereventual<=2s100x0.5KiB/page1000 query/sExecutionfill resolves to sourcepaginate/repair
AP06list symbol tradestenant+symbol+timedescending/no filtereventual<=5s100x0.4KiB/page;1page/request2000 query/s;top share 8%Executionnot sequencerformula selects shard/merge cursor
AP07read portfolio viewtenant+account+optional symbollexical/no filtereventual<=2s;rebuildable10-5000x0.8KiB3000 read/sPortfolio projectionsourceVersion+gap visiblenever authorize;rebuild
AP08claim requesttenant+client keyexact/no filterstrong immediate1x0.7KiB2000 write/sOrders APIfingerprint one resultcomplete/in-progress/mismatch
AP09claim event inboxconsumer+eventId+shardVersionexact/no filterstrong transactional2x<=1KiB (0.35KiB receipt+protected state)5000 write/sConsumerone effect/eventno-op/read/repair
AP10append ledger txntenant+account+month+bucketascending appendtransactional2-20x0.6KiB;max2m/month;250k/bucket1500 tx/sLedgerbalanced immutablereject/reconcile
AP11read ledgertenant+account+month+bucketsmerge ascending/no filterstrong investigationmax2m/month;8x<=150000KiB300 query/sLedgercomplete historypaginate bucket cursor/control totals
AP12authorize cash/securities balance+reservationtenant+account+asset(currency-or-symbol)exact/versionstrong transactional1x0.8KiB2000 tx/sLedger/Risk commandavailable policy+versionconflict retry;never projection
AP13projection checkpointprojection+source key+shardVersionexact/versionstrong1x0.3KiB5000 write/sProjectionnext once/gap visiblepark/replay/rebuild
AP14create/read/list reconciliation batchestenant+date;optional batchIdBATCH#batchId exact/prefixstrong transitions1-20KiB/batch20 batch/sFinance Opsmanifest+windowfail/restart idempotently
AP15list due reconciliation discrepanciestenant+status+shard;due<=cutoffdueAt#batchId#id rangeeventual discover;strong base resolve0-millionsx0.5KiB200 query/sFinance Opsowned resolutionpaginate/escalate/conditional resolve
AP16create/claim/complete/retry outboxeventId base;service+shard;due<=cutoffbase exact;READY GSI due ordereventual discover;strong conditional transitions1x1.6KiB+0.45KiB READY indexcreate5000/s;claim5100/s;complete5000/s;retry100/s;move20/sProducerstate+event atomic;one ownerlease/retry/reconcile
AP17client order uniquenesstenant+clientOrderIdexact/no filtertransactional condition1x0.2KiB2000 write/sOrdersone ID mappingreturn/reject mismatch
AP18idempotency repair queuetenant+shard+duedue order/sparseeventual discover;strong takeoverrare 0.3KiB100 query/sOrders Opsone repair leaseinspect/complete/escalate

The inventory deliberately separates command-current reads from eventual listing projections. A GSI cannot satisfy a strong-read requirement; an AP that authorizes a financial action therefore returns to the base item or ledger authority (C82; A19,A100, retrieved 2026-08-22).

Inference: AP07 is only a stale-tolerant portfolio projection. Even a strongly consistent read of that derived table would make only the stored copy current; it would not make the copy authoritative. Cash, securities quantities, and reservations used by risk or order admission are AP12 state owned by the Ledger/Risk command boundary; AP07 carries source versions/gaps and rebuilds from authority (C46,C91; A19,A32–A35, retrieved 2026-08-22; F08,F17,F21).

The inventory states the question; the key design must answer it without silently changing freshness or ownership. Follow the get-order and list-order patterns first: the authoritative item and the eventual history index can share data while serving different decisions. Then carry the same distinction through every proposed index and its write cost.

Inference: The bounded-context table is the working default here because it aligns service ownership and recovery while retaining one-request item collections inside a context (C94; F21,F22). It is not one table per entity: Orders, Execution, Portfolio, Ledger, Reconciliation, and consumer-owned Inbox tables each overload their base PK/SK only within an owned vocabulary.

PathKindTablePKSKRoleRead consequenceAP IDs
IDX01BASEOrdersTEN#t#ORDER#idMETAaggregate rootstrong/eventualAP01
IDX02GSI1OrdersTEN#t#ACCT#aORD#at#idprojected summaryeventualAP02
IDX03GSI2OrdersTEN#t#ACCT#a#STATUS#sORD#at#idsparse moved membershipeventualAP03
IDX04BASEExecutionTEN#t#ORDER#idTRADE#at#iditem collectionstrong/eventualAP04
IDX05GSI1ExecutionTEN#t#ACCT#aTRADE#at#idprojected summaryeventualAP05
IDX06GSI2ExecutionTEN#t#SYM#symbolTRADE#at#idunsharded at 800RRU/s top-key assumptioneventualAP06
IDX07BASEPortfolioTEN#t#ACCT#aPOS#symbolrebuildable view collectioneventual onlyAP07
IDX08BASEIdempotencyTEN#t#REQ#keyREQUESTstate/resultstrongAP08
IDX09BASEInboxCONSUMER#name#V#v#SHARD#h(eventId)%13EVENT#iddeterministic 13-shard dedupe receiptstrong transactionalAP09
IDX10BASELedgerTEN#t#ACCT#a#MONTH#yyyy-mm#BKT#nnPOST#at#txn#linesequence-range sub-bucketstrong/eventualAP10,AP11
IDX11BASELedgerTEN#t#ACCT#aAUTH#CASH#currency or AUTH#SEC#symbolcash/securities authoritystrongAP12
IDX12BASEProjectionPROJ#name#V#v#SHARD#h(sourceKey)%7SOURCE#keydeterministic 7-shard checkpoint/gapstrongAP13
IDX13BASEReconciliationTEN#t#RECON#dateBATCH#batchIdbatch list/exactstrongAP14
IDX14BASEReconciliationTEN#t#RECON#batchIdBREAK#iddiscrepancy authoritystrongAP15
IDX15GSI1ReconciliationTEN#t#BREAK#status#shardDUE#at#batch#idsparse cross-batch due queueeventualAP15
IDX16BASEContextOUTBOX#eventIdEVENTsemantic envelopestrongAP16
IDX17GSI3ContextSERVICE#svc#READY#shardDUE#at#eventIdsparse 13-shard READY due queueeventualAP16
IDX18BASEOrdersTEN#t#CLIENTORDER#idUNIQUEsentineltransactionalAP17
IDX19GSI1IdempotencyTEN#t#REPAIR#shardDUE#at#keysparse repaireventual+strong takeoverAP18

Inference: No LSI is proposed. The order/fill and account/position item collections are bounded or period-bucketed where they can grow. An LSI would freeze an alternate sort key at table creation and impose the current 10 GB item-collection limit; a GSI is operationally independent but eventually consistent and can throttle base writes when underprovisioned or hot (C86; A104, retrieved 2026-08-22).

The adjacency-list technique is justified only for true one-to-many reads: AP04 order→fills and AP07 account→portfolio-view positions. Symbol and account histories use GSIs because duplicating all reverse edges as base items would increase transaction size and ownership ambiguity. All tenant-bearing partition keys place tenant identity first for policy review but keep the naturally high-cardinality order/account/symbol identifier; a low-cardinality status is never the sole partition key.

Machine-readable AP, path, and amplification contract

Section titled “Machine-readable AP, path, and amplification contract”

The model details retain the exact source records for checking calculations. The reader tables show the important chain: an access pattern selects a route, a logical operation creates base/index work, and that work lands on a physical lane. Read amplification totals together with lane feasibility; a distributed receipt index does not prove that the protected account item can sustain the same load.

The verifier treats this block as the canonical model and cross-checks every field in the three rendered tables. base and index are already-rounded write units per logical operation; only transaction-targeted base-item writes use base-multiplier=2. Asynchronous GSI entries always use index-multiplier=1. Storage consequences are called out even when the operation is read-only.

Model details · task6 model
AP|AP01|get order|tenant+orderId|exact/no filter|strong command;eventual history|1x1.2KiB|2000 read/s|Orders|tenant+version|retry/reconcile by ID
AP|AP02|list account orders|tenant+account+time|descending/no filter|eventual<=2s|100x0.45KiB/page|1200 query/s|Orders|deterministic order;not snapshot|continue LEK/surface lag
AP|AP03|list status orders|tenant+account+status+time|descending/sparse|eventual<=5s|active subset 0.35KiB|400 query/s|Orders|terminal membership removed|verify base before action
AP|AP04|read order trades|tenant+orderId|ascending/no filter|strong for remaining qty|1-20x0.9KiB|1500 query/s|Execution|fills<=accepted qty|stop/reconcile
AP|AP05|list account trades|tenant+account+time|descending/no filter|eventual<=2s|100x0.5KiB/page|1000 query/s|Execution|fill resolves to source|paginate/repair
AP|AP06|list symbol trades|tenant+symbol+time|descending/no filter|eventual<=5s|100x0.4KiB/page;1page/request|2000 query/s;top share 8%|Execution|not sequencer|formula selects shard/merge cursor
AP|AP07|read portfolio view|tenant+account+optional symbol|lexical/no filter|eventual<=2s;rebuildable|10-5000x0.8KiB|3000 read/s|Portfolio projection|sourceVersion+gap visible|never authorize;rebuild
AP|AP08|claim request|tenant+client key|exact/no filter|strong immediate|1x0.7KiB|2000 write/s|Orders API|fingerprint one result|complete/in-progress/mismatch
AP|AP09|claim event inbox|consumer+eventId+shardVersion|exact/no filter|strong transactional|2x<=1KiB (0.35KiB receipt+protected state)|5000 write/s|Consumer|one effect/event|no-op/read/repair
AP|AP10|append ledger txn|tenant+account+month+bucket|ascending append|transactional|2-20x0.6KiB;max2m/month;250k/bucket|1500 tx/s|Ledger|balanced immutable|reject/reconcile
AP|AP11|read ledger|tenant+account+month+buckets|merge ascending/no filter|strong investigation|max2m/month;8x<=150000KiB|300 query/s|Ledger|complete history|paginate bucket cursor/control totals
AP|AP12|authorize cash/securities balance+reservation|tenant+account+asset(currency-or-symbol)|exact/version|strong transactional|1x0.8KiB|2000 tx/s|Ledger/Risk command|available policy+version|conflict retry;never projection
AP|AP13|projection checkpoint|projection+source key+shardVersion|exact/version|strong|1x0.3KiB|5000 write/s|Projection|next once/gap visible|park/replay/rebuild
AP|AP14|create/read/list reconciliation batches|tenant+date;optional batchId|BATCH#batchId exact/prefix|strong transitions|1-20KiB/batch|20 batch/s|Finance Ops|manifest+window|fail/restart idempotently
AP|AP15|list due reconciliation discrepancies|tenant+status+shard;due<=cutoff|dueAt#batchId#id range|eventual discover;strong base resolve|0-millionsx0.5KiB|200 query/s|Finance Ops|owned resolution|paginate/escalate/conditional resolve
AP|AP16|create/claim/complete/retry outbox|eventId base;service+shard;due<=cutoff|base exact;READY GSI due order|eventual discover;strong conditional transitions|1x1.6KiB+0.45KiB READY index|create5000/s;claim5100/s;complete5000/s;retry100/s;move20/s|Producer|state+event atomic;one owner|lease/retry/reconcile
AP|AP17|client order uniqueness|tenant+clientOrderId|exact/no filter|transactional condition|1x0.2KiB|2000 write/s|Orders|one ID mapping|return/reject mismatch
AP|AP18|idempotency repair queue|tenant+shard+due|due order/sparse|eventual discover;strong takeover|rare 0.3KiB|100 query/s|Orders Ops|one repair lease|inspect/complete/escalate
INDEX|IDX01|BASE|Orders|TEN#t#ORDER#id|META|aggregate root|strong/eventual|AP01
INDEX|IDX02|GSI1|Orders|TEN#t#ACCT#a|ORD#at#id|projected summary|eventual|AP02
INDEX|IDX03|GSI2|Orders|TEN#t#ACCT#a#STATUS#s|ORD#at#id|sparse moved membership|eventual|AP03
INDEX|IDX04|BASE|Execution|TEN#t#ORDER#id|TRADE#at#id|item collection|strong/eventual|AP04
INDEX|IDX05|GSI1|Execution|TEN#t#ACCT#a|TRADE#at#id|projected summary|eventual|AP05
INDEX|IDX06|GSI2|Execution|TEN#t#SYM#symbol|TRADE#at#id|unsharded at 800RRU/s top-key assumption|eventual|AP06
INDEX|IDX07|BASE|Portfolio|TEN#t#ACCT#a|POS#symbol|rebuildable view collection|eventual only|AP07
INDEX|IDX08|BASE|Idempotency|TEN#t#REQ#key|REQUEST|state/result|strong|AP08
INDEX|IDX09|BASE|Inbox|CONSUMER#name#V#v#SHARD#h(eventId)%13|EVENT#id|deterministic 13-shard dedupe receipt|strong transactional|AP09
INDEX|IDX10|BASE|Ledger|TEN#t#ACCT#a#MONTH#yyyy-mm#BKT#nn|POST#at#txn#line|sequence-range sub-bucket|strong/eventual|AP10,AP11
INDEX|IDX11|BASE|Ledger|TEN#t#ACCT#a|AUTH#CASH#currency or AUTH#SEC#symbol|cash/securities authority|strong|AP12
INDEX|IDX12|BASE|Projection|PROJ#name#V#v#SHARD#h(sourceKey)%7|SOURCE#key|deterministic 7-shard checkpoint/gap|strong|AP13
INDEX|IDX13|BASE|Reconciliation|TEN#t#RECON#date|BATCH#batchId|batch list/exact|strong|AP14
INDEX|IDX14|BASE|Reconciliation|TEN#t#RECON#batchId|BREAK#id|discrepancy authority|strong|AP15
INDEX|IDX15|GSI1|Reconciliation|TEN#t#BREAK#status#shard|DUE#at#batch#id|sparse cross-batch due queue|eventual|AP15
INDEX|IDX16|BASE|Context|OUTBOX#eventId|EVENT|semantic envelope|strong|AP16
INDEX|IDX17|GSI3|Context|SERVICE#svc#READY#shard|DUE#at#eventId|sparse 13-shard READY due queue|eventual|AP16
INDEX|IDX18|BASE|Orders|TEN#t#CLIENTORDER#id|UNIQUE|sentinel|transactional|AP17
INDEX|IDX19|GSI1|Idempotency|TEN#t#REPAIR#shard|DUE#at#key|sparse repair|eventual+strong takeover|AP18
MAP|AP01|IDX01
MAP|AP02|IDX02
MAP|AP03|IDX03
MAP|AP04|IDX04
MAP|AP05|IDX05
MAP|AP06|IDX06
MAP|AP07|IDX07
MAP|AP08|IDX08
MAP|AP09|IDX09
MAP|AP10|IDX10
MAP|AP11|IDX10
MAP|AP12|IDX11
MAP|AP13|IDX12
MAP|AP14|IDX13
MAP|AP15|IDX14,IDX15
MAP|AP16|IDX16,IDX17
MAP|AP17|IDX18
MAP|AP18|IDX19
LANE|L01|AP01|IDX01|2000 read/s|READ|2000|1|NA|NA|2400|NA|LOAD_TEST_REQUIRED|max-order share is not measured
LANE|L02|AP02|IDX02|1200 query/s|READ|1200|6|NA|NA|2400|NA|LOAD_TEST_REQUIRED|max-account share is not measured
LANE|L03|AP03|IDX03|400 query/s|READ|400|0.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|evaluated page and max account-status share are not measured
LANE|L04|AP04|IDX04|1500 query/s|READ|1500|5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|max-order share and fill-count mix are not measured
LANE|L05|AP05|IDX05|1000 query/s|READ|1000|6.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|max-account share is not measured
LANE|L06|AP06|IDX06|2000 query/s;top share 8%|READ|2000|5|0.08|1|2400|800.0|FEASIBLE_PLANNING|explicit top-symbol share and one-page assumption
LANE|L07|AP07|IDX07|3000 read/s|READ|3000|0.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|optional-symbol versus whole-account page mix is not measured
LANE|L08|AP08|IDX08|2000 write/s|WRITE|2000|2|NA|NA|800|NA|LOAD_TEST_REQUIRED|max-client-key lane and lifecycle mix are not measured
LANE|L09A|AP09|IDX09|5000 write/s|WRITE|5000|2|1|13|800|769.23|FEASIBLE_PLANNING|fixed consumer scope hashes eventId over versioned shards
LANE|L09B|AP09|PROTECTED_STATE_AP_REQUIRED|5000 write/s|WRITE|5000|2|NA|NA|800|NA|UNPROVEN|consumer must bind protected state to its own registered AP lane
LANE|L10|AP10|IDX10|1500 tx/s|WRITE|1500|6|NA|NA|800|NA|LOAD_TEST_REQUIRED|AMP07 three-item scenario; max-account-month share and posting-count mix are not measured
LANE|L11|AP11|IDX10|300 query/s|READ|300|1|NA|NA|2400|NA|LOAD_TEST_REQUIRED|max-account share and evaluated page bytes are not measured
LANE|L12|AP12|IDX11|2000 tx/s|WRITE|2000|2|NA|NA|800|NA|LOAD_TEST_REQUIRED|max-account-asset share is not measured
LANE|L13|AP13|IDX12|5000 write/s|WRITE|5000|1|1|7|800|714.29|FEASIBLE_PLANNING|fixed projection scope hashes sourceKey over versioned shards
LANE|L14|AP14|IDX13|20 batch/s|WRITE|20|20|NA|NA|800|NA|LOAD_TEST_REQUIRED|read-write mix and hottest tenant-date share are not measured
LANE|L15A|AP15|IDX14|200 query/s|READ|200|0.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|base-resolution and page-byte mix are not measured
LANE|L15B|AP15|IDX15|200 query/s|READ|200|0.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|status-shard count and hottest due-queue share are not measured
LANE|L16A|AP16|IDX16|create5000/s;claim5100/s;complete5000/s;retry100/s;move20/s|WRITE|40440|1|NA|NA|800|NA|LOAD_TEST_REQUIRED|base work spans event keys but max physical-key placement is not measured
LANE|L16B|AP16|IDX17|create5000/s;claim5100/s;complete5000/s;retry100/s;move20/s|WRITE|10240|1|1|13|800|787.69|FEASIBLE_PLANNING|full READY lifecycle hashes eventId over thirteen shards
LANE|L17|AP17|IDX18|2000 write/s|WRITE|2000|2|NA|NA|800|NA|LOAD_TEST_REQUIRED|max-tenant-client-order share is not measured
LANE|L18|AP18|IDX19|100 query/s|READ|100|0.5|NA|NA|2400|NA|LOAD_TEST_REQUIRED|repair shard count and hottest due-queue share are not measured
AMP|AMP01|AP01,AP02|order create|2|1|1|1|3|base+account GSI
AMP|AMP02|AP03|order status key move|2|1|2|1|4|old delete+new put;lag
AMP|AMP03|AP04,AP05,AP06|trade+two GSIs|1|1|2|1|3|three representations
AMP|AMP04|AP07|portfolio view update|1|1|0|1|1|derived storage
AMP|AMP05|AP08,AP17|request+sentinel transaction|2|2|0|1|4|two targeted base items
AMP|AMP06|AP09|inbox receipt+protected state|2|2|0|1|4|atomic receipt+effect
AMP|AMP07|AP10,AP12|two postings+authority transaction|3|2|0|1|6|immutable ledger growth
AMP|AMP08|AP11|ledger read only|0|1|0|1|0|bucket pagination/storage
AMP|AMP09|AP13|checkpoint update|1|1|0|1|1|version state
AMP|AMP10|AP14|batch metadata|1|1|0|1|1|manifest storage
AMP|AMP11|AP15|discrepancy+due GSI|1|1|1|1|2|base authority+eventual queue
AMP|AMP12|AP16|outbox create+READY insert|2|2|1|1|5|transactional base+async insert
AMP|AMP13|AP18|failed state+repair GSI|1|1|1|1|2|sparse until repaired
AMP|AMP14|AP01,AP02,AP03,AP08,AP16,AP17|accepted_order_v1 complete route|6|2|3|1|15|4 base targets+3 async GSI entries
AMP|AMP15|AP16|READY claim+index removal|2|1|1|1|3|ordinary base update+async delete
AMP|AMP16|AP16|IN_FLIGHT completion|2|1|0|1|2|ordinary base update;no index entry
AMP|AMP17|AP16|IN_FLIGHT retry+READY insert|2|1|1|1|3|ordinary base update+async insert
AMP|AMP18|AP16|READY due/shard reschedule|2|1|2|1|4|ordinary base update+index delete+put
AmplificationAP IDsScenarioRounded base unitsBase multiplierRounded GSI unitsGSI multiplierTotal unitsConsequence
AMP01AP01,AP02order create21113base+account GSI
AMP02AP03order status key move21214old delete+new put;lag
AMP03AP04,AP05,AP06trade+two GSIs11213three representations
AMP04AP07portfolio view update11011derived storage
AMP05AP08,AP17request+sentinel transaction22014two targeted base items
AMP06AP09inbox receipt+protected state22014atomic receipt+effect
AMP07AP10,AP12two postings+authority transaction32016immutable ledger growth
AMP08AP11ledger read only01010bucket pagination/storage
AMP09AP13checkpoint update11011version state
AMP10AP14batch metadata11011manifest storage
AMP11AP15discrepancy+due GSI11112base authority+eventual queue
AMP12AP16outbox create+READY insert22115transactional base+async insert
AMP13AP18failed state+repair GSI11112sparse until repaired
AMP14AP01,AP02,AP03,AP08,AP16,AP17accepted_order_v1 complete route6231154 base targets+3 async GSI entries
AMP15AP16READY claim+index removal21113ordinary base update+async delete
AMP16AP16IN_FLIGHT completion21012ordinary base update;no index entry
AMP17AP16IN_FLIGHT retry+READY insert21113ordinary base update+async insert
AMP18AP16READY due/shard reschedule21214ordinary base update+index delete+put

The lane contract below is deliberately conservative. It covers every AP and every mapped base/index route. A numeric FEASIBLE_PLANNING row has an independently recomputed rate * rounded-units * max-key-share / shards result; an unmeasured distribution remains LOAD_TEST_REQUIRED or UNPROVEN rather than borrowing table-average or adaptive-capacity headroom. NA therefore means “the interview design still needs a key histogram/load test,” not zero.

LaneAPRouteAP peak-rate contractUnit kindRate/sRounded units/opMax-key shareShardsTarget units/sLoad/shardStateDistribution evidence
L01AP01IDX012000 read/sREAD20001NANA2400NALOAD_TEST_REQUIREDmax-order share is not measured
L02AP02IDX021200 query/sREAD12006NANA2400NALOAD_TEST_REQUIREDmax-account share is not measured
L03AP03IDX03400 query/sREAD4000.5NANA2400NALOAD_TEST_REQUIREDevaluated page and max account-status share are not measured
L04AP04IDX041500 query/sREAD15005NANA2400NALOAD_TEST_REQUIREDmax-order share and fill-count mix are not measured
L05AP05IDX051000 query/sREAD10006.5NANA2400NALOAD_TEST_REQUIREDmax-account share is not measured
L06AP06IDX062000 query/s;top share 8%READ200050.0812400800.0FEASIBLE_PLANNINGexplicit top-symbol share and one-page assumption
L07AP07IDX073000 read/sREAD30000.5NANA2400NALOAD_TEST_REQUIREDoptional-symbol versus whole-account page mix is not measured
L08AP08IDX082000 write/sWRITE20002NANA800NALOAD_TEST_REQUIREDmax-client-key lane and lifecycle mix are not measured
L09AAP09IDX095000 write/sWRITE50002113800769.23FEASIBLE_PLANNINGfixed consumer scope hashes eventId over versioned shards
L09BAP09PROTECTED_STATE_AP_REQUIRED5000 write/sWRITE50002NANA800NAUNPROVENconsumer must bind protected state to its own registered AP lane
L10AP10IDX101500 tx/sWRITE15006NANA800NALOAD_TEST_REQUIREDAMP07 three-item scenario; max-account-month share and posting-count mix are not measured
L11AP11IDX10300 query/sREAD3001NANA2400NALOAD_TEST_REQUIREDmax-account share and evaluated page bytes are not measured
L12AP12IDX112000 tx/sWRITE20002NANA800NALOAD_TEST_REQUIREDmax-account-asset share is not measured
L13AP13IDX125000 write/sWRITE5000117800714.29FEASIBLE_PLANNINGfixed projection scope hashes sourceKey over versioned shards
L14AP14IDX1320 batch/sWRITE2020NANA800NALOAD_TEST_REQUIREDread-write mix and hottest tenant-date share are not measured
L15AAP15IDX14200 query/sREAD2000.5NANA2400NALOAD_TEST_REQUIREDbase-resolution and page-byte mix are not measured
L15BAP15IDX15200 query/sREAD2000.5NANA2400NALOAD_TEST_REQUIREDstatus-shard count and hottest due-queue share are not measured
L16AAP16IDX16create5000/s;claim5100/s;complete5000/s;retry100/s;move20/sWRITE404401NANA800NALOAD_TEST_REQUIREDbase work spans event keys but max physical-key placement is not measured
L16BAP16IDX17create5000/s;claim5100/s;complete5000/s;retry100/s;move20/sWRITE102401113800787.69FEASIBLE_PLANNINGfull READY lifecycle hashes eventId over thirteen shards
L17AP17IDX182000 write/sWRITE20002NANA800NALOAD_TEST_REQUIREDmax-tenant-client-order share is not measured
L18AP18IDX19100 query/sREAD1000.5NANA2400NALOAD_TEST_REQUIREDrepair shard count and hottest due-queue share are not measured

Table-boundary decision: three defensible shapes

Section titled “Table-boundary decision: three defensible shapes”

Inference: Single-table design's strongest benefit is not “fewer tables.” It is answering a heterogeneous, related access pattern in one request. The cost is that shared key/index vocabulary becomes an API among teams, and an unforeseen query may require reshaping or asynchronous projection. Start with APs and ownership, not doctrine (C81; A111, F21,F22,F33–F35, retrieved 2026-08-22).

DimensionOne mega-tableSingle table per bounded contextMultiple entity tables
Request shapeExcellent for cross-entity item collections with one ownerOne-request aggregates within Orders, Execution, or LedgerBatch/transaction or application composition across entities
Deployment couplingShared index/key changes coordinate every writerContext team coordinates only its vocabularyLowest schema coupling; more orchestration
Transaction scopeSame-table is convenient but not uniquely capableCross-context transaction is available inside the current same-account, same-Region boundarySame current cross-table boundary; more table names and IAM resources
Ownership / IAMBroad table permissions and shared stream are hard to isolateClear owner, narrow IAM, dedicated stream/alarmsClearest entity IAM; ownership can become too granular
Blast radius / scalingOne hot index, restore, or bad deploy affects all contextsContext-local capacity, hot keys, restore, and alarmsSmallest table blast radius; more fleet overhead
Backup / restoreRestoring one context means restoring a new copy of everything and extractingRestore context table and rebuild only its projectionsFine-grained restores; cross-table recovery needs a manifest/cutover
ObservabilityTable averages hide context/AP attribution unless every request is taggedAP metrics align to one service and indexesClear table metrics but many dashboards
StreamsOne mixed change feed requires type filtering and shared evolutionContext-owned CDC/outbox relayMultiple event-source mappings and checkpoints
Cognitive complexityHighest global key/index grammarModerate, cohesive grammar per domainSimple schemas; complex cross-table workflows
Best fitOne team, stable related APs, high value from mixed item collectionSeveral domain owners with rich aggregatesIndependent entities, distinct lifecycle/security/scale, relational composition elsewhere

TransactWriteItems and TransactGetItems currently accept up to 100 distinct items and 4 MB across one or more tables in the same account and Region; a write transaction cannot target the same item twice. Indexes themselves are not transaction targets. This means “transactions require one DynamoDB table” is false, although cross-Region/cross-account coordination remains outside this boundary (C83; A20,A101, retrieved 2026-08-22).

Inference: The bounded-context table is the selected shape for this case, but keep a decision record. It minimizes shared deployment/IAM/Stream/restore blast radius while preserving AP04 and AP07 item collections; use a cross-table transaction only when a truly synchronous invariant spans owned tables and its 100-item/4 MB ceiling is acceptable (C94; F21,F22).

Concurrency, transactions, uniqueness, and durable idempotency

Section titled “Concurrency, transactions, uniqueness, and durable idempotency”

Inference: Use attribute_not_exists(PK) for deterministic creation and a condition such as version = :expected AND state = :allowed for compare-and-set transitions. Return the new version as part of the command result. Optimistic locking stops a stale writer; it does not recognize that two different messages represent the same business event. An inbox receipt supplies that identity boundary (C93; A101,A110, retrieved 2026-08-22).

Inference: For AP17, transactionally condition-create TEN#t#CLIENTORDER#clientOrderId / UNIQUE with its mapped orderId and create the order. A concurrent claimant loses the condition and then reads the sentinel: same fingerprint returns the existing order, different fingerprint is a conflict. A pre-read followed by an unconditional write has a race (C93; A101,A110, retrieved 2026-08-22).

Transactions consume capacity even when canceled, and their changes propagate to GSIs, Streams, backups, and exports gradually. ClientRequestToken gives identical TransactWriteItems calls a ten-minute idempotency window; altered parameters cause a mismatch. That API feature is useful for a short retry but is not the permanent record of an accepted order (C83; A20,A101, retrieved 2026-08-22).

Inference: Store the following record, not merely a cached 201 response (C90; A20,A101, retrieved 2026-08-22; F11):

PK = TEN#<tenant>#REQ#<clientKey>, SK = REQUEST
fingerprint = SHA-256(canonical command fields + tenant + operation + schema version)
state = IN_PROGRESS | COMPLETED | REPAIR_REQUIRED
attemptOwner, leaseUntil, createdAt, updatedAt
result = {orderId, acceptedVersion, responseCode, responseDigest}
effect = {orderId, transactionId, outboxEventId}
expiresAt = cleanup time only
  1. Canonicalize the command and hash it. Conditionally create IN_PROGRESS with a short lease; never use the TTL timestamp as the lease decision.
  2. A same-key/different-fingerprint request is 409 Conflict. It must not inherit another command's result.
  3. A concurrent same-fingerprint duplicate reads strongly: COMPLETED returns the durable result; a live IN_PROGRESS returns retry guidance; an expired lease can be conditionally taken over by one owner.
  4. In one transaction, validate the lease/fingerprint, write order and uniqueness sentinel, write the semantic outbox item, and set COMPLETED with the durable response. If table boundaries make one transaction unsuitable, make the authoritative effect deterministically discoverable and move to REPAIR_REQUIRED; never pretend a partial dual write completed.
  5. The repair worker strongly rereads the record and protected effect. It completes from evidence, safely reattempts a deterministic absent effect, or escalates an ambiguous external effect. TTL may later remove a record only after the business replay/audit horizon.

Inference: AP09 applies the same principle at each consumer: target the receipt and the consumer's protected state in one TransactWriteItems call. The receipt key is CONSUMER#name#V#v#SHARD#h(businessEventId)%13 / EVENT#businessEventId; both sub-1-KiB base items therefore cost 2 * 2 = 4 WRU/event in this planning case. The receipt lane alone costs two WRU/event, or 10,000 WRU/s at 5,000 events/s; ceil(10000/(1000*0.80))=13 gives 769.23 WRU/s/shard. The protected state does not magically share that receipt distribution: its table/key must name another AP-specific lane, histogram, and capacity proof. Store source aggregate/version and effect receipt. Transport message IDs are diagnostics, not the durable business identity (C90,C87; A20,A22,A101,A105, retrieved 2026-08-22; F11,F24,F32,F33).

Do not change N in place. Here h is a contract, not a runtime hash: use the unsigned first 64 bits of SHA-256 over the canonical UTF-8 business key, and store hashVersion with shardMapVersion. A shard-map version selects the hash for each new business event; retries retain the original version. During cutover, route lookups by recorded version (or check the bounded old/new versions), stop old admission at a declared watermark, drain and reconcile both maps, and retain old receipts through the deduplication horizon. The cost is version metadata, dual-version reads during cutover, and operational reconciliation; the benefit is a deterministic capacity argument rather than a hope that opaque split-for-heat/adaptive behavior will hold the 80% target.

Money, ledger authority, projections, and reconciliation

Section titled “Money, ledger authority, projections, and reconciliation”

The application currently moves JavaScript number values through order, trade, and portfolio paths. Authoritative financial amounts must not use binary floating point. Choose one representation per field:

  • fixed minor units as an integer plus ISO currency and explicit scale; or
  • DynamoDB Number serialized/deserialized with an exact decimal library, never through a binary-float intermediate.

Define an explicit rounding policy: rounding mode, rounding point, precision, fee/tax allocation, currency conversion rate identity, and residual handling in the contract. “Two decimal places” is not enough for instruments, quantities, FX, or currencies with different scales (C47; A41, F08,F17, retrieved 2026-08-22).

Inference: A ledger transaction uses one deterministic txnId; immutable posting rows carry account, currency, signed exact amount, effective/recorded times, source business ID, and posting line. Validate that debits and credits balance by currency before a transaction writes all postings and conditionally updates the versioned AP12 AUTH#CASH#currency or AUTH#SEC#symbol authority/reservations. DynamoDB supplies conditional/transactional storage; the application supplies chart-of-accounts, balancing, authorization, immutability, rounding, and reversal semantics (C91; F08,F17,F21).

Never update a posting. Correct an error with a linked reversing/correcting transaction. A current balance is a compact authority only when its version and control total are updated with postings; a portfolio, P&L, OpenSearch document, or cache remains derived. Reservation state distinguishes posted, reserved, and available amounts so two commands cannot spend one balance.

Inference: AP13 projection records enforce source version n = current+1. n <= current is a duplicate/stale no-op; n > current+1 records a gap and parks the update. Reconciliation compares source order/fill IDs, ledger posting IDs, balances, and projection versions for a declared window, emits AP15 discrepancies, and requires evidence before a conditional resolution. This is the correctness backstop; DynamoDB alone does not supply accounting semantics (C91; F08,F17,F21).

Inference: The checkpoint PK is PROJ#name#V#v#SHARD#h(sourceKey)%7 / SOURCE#sourceKey. At 5,000 ordinary sub-1-KiB conditional writes/s, N=ceil(5000/(1000*0.80))=7, or 714.29 WRU/s/shard. Hashing the stable sourceKey preserves next-version ordering for that source; it deliberately does not promise one total order across unrelated sources. Whole-projection scans/listing now fan out seven keyed queries and merge source watermarks. Reshard with the same versioned map, admission watermark, drain, gap/control-total reconciliation, and conditional cutover used for AP09; retries must not silently switch versions (C87,C95; A22,A100,A105, retrieved 2026-08-22; F24,F32,F33).

DynamoDB Streams and semantic outbox events

Section titled “DynamoDB Streams and semantic outbox events”

The financial transaction has established what is true locally. The next boundary is telling other services about that committed result. Raw item changes may be enough for some consumers; when consumers need one stable business fact from a multi-item transaction, the outbox supplies that explicit envelope. Follow its full lifecycle, because claim, retry, completion, and index movement all add work.

Inference: Treat Streams as short-lived CDC. Current retention is 24 hours; ordering covers mutations to each individual item primary key, not every item in a partition-key collection or a business transaction. View choices are KEYS_ONLY, NEW_IMAGE, OLD_IMAGE, and NEW_AND_OLD_IMAGES; choose the smallest view that still supports repair; NEW_AND_OLD_IMAGES supplies old and new images. Lambda delivery is at-least-once and may process a record repeatedly (C84; A21,A102, retrieved 2026-08-22).

Transaction item changes can arrive at different times and interleave with other changes. A consumer therefore must not infer one business event by grouping nearby order/sentinel/idempotency records. NEW_AND_OLD_IMAGES helps derive transitions but increases record size and still does not supply a semantic envelope (C83; A101, retrieved 2026-08-22).

Inference: AP16 writes one explicit outbox event item in the same local transaction as the accepted state. It contains stable eventId, aggregate ID and version, event type/schema version, occurred time, trace/causation IDs, and the consumer contract payload. Its exact state machine is:

  1. ABSENT -> READY: the transaction creates the base item with readyPk, readySk=DUE#dueAt#eventId, attempt zero, and no lease; the sparse GSI gets one insert.
  2. READY -> IN_FLIGHT: a conditional claim checks state/version and an absent or expired lease, sets owner/lease/attempt, and removes both READY key attributes; the GSI gets one delete.
  3. IN_FLIGHT -> COMPLETED: only the lease owner conditionally stores the durable broker acknowledgement and completion time; READY attributes are already absent, so the GSI has no action.
  4. IN_FLIGHT -> READY: a failed publish or expired-lease repair conditionally clears owner/lease, records the failure, chooses a new dueAt, and restores READY attributes; the GSI gets one insert.
  5. READY -> READY: a deliberate due/shard reschedule conditionally changes an indexed key, so GSI maintenance is one old-key delete plus one new-key put.

Inference: Every stale/repeated transition condition-fails and reads the durable state; an ambiguous broker acknowledgement can therefore repeat publication, and consumers still use AP09. This repairs the dual-write gap without claiming end-to-end exactly once. The current GSI accounting for a sub-1-KiB entry is one put when indexed attributes appear, one delete when they disappear, and delete+put when an indexed key changes (C84,C95; A21,A102,A104, retrieved 2026-08-22).

Checkpointing within the 24-hour window supports ordinary retry, not indefinite rebuild. A projection that falls behind retention needs a PITR-backed export or another versioned full source, followed by catch-up and a measured cutover. Keep unpublished outbox items longer than the maximum outage/replay policy; the Stream is not the durable event archive.

Capacity, skew, and auditable amplification

Section titled “Capacity, skew, and auditable amplification”

The full formulas and mutation-tested inputs are in the shared cost model. Current rounding is API-specific: standard writes round each item to 1 KiB; standard strong reads round evaluated bytes to 4 KiB, eventual reads use half, and each transaction-targeted base-item write uses two underlying write operations. Indexes are not transaction targets; asynchronous GSI maintenance adds ordinary index write units after commit. Query consumption is based on evaluated bytes before filtering; BatchGetItem rounds each item separately (C82,C83; A100,A101,A104, retrieved 2026-08-22).

Result IDResultConsequence
standard_write_units21.2KiB crosses two 1KiB buckets
base_plus_index_units3base2+ordinary GSI1
moved_index_units4base2+old delete1+new put1
strong_read_units310KiB/4KiB rounded
eventual_read_units1.5half standard strong
transactional_read_units6two underlying reads
query_eventual_units324,000B evaluated before filter
batch_eventual_units1.5each item rounds separately
accepted_order_v1_base_txn_units12four targeted base items
accepted_order_v1_gsi_units3two order GSIs+READY GSI ordinary cost
accepted_order_v1_total_units1512 base transaction+3 async GSI
ap06_page_kib40one 100x0.4KiB page/request
ap06_eventual_rru_per_page5half of ten 4KiB chunks
ap06_aggregate_rru_s100002000 requests/s x5
ap06_top_symbol_rru_s800planning top share 8%
ap06_shards1ceil(800/(3000x0.80))
ap09_atomic_path_wru_per_event4two transaction-targeted <=1KiB base items x2
ap09_receipt_wru_per_event2receipt item alone uses transaction multiplier
ap09_receipt_aggregate_wru_s100005000 receipt writes/s x2
ap09_receipt_shards13ceil(10000/(1000x0.80))
ap09_receipt_per_shard_wru_s769.2310000/13
ap09_receipt_headroom_percent3.85below 800 WCU/s target
ap13_checkpoint_wru_per_event1ordinary conditional <=1KiB write
ap13_checkpoint_aggregate_wru_s50005000 checkpoint writes/s x1
ap13_checkpoint_shards7ceil(5000/(1000x0.80))
ap13_checkpoint_per_shard_wru_s714.295000/7
ap13_checkpoint_headroom_percent10.71below 800 WCU/s target
ap16_create_base_wru_s200005000xceil(1.6KiB)x2 transaction ops
ap16_claim_base_wru_s102005100xceil(1.6KiB) ordinary update
ap16_complete_base_wru_s100005000xceil(1.6KiB) ordinary update
ap16_retry_base_wru_s200100xceil(1.6KiB) ordinary update
ap16_reschedule_base_wru_s4020xceil(1.6KiB) ordinary update
ap16_base_total_wru_s40440create+claim+complete+retry+reschedule
ap16_ready_create_insert_wru_s50005000 READY inserts x1
ap16_ready_claim_delete_wru_s51005100 READY removals x1
ap16_ready_retry_insert_wru_s100100 retry READY inserts x1
ap16_ready_reschedule_move_wru_s4020 READY key moves x(delete+put)
ap16_no_retry_move_floor_index_wru_s100005000 create inserts+5000 claim deletes
ap16_ready_index_wru_s10240all sparse-index lifecycle actions
ap16_ready_shards13ceil(10240/(1000x0.80))
ap16_per_shard_wru_s787.6910240/13
ap16_headroom_percent1.54below 800 WCU/s target
ap16_total_lifecycle_wru_s50680base40440+READY index10240
ledger_month_kib12000002m postings x0.6KiB
ledger_sub_buckets8count and byte ceilings agree
ledger_bucket_max_mib146.48150000KiB/1024

Inference: The named accepted_order_v1 route includes the order, idempotency result, outbox event, and AP17 sentinel as four base transaction targets. Rounded base units are 2+1+2+1=6; two operations/item make 12. The order account/status GSIs and AP16 READY GSI add 1+1+1=3 ordinary units after commit, totaling 15. Canceled transactions can still consume capacity, so conditional-conflict load belongs in the peak model (C83,C95; A100,A101,A104, retrieved 2026-08-22).

Inference: Current on-demand tables start warm at 12,000 read units/s and 4,000 write units/s. An individual physical partition remains bounded at 3,000 read units/s and 1,000 write units/s. These are dated service dimensions, not a promise that one partition key receives the whole table's warm throughput (C87; A22,A105, retrieved 2026-08-22).

ChoiceUse whenBoundary to test
On-demanduncertain/spiky traffic and willingness to pay its request shapeprior peak/warm throughput, sudden step, hot key, account/table quotas
Provisionedpredictable rate, reserved headroom, explicit cost/controlforecast error, target utilization, GSI capacity, scale-out delay
Autoscalinggradual provisioned changesCloudWatch/control-loop delay; not admission control
Warm throughputknown launch/failover rate above current warm valuepre-warm lead time and distribution; cannot cure one hot key
Burst/adaptive capacitytransient uneven demand with spare capacityfinite credits/partition mechanics; do not encode as guaranteed hot-key budget

Inference: The lane table above is the decision surface: twenty-one physical-route rows cover AP01–AP18. Four rows have sufficient planning inputs for numeric feasibility (AP06, AP09 receipt, AP13 checkpoint, and AP16 READY); every other route remains visibly LOAD_TEST_REQUIRED or UNPROVEN. A table can split an item collection when current mechanics permit, but placement and timing are service-managed. With no LSI proposed here, that behavior may help observed traffic; it is still not the deterministic proof for an explicit 80% lane target. Warm, burst, and adaptive capacity likewise do not replace the per-route histogram and load test (C87; A22,A105, retrieved 2026-08-22; F24,F32,F33).

Inference: Instrument ConsumedReadCapacityUnits, ConsumedWriteCapacityUnits, throttled requests/reasons, latency, conditional failures, transaction conflicts, GSI lag, item size, and contributor/key skew by AP. Table averages cannot prove AP06's hottest symbol or AP12's hottest account is healthy (C87; A22,A105, retrieved 2026-08-22).

Inference: AP06's explicit planning case is one 100-item page/request at 0.4 KiB/item. Five eventual read units/query times 2,000 queries/s is 10,000 units/s aggregate; an 8% top symbol is 800 units/s. With a 2,400-unit/s target, ceil(800/2400)=1, so IDX06 stays unsharded. If measured top-symbol demand exceeds the target, write sharding changes PK=SYM#X into PK=SYM#X#SHARD#h(eventId)%N. That distributes writes but AP06 must fan out N Queries, merge-sort, deduplicate, paginate a compound cursor, and surrender one-partition total order. Record the shard version in items and perform an ordered cutover. Prefer a naturally high-cardinality account/order key when it already meets rate and order requirements (C87; A22,A105, retrieved 2026-08-22; F24,F32,F33).

Inference: AP16 hashes eventId over thirteen READY shards for a balanced steady planning lifecycle: 5,000 creates/s enter READY; 5,100 claims/s remove 5,000 new plus 100 retried items; 5,000 items complete; 100 fail or expire back to READY; and 20 already-READY items/s move due/shard keys. At 0.45 KiB/index entry, the no-retry/no-move floor is 5,000 inserts + 5,000 deletes = 10,000 index units/s. Retry circulation adds 100 inserts and 100 claim-deletes; rescheduling adds 20 deletes + 20 puts, totaling 10,240. Thus N=ceil(10240/(1000*0.80))=13, 787.69 units/s/shard, and 1.54% headroom below the 800-unit target. Base work remains separate: create 20,000, claim 10,200, complete 10,000, retry 200, and reschedule 40 units/s, for 40,440 base and 50,680 base+index units/s. dueAt is monotonic only inside each shard; poll all thirteen equality keys, merge by (dueAt,eventId), and carry one LEK per shard in the cursor. Recompute N before any measured rate/mix step (C87,C95; A100,A104,A105, retrieved 2026-08-22).

Inference: AP10/AP11 impose a hard 2,000,000-posting/account/month admission limit. At 0.6 KiB, that is 1,200,000 KiB. A deterministic posting-sequence bucket rolls at 250,000 postings or 150,000 KiB, whichever comes first, so the example uses eight buckets of at most 146.48 MiB. AP11 merge-paginates them with one LEK/bucket; crossing the monthly cap rejects/escalates instead of silently growing the key (C87,C95; A100,A104,A105, retrieved 2026-08-22).

A usable key design must also survive pagination, expiry, rebuild, and regional failure. These operations have different meanings: a continuation key advances a read, TTL cleans up old data, an export supplies a recovery dataset, and replication changes the regional consistency contract. None can stand in for a complete, reconciled business snapshot.

Inference: A Query requires partition-key equality and may narrow the sort key. Its filter runs after evaluation. Continue while LastEvaluatedKey is present; empty returned items plus a continuation key is possible after filtering. A Scan reads broad table/index data and also paginates. Neither ProjectionExpression nor Select=COUNT turns a broad read into a cheap keyed read (C81,C96; A111, retrieved 2026-08-22; F34).

Inference: Online APIs use AP keys, never a table Scan. Bulk reconciliation uses a PITR export with an immutable manifest; an emergency paginated Scan has bounded parallelism, a captured checkpoint/window, throttling protection, and restart state. This directly avoids the repository's single-page/in-memory snapshot failure (C96; A106,A111, retrieved 2026-08-22).

Inference: TTL expiry is cleanup only and is asynchronous, typically within a few days. An expired item can remain readable and billable until deletion; use leaseUntil and a condition against current time for takeover/authorization, not item absence. TTL deletions enter the originating Region's Stream as service deletes; MREC replicas consume replicated writes and cannot identify the replicated delete the same way. MRSC does not support TTL (C85; A23,A103,A107, retrieved 2026-08-22).

Backup, export, restore, and projection rebuild

Section titled “Backup, export, restore, and projection rebuild”

Inference: PITR currently retains a configurable 1–35 days at per-second granularity and restores to a new table, with the latest restorable time approximately five minutes behind. Export to S3 is asynchronous, uses the PITR data plane, and does not consume RCUs or affect the table's performance. Full and incremental exports are available; an incremental range is a compacted final-state view and one transaction can be split across adjacent exports (C88; A106, retrieved 2026-08-22).

Inference: A recovery runbook therefore: (1) declares the source timestamp and business freeze/cutover policy; (2) restores or exports to a new named dataset; (3) validates counts, control totals, schema and projection version; (4) rebuilds a new projection namespace; (5) catches up changes with stable event/version IDs; (6) proves zero gaps/duplicates against reconciliation; and (7) atomically changes the reader alias/config. Never overwrite the old projection before proof. Tags, IAM, alarms, Streams, TTL, autoscaling, and application configuration require explicit restore checks (C88,C96; A102,A106, retrieved 2026-08-22).

Global Tables: make the consistency mode explicit

Section titled “Global Tables: make the consistency mode explicit”
BoundaryMRECMRSC
Default / availabilityCurrent default; replicas in supported DynamoDB Regions (A107, retrieved 2026-08-22)Introduced 2025; supported Region sets only (A107, retrieved 2026-08-22)
TopologyMultiple replicas (A107, retrieved 2026-08-22)Exactly three Regions: three replicas or two replicas + witness (A107, retrieved 2026-08-22)
Replication/readAsynchronous; monitor ReplicationLatency (A107, retrieved 2026-08-22)Synchronous quorum; cross-Region strong reads, zero RPO; higher latency (A107, retrieved 2026-08-22)
TransactionsAtomic only in source Region; replicas can temporarily observe a partial transaction (A107, retrieved 2026-08-22)Transaction APIs unsupported (A107, retrieved 2026-08-22)
TTL / LSITTL supported with replicated-delete cost (A107, retrieved 2026-08-22)TTL and LSI unsupported (A107, retrieved 2026-08-22)
StreamsReplication uses Streams; per-item order and replica records can differ (A107, retrieved 2026-08-22)Not enabled by default; if enabled replica records/order are identical (A107, retrieved 2026-08-22)
Change modeCannot change consistency mode after creation (A107, retrieved 2026-08-22)Cannot change consistency mode after creation (A107, retrieved 2026-08-22)

Inference: For authoritative balances, multi-active MREC writes can race and last-writer convergence is not an accounting conflict policy. Prefer a home Region/single-writer ownership with idempotent failover and reconciliation, or use MRSC only after accepting its topology, latency, feature, transaction, and external-effect boundaries. MRSC zero RPO for table data does not make a broker, bank API, exchange acknowledgement, or customer notification atomic. Detect conflicts/errors, preserve request/event identity, and reconcile every external effect (C89; A24,A107, retrieved 2026-08-22).

DAX, ElastiCache, Aurora, and OpenSearch by access pattern

Section titled “DAX, ElastiCache, Aurora, and OpenSearch by access pattern”

Inference: These are complements or alternatives chosen by a concrete AP; none changes which system owns a monetary invariant (C92; A32–A35,A108,A109,A112, retrieved 2026-08-22).

Candidate and APQuery / transaction shapeConsistency and invalidationOperational loadSource-of-truth boundary
DAX for repeated AP01 history readsDynamoDB-compatible item reads; not arbitrary searchEventually consistent reads cache; strong and transactional reads pass through. Cached Query/Scan results are not invalidated by item writes, so accept TTL staleness explicitly. (A108, retrieved 2026-08-22)Cluster sizing, subnet/security, hit/miss/eviction and fallbackNever AP12 authority or AP04 transition decision
ElastiCache for computed session/market reference dataApplication-defined keys, structures, atomic cache operationsDefine cache-aside/read-through, TTL, invalidation message loss, stampede, and source fallback. (A34,A109, retrieved 2026-08-22)Nodes/serverless capacity, failover, memory/eviction, client behaviorCache disposable; DynamoDB/ledger or market source remains authoritative
Aurora PostgreSQL for ledger/reporting with evolving relationsPostgreSQL-compatible SQL and ACID transactions; Data API exposes begin/commit/rollback operations (A112, retrieved 2026-08-22)Isolation/endpoint mode must be selected and tested; local write forwarding supports documented isolation levels but not SERIALIZABLE; replica freshness is separate (A35,A112, retrieved 2026-08-22)Schema/index tuning, connections, failover, engine maintenanceInference: Candidate ledger authority only if its accounting invariants and operating model are explicitly implemented (C92; A112, retrieved 2026-08-22)
OpenSearch for AP05/AP06/AP15 discoveryFull-text, relevance, aggregations, flexible filtersAsync index with refresh/ingestion lag, duplicates and mapping evolution; rebuildable. (A32, retrieved 2026-08-22)Domain/shard sizing, mappings, ingestion DLQ, rollover, snapshotSearch is a locator/projection; strong-read authority before action

DAX is a poor response to the repository's trades-reader: the query is a GSI history path, freshness matters, and cache invalidation is not established. Measure reuse and acceptable staleness before paying cluster cost. ElastiCache offers more flexible structures but more application-owned coherence. Aurora is preferable when APs are genuinely relational/ad hoc and transaction constraints dominate key-value scale. OpenSearch is preferable for search and aggregations that would otherwise create proliferating GSIs—but only as a rebuildable projection.

This is a repair design against the canonical evidence, not a second audit. All locators and exact observations remain under CS01–CS12 in the repository evidence map.

IDDynamoDB-relevant repairProof / residual boundary
CS01Commit order, fingerprinted AP08 result, AP17 sentinel, and AP16 outbox item in one transaction.Prove no accepted order lacks outbox; relay/consumer still repeat.
CS02Replace cached 201 with durable IN_PROGRESS/COMPLETED result, fingerprint mismatch rejection, lease, and repair state.TTL is cleanup; ambiguous external effects still require evidence.
CS03Persist relay attempt and broker response per outbox ID; inspect every PutEvents entry and reconcile target effects.Broker acknowledgement is not downstream completion.
CS04Atomically write fill, conditionally advance order version/remaining quantity, and write semantic trade outbox item.Cross-boundary ledger/clearing effects need inbox/outbox/reconciliation.
CS05Retry discovers deterministic fill/outbox records and resumes publication; duplicate guard returns an effect receipt.Never delete repair evidence merely because publish later succeeds.
CS06AP09 inbox event ID plus AP13 source version accompany the conditional AP07 portfolio projection update.Version stops stale order; inbox stops duplicate identity; only AP12 authority may authorize cash/securities/risk.
CS07Accept only next aggregate version, expose gaps, park later events, and rebuild from full source.EventBridge provides routing, not per-account causal order.
CS08Keep EventBridge target-DLQ policy and failed-DLQ-send metrics as separate transport controls.DynamoDB repair records do not grant SQS policy or replace DLQ runbooks.
CS09Replace one-page Scan with PITR export, manifest/control totals, versioned rebuild, catch-up, and cutover.Export is async and not an atomic business transaction snapshot.
CS10Store fixed minor units or exact decimals with currency, scale, and explicit rounding.Validate serialization end to end; no binary-float intermediate.
CS11Add immutable balanced postings, versioned balances/reservations, AP14/AP15 reconciliation, and projections.DynamoDB primitives do not invent accounting semantics.
CS12Keep matching/sequencing on an evidenced runtime; use DynamoDB for durable orders, results, ledger, and projections.Durability does not establish deterministic microsecond matching.
  • A latency-critical central limit order book requiring deterministic global priority and one sequenced matching loop. DynamoDB can persist surrounding state; its partitioned request model is not the matching algorithm.
  • Unbounded ad-hoc joins, constantly changing predicates, and exploratory analytics. Export to S3/Athena or use Aurora/OpenSearch according to the AP.
  • Long-retention event sourcing from DynamoDB Streams. Retention is 24 hours; store an authoritative event sequence explicitly if that is the model.
  • Cross-Region multi-item financial transactions with arbitrary external effects. Current MREC/MRSC boundaries do not supply that atomicity.
  • One hot monotonically addressed key whose required write rate exceeds one partition and whose total order cannot be relaxed. Sharding changes the order contract; capacity mode does not repeal it.
Local-note myth or tempting shorthandCorrection
“Use a single table for DynamoDB.”Inference: Start with APs. One table helps when a related heterogeneous collection answers them in one request; ownership/new-query/analytics trade-offs can justify other boundaries (C81; A111, F21,F22,F33–F35, retrieved 2026-08-22).
“Transactions lock items and are about 2–5 ms / 25 tx/s per item.”Do not invent lock/latency/per-item throughput guarantees. Use the documented 100-item, 4 MB, same-account/Region scope and load-test the real shape (C83; A20,A101, retrieved 2026-08-22).
ClientRequestToken gives business idempotency.”It is a ten-minute identical-call window. AP08 persists fingerprint, state, lease, effect and result (C83; A20,A101, retrieved 2026-08-22).
“Strong reads cost 2×.”Standard strong is one 4 KiB unit; eventual is half; transactional strong is twice standard (C82; A19,A100, retrieved 2026-08-22).
“A GSI can give current status if I request strong consistency.”GSIs are eventual-only. Return to the base table/LSI for a strong decision (C82; A19,A100, retrieved 2026-08-22).
“A filter makes a Query cheap.”Inference: Filtering occurs after evaluated read work. Put selectivity in keys (C81; A111, F34, retrieved 2026-08-22).
“Streams delivers every change exactly once and in table order.”Inference: It is 24-hour CDC with per-item order; Lambda is at least once and repeats (C84; A21,A102, retrieved 2026-08-22).
“A transaction appears as one event in Streams.”Item changes may interleave. Write one semantic outbox item in the transaction (C83; A101, retrieved 2026-08-22).
“TTL deletes within 48 hours, so it enforces expiry.”Inference: Current wording is typically within a few days; conditions enforce expiry/lease, TTL only cleans up (C85; A23,A103, retrieved 2026-08-22).
“On-demand fixes hot keys.”Inference: Warm/prior-peak and physical-partition limits remain; one partition is 3,000 read units/s and 1,000 write units/s (C87; A22,A105, retrieved 2026-08-22).
“DAX invalidates all queries on write.”Inference: Strong/transaction reads pass through; cached Query/Scan results are not invalidated by item writes (C92; A108, retrieved 2026-08-22).
“Global Tables are always eventual.”Inference: MREC is default; MRSC now provides cross-Region strong reads/zero RPO under strict limits (C89; A24,A107, retrieved 2026-08-22).
“A mutable balance row is a ledger.”Inference: A ledger needs exact amounts, immutable balanced postings, authority, reversals, versions and reconciliation (C91; F08,F17,F21).
DecisionChooseReject / escalate whenEvidence before production
Table boundaryBounded-context tables hereCross-context AP misses latency/transaction budgetAP trace, IAM/restore/stream owner, load test
Base keyNatural high-cardinality tenant + order/accountHot-key percentile breaches partition boundarykey histogram and per-AP consumed capacity
GSIOnly IDX02/03/05/06/14/15/17AP needs strong read or amplification lacks budgetbytes, lag, throttle and rebuild test
LSINone hereStrong alternate order within bounded <10 GB collection is provengrowth proof and creation-time decision
IdempotencyFingerprinted durable state/result + inboxExternal effect cannot be observed/reconciledconcurrency/timeout/lease/repair game day
TransactionOne invariant, <=100 items/4 MB, same account/RegionMRSC/cross-Region/account/external API requiredconflict load, capacity, cancellation evidence
Money/ledgerExact amounts + immutable balanced postingsRounding/reversal/authority undefinedinvariant tests and reconciliation
StreamsCDC/outbox within 24-hour recoveryLong replay/event sourcing/transaction envelope requiredrepeat/gap/outage exercise
CapacityOn-demand uncertain; provisioned stable measured loadone hot key or untested step growthpeak/skew/item/index/unit model
GlobalRegional/home-Region MREC; MRSC for stated needfeature/latency/topology limits failfailover/conflict/reconciliation game day
Cache/searchOnly stale-tolerant derived APused to authorize financial commandinvalidation/lag/fallback/rebuild proof
RecoveryPITR/export → new version → validate → catch up → cut overno manifest/control totals/rollbacktimed restore and reconciliation

Rubric: Name operation, predicates, order, consistency, size/rate, owner, invariant and failure response; every key/index must trace back.

Rubric: One request over heterogeneous related items; then discuss stable APs, ownership, analytics, new-query friction and recovery coupling.

Rubric: Align ownership/blast radius while preserving local item collections; acknowledge cross-table transactions and trade-offs.

4. Can a GSI satisfy a strongly current balance read?

Section titled “4. Can a GSI satisfy a strongly current balance read?”

Rubric: No; GSI is eventual-only. Use base/LSI strong read or transaction, and name lag/fallback behavior.

5. What is the current transaction boundary?

Section titled “5. What is the current transaction boundary?”

Rubric: Up to 100 distinct items/4 MB, one or more tables, same account and Region; no two write actions on one item; not indexes/external effects.

6. Why is ClientRequestToken insufficient?

Section titled “6. Why is ClientRequestToken insufficient?”

Rubric: Ten-minute API window versus durable fingerprinted business record/result, concurrent duplicates, leases, cleanup and repair.

Rubric: Fingerprint, conditional IN_PROGRESS, owner/lease, protected effect + COMPLETED, durable result, evidence-based takeover.

8. Does optimistic locking deduplicate events?

Section titled “8. Does optimistic locking deduplicate events?”

Rubric: No; version enforces order. Inbox identity deduplicates. Explain duplicate, stale, next, and gap cases.

9. How do you enforce a unique client order ID?

Section titled “9. How do you enforce a unique client order ID?”

Rubric: Sentinel plus entity in one conditioned transaction; on collision read mapping and compare fingerprint, never check-then-put.

Rubric: Fixed minor units or exact Decimal/Number, currency/scale, rounding, precision, conversion and residual policy; no binary float.

Rubric: Immutable balanced postings, deterministic IDs, versioned balances/reservations, reversals, exact amounts and reconciliation.

12. What order does DynamoDB Streams provide?

Section titled “12. What order does DynamoDB Streams provide?”

Rubric: Per individual item primary key, 24-hour retention; Lambda at least once. Not collection/global/business-transaction order.

Rubric: Transaction items can interleave; outbox supplies one semantic envelope atomically with state. Relay and consumers still deduplicate.

Rubric: Round four base targets, then 2*(2+1+2+1)=12; add three ordinary asynchronous GSI writes for 15. Never double index entries.

15. Why can a selective filter be expensive?

Section titled “15. Why can a selective filter be expensive?”

Rubric: Read work precedes filter. Move selectivity into keys and continue LastEvaluatedKey even after an empty filtered page.

Rubric: No. Separate warm/prior-peak behavior from the physical-partition 3,000 read-unit/1,000 write-unit boundary; measure skew.

Rubric: MREC default/async/conflicts/source-Region transaction; MRSC three-Region quorum/strong/zero RPO/higher latency/no TTL-LSI-tx; external effects remain separate.

18. How do you recover a projection after 30 hours?

Section titled “18. How do you recover a projection after 30 hours?”

Rubric: Streams expired. Use PITR/export manifest and versioned namespace, catch-up with IDs/versions, prove gaps/control totals, then cut over.

You should be able to trace an access pattern to its base or index route, explain why a projection cannot authorize money, and account for the accepted-order transaction without doubling asynchronous GSI work. Retain the distinction between a receipt's distribution and its protected state. Next, use these local guarantees to reason about CQRS, event sourcing, outbox, and sagas.

Reading layout adapted from SSE reading notes by Mohammed Balila, MIT. Source manifest · Attribution