compliance
Change & Audit Log
An append-only history beside the current state it explains.
Every change to a resource is written as an immutable event, and the resource's current state lives in the same partition with a version number. One Query returns the state and the history that produced it.
The model
CurrentState
What the resource looks like now, and which version that is.
- pk
- RESOURCE#<resourceId>
- sk
- CURRENT
Attributes: status (S), version (N), updatedAt (N)
ChangeEvent
One immutable record of a change, numbered in sequence.
- pk
- RESOURCE#<resourceId>
- sk
- EVENT#<sequence>
Attributes: action (S), actor (S), at (N)
Access patterns
- QueryRead a resource and its history
The current state and every event that led to it.
- UpdateItemApply a change
Update the current state, only if nobody else has since you read it.
- GetItemRead the current state
Just the resource as it stands, without its history.
Design notes
CURRENT sorts before every EVENTwhy
The sort key labels put the current state at the head of the partition, ahead of the log. So a Query that stops after one row is a cheap read of the present, while the same Query run out returns the whole history. One key design, two very different reads.
The version number is the lockwhy
An update carries the version it read and asks DynamoDB to apply the change only if version still matches. Two reviewers acting on version 3 both send the same condition; the first wins and moves it to 4, the second is refused and has to re-read. No row is locked and nothing waits - the loser simply finds out.
The state and its event are one write, or neithertrade-off
Advancing CURRENT and appending its EVENT# are two writes, and a crash between them leaves a resource whose state no event explains - which is the one thing an audit trail exists to prevent. Production binds them in a single TransactWriteItems: the guarded update and the conditional append succeed together or not at all. The access pattern here shows only the guarded update, because that is the half this format can express.
Applying a change is a design here, not a live demonstrationtrade-off
The preview console cannot run the guarded update: the resolver templates writes but does not emit them as runnable, so there is no button here that races two reviewers. The engine itself does support the mechanism, so this is a limit of what the page can show rather than of what DynamoDB does.
Events are numbered, not timestamped, for orderingwhy
at records when a change happened, but EVENT#000001 is what orders the log. Two changes in the same millisecond collide on a timestamp key and one silently overwrites the other; a sequence removes that. It does not remove contention on its own - two writers can still reach for the same number - so the number comes from the version the guarded update just bumped, and the event is written with attribute_not_exists on its sort key so a second claimant is refused rather than overwriting. The padding matters as much as the number, since sort keys compare as strings and EVENT#10 sorts before EVENT#2 without it.
Taught in the course
- One query, a whole collection - Items that share a partition key are read together in one Query.
- No silent clobbers - A version check lets an update land only if nobody changed the item since you read it.
The current state and every event that led to it.
Run an operation to see the raw engine response.
The in-browser engine is a preview build. Transactions, vector search, streams, tags and TTL are among the operations it doesn't implement yet.