schema: migration v17 — le format d'import complet sur import_sources #323

Closed
opened 2026-08-12 20:14:32 +00:00 by maximus · 0 comments
Owner

Refs: spec-decisions-import-csv-format.md + spec-plan-import-csv-format.md (racine du repo).

Contexte

import_sources ne porte ni amount_mode ni sign_convention (src-tauri/src/database/consolidated_schema.sql:8-20). Ces deux champs n'existent que sur import_config_templates (:147-159). C'est cette asymetrie qui cause le bug racine du chantier : useImportWizard.ts:323 ecrit signConvention: "negative_expense" en dur a la restauration d'une source, et une source reglee en montants positifs revient au defaut inverse au deuxieme import.

Cette issue pose le socle de donnees. Elle ne change aucun comportement observable : le backfill reproduit exactement la regle appliquee aujourd'hui a la volee.

Taches

  • Migration v17 dans src-tauri/src/lib.rs, sur le modele des v14/v15 :
    ALTER TABLE import_sources ADD COLUMN amount_mode TEXT NOT NULL DEFAULT 'single';
    ALTER TABLE import_sources ADD COLUMN sign_convention TEXT NOT NULL DEFAULT 'negative_expense';
    ALTER TABLE import_sources ADD COLUMN header_signature TEXT;
    ALTER TABLE import_sources ADD COLUMN template_id INTEGER REFERENCES import_config_templates(id) ON DELETE SET NULL;
    UPDATE import_sources SET amount_mode = 'debit_credit' WHERE column_mapping LIKE '%debitAmount%';
  • Miroir des quatre colonnes dans consolidated_schema.sql (nouveaux profils)
  • Constante V17_SQL cote tests, sur le pattern V13_SQL a V16_SQL
  • Test : application sur une base v16 peuplee
  • Test : le backfill reproduit la regle actuelle (mapping avec debitAmount -> debit_credit, sans -> single)
  • Test de non-regression : v1 a v16 inchangees, checksums intacts

Points d'attention

  • Pas de contrainte CHECK sur amount_mode, contrairement au pattern de la v15 sur balance_accounts.kind. Ecart assume et decide : le troisieme mode de montant (montant absolu + colonne indicateur D/C) est hors scope mais doit pouvoir etre ajoute sans migration.
  • Le backfill utilise LIKE '%debitAmount%' et non json_extract, pour ne dependre d'aucune extension JSON1 dans le SQLite embarque.
  • Ne jamais modifier une migration existante (checksum). v17 est strictement additive.

Criteres d'acceptation

  • La v17 s'applique sur une base v16 peuplee sans perte
  • Aucune source ne change de comportement apres migration
  • cargo test vert, migrations v1-v16 intactes

Revision /review-spec — 2026-08-13

Corrections a appliquer, issues de la revue 3 experts :

  • Ordre change : cette issue depend desormais de #326 (le corpus de contrat passe en premier maillon).
  • Garder les CHECK (decision tranchee, revise le corps ci-dessus) :
    amount_mode TEXT NOT NULL DEFAULT 'single' CHECK (amount_mode IN ('single','debit_credit','absolute_indicator'))
    sign_convention TEXT NOT NULL DEFAULT 'negative_expense' CHECK (sign_convention IN ('negative_expense','positive_expense'))
    La valeur absolute_indicator est admise d'emblee : le 3e mode reste ajoutable sans migration, et la base oppose quand meme une garantie a une valeur corrompue.
  • template_id est une etiquette de provenance — jamais relue comme format. Les huit colonnes de la source font foi.
  • Le rationale du miroir consolide etait inverse : get_new_profile_init_sql s'execute APRES toutes les migrations et le script n'utilise que CREATE TABLE IF NOT EXISTS, donc les colonnes ajoutees la sont inertes en production. Les nouveaux profils les recoivent de la v17 seule ; le miroir sert au test de parite.
  • Remplacer la case « checksums intacts » — aucun harnais de checksum n'existe (les constantes V10_SQL..V16_SQL sont des copies manuelles ; les checksums ne vivent qu'au runtime dans _sqlx_migrations). La verifier revient a : chaines SQL v1-v16 absentes du diff + V17_SQL applique sur une base v16 peuplee.
  • Ajouter un test de parite consolidated_schema / chaine v1→v17 (colonnes, DEFAULT, CHECK), sur le modele de consolidated_schema_has_holdings_tables_and_kind_at_parity (lib.rs:2824).

Depends on #326


Fichiers concernes

  • src-tauri/src/lib.rs — migration v17 + constante V17_SQL + tests
  • src-tauri/src/database/consolidated_schema.sql — miroir des 4 colonnes (definition de reference testee)

Decisions prises en planification

  • Emplacement du code partage : le codec formatToRow/formatFromRow et mapRow vivent dans src/utils/importFormat.ts — meme dossier que amountParser, dateParser et csvAutoDetect, qui portent deja la logique pure du domaine. Les types restent dans src/shared/types/.
  • Aucune correction retroactive des transactions deja importees a l'envers : la voie de reparation est deleteImportWithTransactions puis re-import. Ne jamais muter des montants deja ecrits.
  • L'import reste entierement en edition Free — aucun gating a ajouter.
  • Les specs spec-decisions-import-csv-format.md et spec-plan-import-csv-format.md sont committees a la racine (force-add, precedent PR #295) : elles sont lisibles depuis un worktree.

Spec source

spec-plan-import-csv-format.md + spec-decisions-import-csv-format.md (racine du repo, committees).

Refs: `spec-decisions-import-csv-format.md` + `spec-plan-import-csv-format.md` (racine du repo). ## Contexte `import_sources` ne porte ni `amount_mode` ni `sign_convention` (`src-tauri/src/database/consolidated_schema.sql:8-20`). Ces deux champs n'existent que sur `import_config_templates` (`:147-159`). C'est cette asymetrie qui cause le bug racine du chantier : `useImportWizard.ts:323` ecrit `signConvention: "negative_expense"` en dur a la restauration d'une source, et une source reglee en montants positifs revient au defaut inverse au deuxieme import. Cette issue pose le socle de donnees. Elle ne change aucun comportement observable : le backfill reproduit exactement la regle appliquee aujourd'hui a la volee. ## Taches - [ ] Migration v17 dans `src-tauri/src/lib.rs`, sur le modele des v14/v15 : `ALTER TABLE import_sources ADD COLUMN amount_mode TEXT NOT NULL DEFAULT 'single';` `ALTER TABLE import_sources ADD COLUMN sign_convention TEXT NOT NULL DEFAULT 'negative_expense';` `ALTER TABLE import_sources ADD COLUMN header_signature TEXT;` `ALTER TABLE import_sources ADD COLUMN template_id INTEGER REFERENCES import_config_templates(id) ON DELETE SET NULL;` `UPDATE import_sources SET amount_mode = 'debit_credit' WHERE column_mapping LIKE '%debitAmount%';` - [ ] Miroir des quatre colonnes dans `consolidated_schema.sql` (nouveaux profils) - [ ] Constante `V17_SQL` cote tests, sur le pattern `V13_SQL` a `V16_SQL` - [ ] Test : application sur une base v16 peuplee - [ ] Test : le backfill reproduit la regle actuelle (mapping avec `debitAmount` -> `debit_credit`, sans -> `single`) - [ ] Test de non-regression : v1 a v16 inchangees, checksums intacts ## Points d'attention - **Pas de contrainte `CHECK` sur `amount_mode`**, contrairement au pattern de la v15 sur `balance_accounts.kind`. Ecart assume et decide : le troisieme mode de montant (montant absolu + colonne indicateur `D`/`C`) est hors scope mais doit pouvoir etre ajoute sans migration. - Le backfill utilise `LIKE '%debitAmount%'` et non `json_extract`, pour ne dependre d'aucune extension JSON1 dans le SQLite embarque. - Ne jamais modifier une migration existante (checksum). v17 est strictement additive. ## Criteres d'acceptation - [ ] La v17 s'applique sur une base v16 peuplee sans perte - [ ] Aucune source ne change de comportement apres migration - [ ] `cargo test` vert, migrations v1-v16 intactes --- ## Revision /review-spec — 2026-08-13 Corrections a appliquer, issues de la revue 3 experts : - **Ordre change** : cette issue depend desormais de #326 (le corpus de contrat passe en premier maillon). - **Garder les `CHECK`** (decision tranchee, revise le corps ci-dessus) : `amount_mode TEXT NOT NULL DEFAULT 'single' CHECK (amount_mode IN ('single','debit_credit','absolute_indicator'))` `sign_convention TEXT NOT NULL DEFAULT 'negative_expense' CHECK (sign_convention IN ('negative_expense','positive_expense'))` La valeur `absolute_indicator` est admise d'emblee : le 3e mode reste ajoutable sans migration, et la base oppose quand meme une garantie a une valeur corrompue. - **`template_id` est une etiquette de provenance** — jamais relue comme format. Les huit colonnes de la source font foi. - **Le rationale du miroir consolide etait inverse** : `get_new_profile_init_sql` s'execute APRES toutes les migrations et le script n'utilise que `CREATE TABLE IF NOT EXISTS`, donc les colonnes ajoutees la sont inertes en production. Les nouveaux profils les recoivent de la v17 seule ; le miroir sert au test de parite. - **Remplacer la case « checksums intacts »** — aucun harnais de checksum n'existe (les constantes `V10_SQL`..`V16_SQL` sont des copies manuelles ; les checksums ne vivent qu'au runtime dans `_sqlx_migrations`). La verifier revient a : chaines SQL v1-v16 absentes du diff + `V17_SQL` applique sur une base v16 peuplee. - **Ajouter un test de parite** consolidated_schema / chaine v1→v17 (colonnes, `DEFAULT`, `CHECK`), sur le modele de `consolidated_schema_has_holdings_tables_and_kind_at_parity` (`lib.rs:2824`). Depends on #326 --- ## Fichiers concernes - `src-tauri/src/lib.rs` — migration v17 + constante `V17_SQL` + tests - `src-tauri/src/database/consolidated_schema.sql` — miroir des 4 colonnes (definition de reference testee) ## Decisions prises en planification - **Emplacement du code partage** : le codec `formatToRow`/`formatFromRow` et `mapRow` vivent dans `src/utils/importFormat.ts` — meme dossier que `amountParser`, `dateParser` et `csvAutoDetect`, qui portent deja la logique pure du domaine. Les types restent dans `src/shared/types/`. - **Aucune correction retroactive** des transactions deja importees a l'envers : la voie de reparation est `deleteImportWithTransactions` puis re-import. Ne jamais muter des montants deja ecrits. - **L'import reste entierement en edition Free** — aucun gating a ajouter. - Les specs `spec-decisions-import-csv-format.md` et `spec-plan-import-csv-format.md` sont **committees a la racine** (force-add, precedent PR #295) : elles sont lisibles depuis un worktree. ## Spec source `spec-plan-import-csv-format.md` + `spec-decisions-import-csv-format.md` (racine du repo, committees).
maximus added this to the planned-2026-08-12-import-csv-format milestone 2026-08-12 20:14:32 +00:00
maximus added the
status:ready
type:schema
source:human
labels 2026-08-12 20:14:32 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-08-13 16:41:59 +00:00
maximus added
status:approved
and removed
status:in-progress
labels 2026-08-14 15:28:25 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#323
No description provided.