DVR First Slice Operational Hardening¶
Stato di riferimento:
dvr_first_slice_completed_with_notesdvr_operational_hardening_ready_with_notes
Scopo di questo documento:
- chiudere l'operativita' del primo slice DVR
- definire una strategia migration prudente
- definire uno smoke script ufficiale del modulo DVR
Warning forti¶
- Nessun
stampcieco. - Nessun intervento su ambienti non allineati senza backup DB.
- Non riscrivere la migration
0003_dvr_initial_slicese e' gia' stata applicata su ambienti reali. - Su ambienti
schema-misalignednon eseguireflask db upgradealla cieca.
Stato Alembic del modulo DVR¶
Chain DVR nel repository:
0001_initial0002_optimization_results0003_dvr_initial_slice
La revisione 0003_dvr_initial_slice.py crea:
dvr_casedvr_case_snapshotdvr_section_instancedvr_measure_actiondvr_exportdvr_case_event
Strategia operativa¶
Caso A. Ambiente pulito¶
Condizioni:
- history Alembic coerente col repository
- tabelle DVR non presenti
Procedura:
- Eseguire backup DB.
- Verificare:
flask db currentflask db history- Applicare:
flask db upgrade
Sicuro:
- migration Alembic normale
Non sicuro:
- creare tabelle DVR a mano
- fare
stampsenza motivo
Caso B. Tabelle DVR presenti ma migration non registrata¶
Condizioni:
- tabelle
dvr_*gia' presenti - migration
0003_dvr_initial_slicenon registrata
Procedura:
- Eseguire backup DB.
- Verificare parity completa tra DB reale e migration
0003. - Solo se la parity e' completa:
flask db stamp 0003_dvr_initial_slice- Riprendere il flusso standard:
flask db upgrade
Sicuro:
stampsolo dopo audit strutturale completo
Non sicuro:
stampciecoupgradediretto se Alembic tenterebbe di creare oggetti gia' esistenti
Caso C. Ambiente schema-misaligned¶
Condizioni:
alembic_versionfuori tree- history diverge dal repository
- tabelle create manualmente o schema non coerente
Procedura:
- Eseguire backup DB.
- Leggere:
SELECT version_num FROM alembic_version;- Verificare presenza e forma delle tabelle DVR.
- Scegliere esplicitamente:
parity + stamp, solo se schema reale e0003coincidono- migration correttiva nuova, se non coincidono
Sicuro:
- runbook + audit + decisione esplicita
Non sicuro:
stamp head- aggiornare
alembic_versionmanualmente - drop/recreate delle tabelle con dati
Checklist di audit tabella-per-tabella¶
Usare:
SHOW CREATE TABLE dvr_case;
SHOW CREATE TABLE dvr_case_snapshot;
SHOW CREATE TABLE dvr_section_instance;
SHOW CREATE TABLE dvr_measure_action;
SHOW CREATE TABLE dvr_export;
SHOW CREATE TABLE dvr_case_event;
dvr_case¶
Colonne attese:
idtenant_keydocumento_idcliente_idcliente_sede_idcase_keystatusrevision_noderived_from_case_idtemplate_registry_idtemplate_version_ideasy_builder_template_idopened_atready_for_generation_atgenerated_atcreated_by_idcreated_atupdated_at
FK attese:
documento_id -> documento.idcliente_id -> cliente.idcliente_sede_id -> cliente_sede.idderived_from_case_id -> dvr_case.idtemplate_registry_id -> template_registry.idtemplate_version_id -> template_version.id
Unique attesi:
uq_dvr_case_case_keysucase_key
Indici attesi:
ix_dvr_case_tenant_key_statusix_dvr_case_cliente_idix_dvr_case_documento_idix_dvr_case_cliente_sede_idix_dvr_case_derived_from_case_id
dvr_case_snapshot¶
Colonne attese:
iddvr_case_idsnapshot_kindpayload_jsonchecksumcreated_by_idcreated_at
FK attese:
dvr_case_id -> dvr_case.id
Unique attesi:
uq_dvr_case_snapshot_kindsu(dvr_case_id, snapshot_kind)
Indici attesi:
ix_dvr_case_snapshot_dvr_case_idix_dvr_case_snapshot_snapshot_kindix_dvr_case_snapshot_checksum
dvr_section_instance¶
Colonne attese:
iddvr_case_idsection_codesection_labelsort_orderapplicability_statusstructured_payload_jsontechnical_notesupdated_by_idcreated_atupdated_at
FK attese:
dvr_case_id -> dvr_case.id
Unique attesi:
uq_dvr_section_case_codesu(dvr_case_id, section_code)
Indici attesi:
ix_dvr_section_instance_dvr_case_idix_dvr_section_instance_section_codeix_dvr_section_instance_applicability_status
dvr_measure_action¶
Colonne attese:
iddvr_case_idsection_instance_idaction_typedescriptionresponsabile_labeldue_datestatusnotecreated_by_idcreated_atupdated_at
FK attese:
dvr_case_id -> dvr_case.idsection_instance_id -> dvr_section_instance.id
Unique attesi:
- nessuno
Indici attesi:
ix_dvr_measure_action_dvr_case_idix_dvr_measure_action_section_instance_idix_dvr_measure_action_action_typeix_dvr_measure_action_statusix_dvr_measure_action_due_date
dvr_export¶
Colonne attese:
iddvr_case_iddocumento_idsource_snapshot_idexport_kindversion_norender_checksumcreated_by_idcreated_at
FK attese:
dvr_case_id -> dvr_case.iddocumento_id -> documento.idsource_snapshot_id -> dvr_case_snapshot.id
Unique attesi:
- nessuno
Indici attesi:
ix_dvr_export_dvr_case_idix_dvr_export_documento_idix_dvr_export_source_snapshot_idix_dvr_export_render_checksum
dvr_case_event¶
Colonne attese:
iddvr_case_idevent_codefrom_statusto_statuspayload_jsonactor_user_idcreated_at
FK attese:
dvr_case_id -> dvr_case.id
Unique attesi:
- nessuno
Indici attesi:
ix_dvr_case_event_dvr_case_idix_dvr_case_event_event_code
Comandi operativi¶
Verifica revision Alembic:
/root/.pyenv/versions/safeops/bin/flask --app app db current
/root/.pyenv/versions/safeops/bin/flask --app app db history
Verifica DB:
SELECT version_num FROM alembic_version;
SHOW TABLES LIKE 'dvr_%';
Solo dopo parity completa, nel caso B:
/root/.pyenv/versions/safeops/bin/flask --app app db stamp 0003_dvr_initial_slice
/root/.pyenv/versions/safeops/bin/flask --app app db upgrade
Smoke script ufficiale¶
Script:
Scopo:
- verificare il primo slice DVR via services esistenti
- nessuna nuova logica di dominio
Input minimi:
DATABASE_URL='mysql+pymysql://appuser:***@127.0.0.1:3306/appdb' \
SAFEOPS_SKIP_APPBUILDER_BOOTSTRAP=1 \
/root/.pyenv/versions/3.11.5/bin/python /home/safeops/safeops/scripts/dvr_first_slice_smoke.py \
--documento-id 123 \
--actor-username dvr_smoke
Verifiche eseguite:
- create_case
- bootstrap 3 sezioni
- snapshot prefill
- compilazione 3 sezioni
- almeno una azione
- transizione
in_compilazione - transizione
pronto_per_generazione - snapshot issued
- export PDF
- stato finale
generato
Exit code:
0se tutto passa1se una verifica critica fallisce
Output JSON stabile:
okscriptstarted_atfinished_atduration_msinputcasesectionsactionssnapshotsexporteventserrorswarnings
Cleanup:
- nessun cleanup automatico
- usare gli ID stampati in output per eventuale cleanup manuale in ambienti non produttivi
Guardrail¶
Non toccare:
- dominio DVR
- workflow DVR
- Compila DVR
- renderer core
- snapshot logic
Non rimettere dentro documentale:
- workflow DVR
- bootstrap case
- snapshot logic
- audit di dominio DVR
Non complicare questo hardening:
- Easy alignment
- nuove feature
- cleanup automatico
- automazioni aggressive per ambienti schema-misaligned
Lo smoke script non deve diventare:
- un workflow parallelo
- un provisioning tool
- un refactor mascherato del dominio DVR