Sincronizzazione editoriale D1
Scopo e confine
Questo runbook copia in modo esplicito il contenuto editoriale canonico dal D1
di produzione al D1 locale persistito oppure, in una fase separata, al D1
remoto architecture-coffee-development-refresh-20260822. La produzione è sempre una sorgente
in sola lettura: il comando repository-owned esegue una singola SELECT
costruita dal codice, tramite il Wrangler installato nel repository. Non esiste
un'opzione per scegliere un database o un ambiente arbitrario e la produzione
non è mai accettata come target.
La sincronizzazione non è replica continua, non collega l'applicazione locale a produzione, non applica migrazioni remote e non distribuisce Worker.
Dataset ammesso
Lo snapshot contiene esattamente:
editorial_topics;knowledge_assets;glossary_terms;issues.
Per queste tabelle sono ammessi solo i nomi di colonna dichiarati nello script.
ID, slug, JSON canonico, stati, revisioni, relazioni e timestamp vengono
conservati. issue_number_sequence non viene letto dalla produzione: dopo
l'import viene riconciliato dal massimo numero Issue presente nel target, senza
ridurre un valore locale già più alto.
Le relazioni nei campi JSON vengono preservate come insiemi ordinati di identificatori canonici e validate per forma e unicità. Lo schema corrente non impone che ogni identificatore JSON risolva una riga presente nello stesso snapshot; i vincoli SQL e il controllo foreign key restano l'autorità per l'integrità referenziale del database.
Sono esclusi feedback, Campaign Draft e attempt, stato Mailjet/provider, job e
diagnostica di generazione, operation e attempt di deployment, autenticazione,
recipient/consenso, code ed evidenza operativa. issue_draft_revisions è
esclusa perché l'Admin corrente legge issues.draft_revision e crea nuove
revisioni, ma non espone una lettura della storia. La tabella esclusa contiene
inoltre contenuto precedente e change_reason non necessari per il test locale.
La sostituzione si ferma prima della mutazione se la rimozione di una Issue solo locale produrrebbe una cascata su una tabella esclusa. I conteggi delle tabelle escluse vengono confrontati prima e dopo ogni import.
Prerequisiti
- Usare Node.js 22 o successivo con
nvm useed eseguirenpm ci. - Verificare che il Wrangler repository-owned sia v4 con
./node_modules/.bin/wrangler --version. - Per letture remote, autenticare Wrangler con l'account autorizzato.
- Preparare lo schema locale con
npm run db:prepare:localoppure applicare tutte le migrazioni a un percorso persistito isolato. - Non eseguire migrazioni, deployment o operazioni provider durante la stessa finestra.
Lo script richiede che la storia d1_migrations e lo schema delle colonne
ammesse coincidano esattamente con il repository. Qualsiasi drift interrompe il
flusso.
Snapshot di produzione in sola lettura
Per conservare esplicitamente uno snapshot locale:
npm run db:snapshot-editorial:production -- \
--retain-to .d1-backups/production-editorial-YYYYMMDD.json
Il file deve restare sotto .d1-backups/, directory ignorata da Git, e viene
creato senza sovrascrivere file esistenti con permessi 0600 dove supportati.
L'output terminale contiene solo conteggi, distribuzioni di stato, checksum
SHA-256 e percorso locale; non contiene righe editoriali. Non allegare mai il
file a Issue, PR, workflow o artifact CI.
La sincronizzazione composta usa invece un file temporaneo 0600 e lo elimina
su successo o errore.
Import e sincronizzazione locale
merge aggiorna o inserisce le righe di produzione per chiave stabile e lascia
le righe solo locali. replace rimuove esclusivamente le righe canoniche solo
locali e poi importa lo snapshot; non cancella mai implicitamente feedback,
audit, job, Campaign Draft o altre tabelle escluse. La modalità è obbligatoria:
non esiste un default distruttivo.
Preflight senza mutazione:
npm run db:import-editorial:local -- \
--snapshot .d1-backups/production-editorial-YYYYMMDD.json \
--mode replace \
--dry-run
Import di uno snapshot già conservato:
npm run db:import-editorial:local -- \
--snapshot .d1-backups/production-editorial-YYYYMMDD.json \
--mode replace
Snapshot, import e validazione composti con cleanup automatico:
npm run db:sync-editorial:local -- --mode merge --dry-run
npm run db:sync-editorial:local -- --mode merge
Per una prova isolata è ammesso --persist-to solo sotto
.wrangler/state/ o una sottodirectory della directory temporanea di sistema.
Il percorso locale ordinario resta .wrangler/state/development.
Backup e preflight dello sviluppo remoto
Il backup editoriale dello sviluppo contiene le quattro tabelle ammesse e il
suo issue_number_sequence; non copia tabelle operative escluse che il piano di
import non deve modificare:
npm run db:backup-editorial:development -- \
--retain-to .d1-backups/development-editorial-before-YYYYMMDD.json
Il preflight composto legge produzione e sviluppo, valida schema, migrazioni, checksum, JSON, relazioni, chiavi, foreign key e piano di sostituzione, ma non scrive nel D1 remoto:
npm run db:sync-editorial:development -- --dry-run
Una mutazione dello sviluppo remoto è una fase distinta. Richiede
scope esplicito nell'Issue mergiata da Fra, un backup locale nuovo e il token
esatto architecture-coffee-development-refresh-20260822:
npm run db:sync-editorial:development -- \
--confirm architecture-coffee-development-refresh-20260822 \
--backup-to .d1-backups/development-editorial-before-YYYYMMDD-HHMM.json
In alternativa, con uno snapshot di produzione già conservato:
npm run db:import-editorial:development -- \
--snapshot .d1-backups/production-editorial-YYYYMMDD.json \
--confirm architecture-coffee-development-refresh-20260822 \
--backup-to .d1-backups/development-editorial-before-YYYYMMDD-HHMM.json
Lo sviluppo remoto usa solo replace. Il token errato, assente o riferito alla
produzione viene rifiutato. L'implementazione e la review del comando non
autorizzano la sua esecuzione.
Validazioni e criteri di arresto
Prima della scrittura vengono controllati formato e checksum, sorgente esatta,
tabelle e colonne, migrazioni, JSON, ID, slug, stati, revisioni, relazioni,
conflitti di chiave e dipendenze escluse. Il SQL target viene generato dal
repository e rifiuta DDL, trigger, migrazioni, PRAGMA, transazioni e target
non ammessi.
Dopo la scrittura vengono riletti il dataset e issue_number_sequence, viene
eseguito il controllo foreign key e vengono confrontati i conteggi esclusi. In
replace la proiezione deve coincidere con lo snapshot; in merge ogni riga
dello snapshot deve coincidere e le righe solo locali restano presenti. Una
seconda esecuzione deve conservare lo stesso stato e non creare duplicati.
Fermarsi senza tentare correzioni automatiche quando:
- schema o migrazioni non coincidono;
- checksum, JSON, relazione o stato non è valido;
- esiste un conflitto fra ID, slug o numero Issue;
replacetoccherebbe una dipendenza esclusa;- Wrangler non è v4, il target non è esatto o il token non coincide;
- una lettura, un import o il readback è fallito o ambiguo;
- cambiano i conteggi delle tabelle escluse o una foreign key non è valida.
Cleanup e recupero
I file temporanei composti vengono eliminati anche in caso di errore. Eliminare
uno snapshot conservato solo dopo aver concluso le verifiche, indicando il file
esatto sotto .d1-backups/; non cancellare l'intera directory alla cieca.
Un errore locale prima della mutazione non richiede recupero. Dopo un import
locale non valido, fermare API e MCP e scegliere esplicitamente fra nuovo
import dello snapshot o npm run db:reset:local seguito da
npm run db:prepare:local; il reset elimina tutto il D1 locale.
Dopo una mutazione remota fallita o un readback ambiguo, conservare il backup, non ripetere il comando e non improvvisare SQL di riparazione. Il ripristino del D1 di sviluppo usa il rollback già approvato nell'Issue; se manca o lo stato non è determinabile, applica la stop condition eccezionale senza un retry.
Evidenza sanitizzata
Issue e PR possono riportare solo comando, esito, conteggi per tabella, distribuzioni di stato, checksum, controllo foreign key, sequenza riconciliata e lista delle tabelle escluse. Non riportare righe, note, identità reviewer, payload JSON, identificatori infrastrutturali, URL firmati o altri dati privati.