From 33682eafb6cc4d7a349789e91426037c7ccdf71b Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sat, 13 Jun 2026 14:45:00 +0200 Subject: [PATCH] clean db Signed-off-by: GnomeZworc --- migrations/000001_init_schema.down.sql | 2 +- migrations/000001_init_schema.up.sql | 60 +++++++++---------- .../000002_price_history_intraday.down.sql | 10 ---- .../000002_price_history_intraday.up.sql | 19 ------ migrations/000003_drop_account_taux.down.sql | 1 - migrations/000003_drop_account_taux.up.sql | 3 - ...000004_envelopes_and_transactions.down.sql | 18 ------ .../000004_envelopes_and_transactions.up.sql | 49 --------------- .../000005_envelope_as_account.down.sql | 59 ------------------ migrations/000005_envelope_as_account.up.sql | 50 ---------------- .../000006_drop_montant_alloue.down.sql | 1 - migrations/000006_drop_montant_alloue.up.sql | 3 - 12 files changed, 31 insertions(+), 244 deletions(-) delete mode 100644 migrations/000002_price_history_intraday.down.sql delete mode 100644 migrations/000002_price_history_intraday.up.sql delete mode 100644 migrations/000003_drop_account_taux.down.sql delete mode 100644 migrations/000003_drop_account_taux.up.sql delete mode 100644 migrations/000004_envelopes_and_transactions.down.sql delete mode 100644 migrations/000004_envelopes_and_transactions.up.sql delete mode 100644 migrations/000005_envelope_as_account.down.sql delete mode 100644 migrations/000005_envelope_as_account.up.sql delete mode 100644 migrations/000006_drop_montant_alloue.down.sql delete mode 100644 migrations/000006_drop_montant_alloue.up.sql diff --git a/migrations/000001_init_schema.down.sql b/migrations/000001_init_schema.down.sql index 0f68c15..b107d46 100644 --- a/migrations/000001_init_schema.down.sql +++ b/migrations/000001_init_schema.down.sql @@ -2,7 +2,7 @@ DROP TABLE IF EXISTS account_snapshot; DROP TABLE IF EXISTS position_snapshot; DROP TABLE IF EXISTS transaction; DROP TABLE IF EXISTS recurring_rule; -DROP TABLE IF EXISTS envelope; DROP TABLE IF EXISTS account; +DROP TABLE IF EXISTS instrument_ticker_cache; DROP TABLE IF EXISTS price_history; DROP TABLE IF EXISTS instrument; diff --git a/migrations/000001_init_schema.up.sql b/migrations/000001_init_schema.up.sql index a81a880..90df706 100644 --- a/migrations/000001_init_schema.up.sql +++ b/migrations/000001_init_schema.up.sql @@ -9,32 +9,34 @@ CREATE TABLE instrument ( devise_cotation TEXT NOT NULL DEFAULT 'EUR' ); --- Historique de prix (hypertable TimescaleDB) +-- Historique de prix intraday (hypertable TimescaleDB) +-- Le job de nettoyage consolide à J-1 en gardant uniquement le dernier fetch CREATE TABLE price_history ( - instrument_id INTEGER NOT NULL REFERENCES instrument(id), - date DATE NOT NULL, + instrument_id INTEGER NOT NULL REFERENCES instrument(id), + fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), prix NUMERIC(24, 8) NOT NULL, - PRIMARY KEY (instrument_id, date) + PRIMARY KEY (instrument_id, fetched_at) ); -SELECT create_hypertable('price_history', by_range('date')); +SELECT create_hypertable('price_history', by_range('fetched_at')); +CREATE INDEX idx_price_history_instrument ON price_history(instrument_id, fetched_at DESC); --- Comptes : conteneurs de positions, aucun solde stocké +-- Cache OpenFIGI (ISIN → ticker Yahoo Finance) et CoinGecko (ticker → coin ID) +CREATE TABLE instrument_ticker_cache ( + instrument_id INTEGER PRIMARY KEY REFERENCES instrument(id) ON DELETE CASCADE, + ticker TEXT NOT NULL, + fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +-- Comptes et enveloppes : les enveloppes sont des sous-comptes (master_account_id non null) +-- Un sous-compte hérite du type et de la devise de son maître ; pas de chaînage CREATE TABLE account ( - id SERIAL PRIMARY KEY, - nom TEXT NOT NULL, - type TEXT NOT NULL, -- courant, livret, pea, cto, crypto, ... - devise_reference TEXT NOT NULL DEFAULT 'EUR', - plafond NUMERIC(24, 8), - taux NUMERIC(10, 6) -); - --- Enveloppes : ventilation logique EUR d'un compte (strictement monétaire) -CREATE TABLE envelope ( - id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - nom TEXT NOT NULL, - objectif TEXT, - montant_alloue NUMERIC(24, 8) NOT NULL DEFAULT 0 + id SERIAL PRIMARY KEY, + nom TEXT NOT NULL, + type TEXT NOT NULL, -- courant, livret, pea, cto, crypto, ... + devise_reference TEXT NOT NULL DEFAULT 'EUR', + plafond NUMERIC(24, 8), -- indicatif (ex : plafond réglementaire Livret A) + master_account_id INTEGER REFERENCES account(id) ON DELETE CASCADE, + objectif TEXT -- description libre pour les enveloppes ); -- Règles de récurrence @@ -49,11 +51,10 @@ CREATE TABLE recurring_rule ( tiers TEXT, label TEXT NOT NULL, categorie TEXT, - envelope_id INTEGER REFERENCES envelope(id), frequence TEXT NOT NULL, -- RRULE string (RFC 5545) date_debut DATE NOT NULL, date_fin DATE, - generated_until DATE -- curseur d'idempotence + generated_until DATE -- curseur d'idempotence ); -- Transactions : échange atomique source/dest généralisé aux instruments @@ -69,7 +70,6 @@ CREATE TABLE transaction ( tiers TEXT, label TEXT NOT NULL, categorie TEXT, - envelope_id INTEGER REFERENCES envelope(id), validated BOOLEAN NOT NULL DEFAULT FALSE, recurring_rule_id INTEGER REFERENCES recurring_rule(id), @@ -100,12 +100,12 @@ CREATE TABLE transaction ( ) ); -CREATE INDEX idx_transaction_date ON transaction(date); -CREATE INDEX idx_transaction_account_source ON transaction(account_source_id) WHERE account_source_id IS NOT NULL; -CREATE INDEX idx_transaction_account_dest ON transaction(account_dest_id) WHERE account_dest_id IS NOT NULL; -CREATE INDEX idx_transaction_unvalidated ON transaction(date) WHERE validated = FALSE; +CREATE INDEX idx_transaction_date ON transaction(date); +CREATE INDEX idx_transaction_account_source ON transaction(account_source_id) WHERE account_source_id IS NOT NULL; +CREATE INDEX idx_transaction_account_dest ON transaction(account_dest_id) WHERE account_dest_id IS NOT NULL; +CREATE INDEX idx_transaction_unvalidated ON transaction(date) WHERE validated = FALSE; --- Snapshots de position (hypertable TimescaleDB) +-- Snapshots de position par instrument et par compte (hypertable TimescaleDB) CREATE TABLE position_snapshot ( date DATE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id), @@ -119,7 +119,7 @@ CREATE TABLE position_snapshot ( SELECT create_hypertable('position_snapshot', by_range('date')); CREATE INDEX idx_position_snapshot_lookup ON position_snapshot(account_id, instrument_id, date DESC); --- Snapshots de compte agrégés (hypertable TimescaleDB) +-- Snapshots de valeur agrégée par compte (hypertable TimescaleDB) CREATE TABLE account_snapshot ( date DATE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id), diff --git a/migrations/000002_price_history_intraday.down.sql b/migrations/000002_price_history_intraday.down.sql deleted file mode 100644 index 42b971f..0000000 --- a/migrations/000002_price_history_intraday.down.sql +++ /dev/null @@ -1,10 +0,0 @@ -DROP TABLE IF EXISTS instrument_ticker_cache; -DROP TABLE IF EXISTS price_history; - -CREATE TABLE price_history ( - instrument_id INTEGER NOT NULL REFERENCES instrument(id), - date DATE NOT NULL, - prix NUMERIC(24, 8) NOT NULL, - PRIMARY KEY (instrument_id, date) -); -SELECT create_hypertable('price_history', by_range('date')); diff --git a/migrations/000002_price_history_intraday.up.sql b/migrations/000002_price_history_intraday.up.sql deleted file mode 100644 index 49bc9f0..0000000 --- a/migrations/000002_price_history_intraday.up.sql +++ /dev/null @@ -1,19 +0,0 @@ --- Recréation de price_history avec support intraday (plusieurs prix par jour) --- Le job de nettoyage consolide à J-1 en gardant uniquement le dernier fetch -DROP TABLE IF EXISTS price_history; - -CREATE TABLE price_history ( - instrument_id INTEGER NOT NULL REFERENCES instrument(id), - fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - prix NUMERIC(24, 8) NOT NULL, - PRIMARY KEY (instrument_id, fetched_at) -); -SELECT create_hypertable('price_history', by_range('fetched_at')); -CREATE INDEX idx_price_history_instrument ON price_history(instrument_id, fetched_at DESC); - --- Cache OpenFIGI (ISIN → ticker Yahoo Finance) et CoinGecko (ticker → coin ID) -CREATE TABLE instrument_ticker_cache ( - instrument_id INTEGER PRIMARY KEY REFERENCES instrument(id) ON DELETE CASCADE, - ticker TEXT NOT NULL, - fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -); diff --git a/migrations/000003_drop_account_taux.down.sql b/migrations/000003_drop_account_taux.down.sql deleted file mode 100644 index 2fafcab..0000000 --- a/migrations/000003_drop_account_taux.down.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE account ADD COLUMN taux NUMERIC(10, 6); diff --git a/migrations/000003_drop_account_taux.up.sql b/migrations/000003_drop_account_taux.up.sql deleted file mode 100644 index f322a8b..0000000 --- a/migrations/000003_drop_account_taux.up.sql +++ /dev/null @@ -1,3 +0,0 @@ --- taux retiré de account : le taux varie dans le temps et nécessite --- une table account_rate(account_id, taux, date_debut, date_fin) dédiée -ALTER TABLE account DROP COLUMN taux; diff --git a/migrations/000004_envelopes_and_transactions.down.sql b/migrations/000004_envelopes_and_transactions.down.sql deleted file mode 100644 index 0aac6c4..0000000 --- a/migrations/000004_envelopes_and_transactions.down.sql +++ /dev/null @@ -1,18 +0,0 @@ -ALTER TABLE transaction DROP CONSTRAINT chk_transaction_sides; - -ALTER TABLE transaction - DROP COLUMN envelope_source_id, - DROP COLUMN envelope_dest_id, - ADD COLUMN envelope_id INTEGER REFERENCES envelope(id); - -ALTER TABLE transaction ADD CONSTRAINT chk_transaction_sides CHECK ( - (account_source_id IS NOT NULL AND instrument_source_id IS NOT NULL AND quantite_source IS NOT NULL - OR account_source_id IS NULL AND instrument_source_id IS NULL AND quantite_source IS NULL) - AND - (account_dest_id IS NOT NULL AND instrument_dest_id IS NOT NULL AND quantite_dest IS NOT NULL - OR account_dest_id IS NULL AND instrument_dest_id IS NULL AND quantite_dest IS NULL) - AND - (account_source_id IS NOT NULL OR account_dest_id IS NOT NULL) -); - -DROP TABLE IF EXISTS envelope_snapshot; diff --git a/migrations/000004_envelopes_and_transactions.up.sql b/migrations/000004_envelopes_and_transactions.up.sql deleted file mode 100644 index 8c35fbb..0000000 --- a/migrations/000004_envelopes_and_transactions.up.sql +++ /dev/null @@ -1,49 +0,0 @@ --- Snapshots dédiés aux enveloppes (strictement monétaires = valeur EUR uniquement) -CREATE TABLE envelope_snapshot ( - date DATE NOT NULL, - envelope_id INTEGER NOT NULL REFERENCES envelope(id) ON DELETE CASCADE, - valeur NUMERIC(24, 8) NOT NULL, - PRIMARY KEY (date, envelope_id) -); -SELECT create_hypertable('envelope_snapshot', by_range('date')); -CREATE INDEX idx_envelope_snapshot_lookup ON envelope_snapshot(envelope_id, date DESC); - --- Mise à jour de la table transaction : --- Les enveloppes deviennent de vrais participants source/dest (plus de envelope_id de catégorie) -ALTER TABLE transaction - DROP COLUMN envelope_id, - ADD COLUMN envelope_source_id INTEGER REFERENCES envelope(id), - ADD COLUMN envelope_dest_id INTEGER REFERENCES envelope(id); - --- Remplacement de la contrainte CHECK pour couvrir account et envelope comme participants -ALTER TABLE transaction DROP CONSTRAINT chk_transaction_sides; - -ALTER TABLE transaction ADD CONSTRAINT chk_transaction_sides CHECK ( - -- Côté source : au plus un parmi (account, envelope), les trois champs cohérents ou tous null - ( - (account_source_id IS NOT NULL AND envelope_source_id IS NULL - OR account_source_id IS NULL AND envelope_source_id IS NOT NULL - OR account_source_id IS NULL AND envelope_source_id IS NULL) - AND - (((account_source_id IS NOT NULL OR envelope_source_id IS NOT NULL) - AND instrument_source_id IS NOT NULL AND quantite_source IS NOT NULL) - OR (account_source_id IS NULL AND envelope_source_id IS NULL - AND instrument_source_id IS NULL AND quantite_source IS NULL)) - ) - AND - -- Côté dest : même logique - ( - (account_dest_id IS NOT NULL AND envelope_dest_id IS NULL - OR account_dest_id IS NULL AND envelope_dest_id IS NOT NULL - OR account_dest_id IS NULL AND envelope_dest_id IS NULL) - AND - (((account_dest_id IS NOT NULL OR envelope_dest_id IS NOT NULL) - AND instrument_dest_id IS NOT NULL AND quantite_dest IS NOT NULL) - OR (account_dest_id IS NULL AND envelope_dest_id IS NULL - AND instrument_dest_id IS NULL AND quantite_dest IS NULL)) - ) - AND - -- Au moins un côté doit exister - (account_source_id IS NOT NULL OR envelope_source_id IS NOT NULL - OR account_dest_id IS NOT NULL OR envelope_dest_id IS NOT NULL) -); diff --git a/migrations/000005_envelope_as_account.down.sql b/migrations/000005_envelope_as_account.down.sql deleted file mode 100644 index 85faddb..0000000 --- a/migrations/000005_envelope_as_account.down.sql +++ /dev/null @@ -1,59 +0,0 @@ --- Recréation de la table envelope -CREATE TABLE envelope ( - id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - nom TEXT NOT NULL, - objectif TEXT, - montant_alloue NUMERIC(24, 8) NOT NULL DEFAULT 0 -); - --- Remigration des sous-comptes vers envelope -INSERT INTO envelope (account_id, nom, objectif, montant_alloue) -SELECT master_account_id, nom, objectif, COALESCE(montant_alloue, 0) -FROM account WHERE master_account_id IS NOT NULL; - --- Suppression des sous-comptes de account -DELETE FROM account WHERE master_account_id IS NOT NULL; - -ALTER TABLE account - DROP COLUMN master_account_id, - DROP COLUMN objectif, - DROP COLUMN montant_alloue; - --- Restauration envelope_snapshot -CREATE TABLE envelope_snapshot ( - date DATE NOT NULL, - envelope_id INTEGER NOT NULL REFERENCES envelope(id) ON DELETE CASCADE, - valeur NUMERIC(24, 8) NOT NULL, - PRIMARY KEY (date, envelope_id) -); -SELECT create_hypertable('envelope_snapshot', by_range('date')); - --- Restauration transaction avec envelope_source/dest -ALTER TABLE transaction - DROP CONSTRAINT chk_transaction_sides, - ADD COLUMN envelope_source_id INTEGER REFERENCES envelope(id), - ADD COLUMN envelope_dest_id INTEGER REFERENCES envelope(id); - -ALTER TABLE transaction ADD CONSTRAINT chk_transaction_sides CHECK ( - (account_source_id IS NOT NULL AND envelope_source_id IS NULL - OR account_source_id IS NULL AND envelope_source_id IS NOT NULL - OR account_source_id IS NULL AND envelope_source_id IS NULL) - AND - (((account_source_id IS NOT NULL OR envelope_source_id IS NOT NULL) - AND instrument_source_id IS NOT NULL AND quantite_source IS NOT NULL) - OR (account_source_id IS NULL AND envelope_source_id IS NULL - AND instrument_source_id IS NULL AND quantite_source IS NULL)) - AND - (account_dest_id IS NOT NULL AND envelope_dest_id IS NULL - OR account_dest_id IS NULL AND envelope_dest_id IS NOT NULL - OR account_dest_id IS NULL AND envelope_dest_id IS NULL) - AND - (((account_dest_id IS NOT NULL OR envelope_dest_id IS NOT NULL) - AND instrument_dest_id IS NOT NULL AND quantite_dest IS NOT NULL) - OR (account_dest_id IS NULL AND envelope_dest_id IS NULL - AND instrument_dest_id IS NULL AND quantite_dest IS NULL)) - AND - (account_source_id IS NOT NULL OR envelope_source_id IS NOT NULL - OR account_dest_id IS NOT NULL OR envelope_dest_id IS NOT NULL) -); diff --git a/migrations/000005_envelope_as_account.up.sql b/migrations/000005_envelope_as_account.up.sql deleted file mode 100644 index 3b86a96..0000000 --- a/migrations/000005_envelope_as_account.up.sql +++ /dev/null @@ -1,50 +0,0 @@ --- Les enveloppes deviennent des comptes avec master_account_id --- Un sous-compte hérite du type et de la devise de son compte maître -ALTER TABLE account - ADD COLUMN master_account_id INTEGER REFERENCES account(id) ON DELETE CASCADE, - ADD COLUMN objectif TEXT, - ADD COLUMN montant_alloue NUMERIC(24, 8); - --- Migration des enveloppes existantes vers account -INSERT INTO account (nom, type, devise_reference, master_account_id, objectif, montant_alloue) -SELECT e.nom, a.type, a.devise_reference, e.account_id, e.objectif, e.montant_alloue -FROM envelope e -JOIN account a ON a.id = e.account_id; - --- Suppression des champs envelope_source/dest ajoutés en 000004 --- (les enveloppes étant désormais des comptes, account_source_id suffit) -ALTER TABLE transaction - DROP CONSTRAINT chk_transaction_sides, - DROP COLUMN envelope_source_id, - DROP COLUMN envelope_dest_id; - -ALTER TABLE transaction ADD CONSTRAINT chk_transaction_sides CHECK ( - ( - account_source_id IS NOT NULL AND - instrument_source_id IS NOT NULL AND - quantite_source IS NOT NULL - OR - account_source_id IS NULL AND - instrument_source_id IS NULL AND - quantite_source IS NULL - ) - AND - ( - account_dest_id IS NOT NULL AND - instrument_dest_id IS NOT NULL AND - quantite_dest IS NOT NULL - OR - account_dest_id IS NULL AND - instrument_dest_id IS NULL AND - quantite_dest IS NULL - ) - AND - (account_source_id IS NOT NULL OR account_dest_id IS NOT NULL) -); - --- Suppression de la FK envelope_id dans recurring_rule avant de dropper envelope -ALTER TABLE recurring_rule DROP COLUMN envelope_id; - --- Suppression des tables envelope devenues inutiles -DROP TABLE IF EXISTS envelope_snapshot; -DROP TABLE IF EXISTS envelope; diff --git a/migrations/000006_drop_montant_alloue.down.sql b/migrations/000006_drop_montant_alloue.down.sql deleted file mode 100644 index dc51e8f..0000000 --- a/migrations/000006_drop_montant_alloue.down.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE account ADD COLUMN montant_alloue NUMERIC(24, 8); diff --git a/migrations/000006_drop_montant_alloue.up.sql b/migrations/000006_drop_montant_alloue.up.sql deleted file mode 100644 index e3b6931..0000000 --- a/migrations/000006_drop_montant_alloue.up.sql +++ /dev/null @@ -1,3 +0,0 @@ --- montant_alloue retiré : le solde réel d'une enveloppe est dérivé --- des transactions et stocké dans account_snapshot -ALTER TABLE account DROP COLUMN montant_alloue;