@@ -27,8 +27,23 @@ AWS-native backups and portable exports.
2727Before any restore, make sure both layers are active:
2828
29291 . ** DynamoDB PITR** - point-in-time recovery is enabled on all durable
30- execution tables (tasks, cards, templates, users, files, notifications).
31- This protects against accidental deletes and bad updates.
30+ execution tables:
31+
32+ - ` <stack>-tasks `
33+ - ` <stack>-cards `
34+ - ` <stack>-templates `
35+ - ` <stack>-users `
36+ - ` <stack>-files `
37+ - ` <stack>-artifacts `
38+ - ` <stack>-assistant-jobs `
39+ - ` <stack>-audit-events `
40+ - ` <stack>-intake `
41+ - ` <stack>-notifications `
42+ - ` <stack>-conversational-state `
43+
44+ This protects against accidental deletes and bad updates. Ephemeral session
45+ state is excluded. Separately governed bookkeeping, sponsor-CRM, calendar,
46+ and newsletter-slot domains are outside the portable execution boundary.
32472 . ** Portable export archive** - an application-level JSONL snapshot bundled as
3348 a retained offsite archive that does not depend on DynamoDB internals. This
3449 is the migration path to Postgres or another store.
@@ -40,19 +55,32 @@ scripts, or risky releases:
4055
4156``` bash
4257aws dynamodb create-backup \
43- --table-name dataops-v1 -tasks \
44- --backup-name dataops-v1 -tasks-pre-migration-$( date +%Y%m%d%H%M%S)
58+ --table-name < stack > -tasks \
59+ --backup-name < stack > -tasks-pre-migration-$( date +%Y%m%d%H%M%S)
4560```
4661
47- Repeat for each durable table: ` cards ` , ` templates ` , ` users ` , ` files ` ,
48- ` notifications ` . Tag or name backups with the environment, date, and reason.
62+ Repeat for each durable execution table:
63+
64+ - ` <stack>-tasks `
65+ - ` <stack>-cards `
66+ - ` <stack>-templates `
67+ - ` <stack>-users `
68+ - ` <stack>-files `
69+ - ` <stack>-artifacts `
70+ - ` <stack>-assistant-jobs `
71+ - ` <stack>-audit-events `
72+ - ` <stack>-intake `
73+ - ` <stack>-notifications `
74+ - ` <stack>-conversational-state `
75+
76+ Tag or name backups with the environment, date, and reason.
4977
5078## Portable Export
5179
5280Create a portable export:
5381
5482``` bash
55- npm --prefix work-engine run export:data -- .tmp/exports/dataops-export
83+ npm --prefix backend run export:data -- .tmp/exports/dataops-export
5684```
5785
5886Or trigger the scheduled export route:
@@ -73,14 +101,30 @@ cards.jsonl
73101templates.jsonl
74102recurring_configs.jsonl
75103files.jsonl
76- notifications.jsonl
77104artifacts.jsonl
78105assistant_jobs.jsonl
79106audit_events.jsonl
107+ intake_items.jsonl
108+ notifications.jsonl
109+ identity_bindings.jsonl
110+ identity_binding_audits.jsonl
111+ conversations.jsonl
112+ channel_bindings.jsonl
113+ conversation_events.jsonl
114+ summary_checkpoints.jsonl
115+ plugin_drafts.jsonl
116+ proposal_versions.jsonl
117+ proposal_presentations.jsonl
118+ execution_attempts.jsonl
119+ conversation_audit_events.jsonl
120+ result_notifications.jsonl
121+ conversational_private_payloads.jsonl
80122```
81123
82- Password hashes and session tokens are redacted. File binaries are excluded;
83- only metadata is exported.
124+ All 24 JSONL families are required even when a snapshot contains zero records,
125+ so an empty JSONL file is valid. Password hashes and session tokens are redacted.
126+ The portable export excludes file and artifact binaries; it contains metadata
127+ only.
84128
85129Offsite archives are gzip-compressed tar files stored under:
86130
@@ -89,7 +133,7 @@ Offsite archives are gzip-compressed tar files stored under:
89133```
90134
91135The deployed SAM stack sets ` DATAOPS_EXPORT_ARCHIVE_BUCKET ` ,
92- ` DATAOPS_EXPORT_ARCHIVE_PREFIX ` , and ` DATAOPS_ENV ` for the private work-engine .
136+ ` DATAOPS_EXPORT_ARCHIVE_PREFIX ` , and ` DATAOPS_ENV ` for the backend .
93137The archive bucket is retained, private, encrypted, versioned, tagged for backup
94138selection, and configured with noncurrent-version lifecycle retention.
95139
@@ -98,7 +142,7 @@ selection, and configured with noncurrent-version lifecycle retention.
98142Validate the export:
99143
100144``` bash
101- npm --prefix work-engine run validate:export -- .tmp/exports/dataops-export
145+ npm --prefix backend run validate:export -- .tmp/exports/dataops-export
102146```
103147
104148This checks manifest schema version, file presence, entity counts, checksums,
@@ -110,7 +154,7 @@ Run a dry-run import to see what a restore would write without mutating any
110154data:
111155
112156``` bash
113- npm --prefix work-engine run dry-run:import -- .tmp/exports/dataops-export
157+ npm --prefix backend run dry-run:import -- .tmp/exports/dataops-export
114158```
115159
116160Output:
@@ -137,12 +181,21 @@ Exits zero when valid, non-zero when validation fails.
137181Generate local restore evidence from an archive without writing production data:
138182
139183``` bash
140- npm --prefix work-engine run restore:drill -- \
184+ # Download or copy the selected remote archive byte-for-byte to
185+ # .tmp/exports/selected-archive.tar.gz before computing its checksum.
186+ s3_archive_checksum=$(
187+ sha256sum .tmp/exports/selected-archive.tar.gz | awk ' {print "sha256:"$1}'
188+ )
189+ npm --prefix backend run restore:drill -- \
141190 --archive s3://< archive-bucket> /< archive-key> \
191+ --archive-checksum " $s3_archive_checksum " \
142192 --target-environment staging-drill \
143193 --output-dir .tmp/exports/restore-drill
144194```
145195
196+ The checksum must come from that byte-for-byte local copy of the selected remote
197+ archive. Do not infer it from bucket metadata.
198+
146199For local tests, pass a ` file:// ` archive URI returned by the scheduled export
147200route. The command extracts the archive under ` .tmp/exports/restore-drill ` , runs
148201` validate:export ` , runs ` dry-run:import ` , and writes
@@ -160,6 +213,9 @@ The evidence report includes:
160213- target environment
161214- evidence timestamp
162215- smoke-check checklist result
216+ - generic statement that artifact-binary backup proof was not performed or
217+ verified by this drill and remains the separate privately retained
218+ responsibility of the authorized artifact-storage operator
163219
164220` restore:drill ` rejects ` production ` and ` prod ` as target environments. It does
165221not restore, import, overwrite, delete, or repair production DynamoDB records.
@@ -174,8 +230,8 @@ backups:
174230
175231``` bash
176232aws dynamodb restore-table-to-point-in-time \
177- --source-table-name dataops-v1 -tasks \
178- --target-table-name dataops-v1 -tasks-restored \
233+ --source-table-name < stack > -tasks \
234+ --target-table-name < stack > -tasks-restored \
179235 --restore-date-time 2026-06-27T10:00:00Z
180236```
181237
@@ -211,8 +267,10 @@ Run this sequence end-to-end before production data becomes critical:
211267
212268- ` generated_at ` is the logical snapshot anchor. The export scans tables
213269 sequentially; there is no multi-table transactional snapshot guarantee.
214- - File export covers metadata only; binary backup requires S3 versioning or
215- a separate artifact archive.
270+ - Portable export validation, dry-run analysis, restore evidence, and passed
271+ smoke checks do not prove that externally stored file or artifact binaries
272+ remain recoverable. Artifact-binary backup proof is retained privately by the
273+ authorized artifact-storage operator under a separate process.
216274- The dry-run import validates and counts but does not write to a target
217275 database. A full import tool (for Postgres migration) is a follow-up.
218276- Production restore/import/write behavior is human-gated. Automated cron
0 commit comments