feat(categories): add v1 IPC seed, i18n keys, and migration v8 (#115)
All checks were successful
PR Check / rust (push) Successful in 22m29s
PR Check / frontend (push) Successful in 2m18s
PR Check / rust (pull_request) Successful in 22m39s
PR Check / frontend (pull_request) Successful in 2m18s

Livraison 1 du milestone spec-refonte-seed-categories-ipc. Applies the
new v1 IPC (Indice des prix à la consommation) taxonomy to freshly
created profiles while leaving existing v2 profiles untouched until the
migration wizard (upcoming issue #121) prompts them to move.

- Migration v8 (additive only):
    - ALTER TABLE categories ADD COLUMN i18n_key TEXT
    - INSERT OR IGNORE user_preferences.categories_schema_version=v2
      (existing profiles tagged as v2 for later migration)
- consolidated_schema.sql rewritten with the full v1 seed and
  categories_schema_version='v1' default for brand-new profiles
- src/data/categoryTaxonomyV1.json bundled as the TS-side source of
  truth (consumed by #116 categoryTaxonomyService next)
- categoriesSeed.* i18n namespace (FR/EN) — 150 entries each
- CategoryTree and CategoryCombobox fall back to the raw `name` when
  i18n_key is null (user-created categories stay literal)
- CategoryTreeNode and CategoryRow gain the i18n_key field end-to-end

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
le king fu 2026-04-19 16:41:55 -04:00
parent 0e2078088a
commit bd992f2f94
13 changed files with 1483 additions and 11 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@ target/
# User data
data/
!src/data/
*.db
*.db-journal
*.db-wal

View file

@ -2,6 +2,9 @@
## [Non publié]
### Ajouté
- **Seed de catégories IPC pour les nouveaux profils** : les nouveaux profils sont désormais créés avec la taxonomie v1 IPC (Indice des prix à la consommation) — une hiérarchie alignée sur les catégories de Statistique Canada. Les noms des catégories du seed sont traduits dynamiquement depuis la clé i18n `categoriesSeed.*` (FR/EN), donc affichés dans la langue de l'utilisateur. Les profils existants gardent l'ancien seed v2, marqués via une nouvelle préférence `categories_schema_version` (une page de migration ultérieure offrira le passage v2→v1). Côté interne : colonne `categories.i18n_key` (nullable) ajoutée par la migration v8 (strictement additive), `src/data/categoryTaxonomyV1.json` livré comme source de vérité côté TS, les renderers `CategoryTree` et `CategoryCombobox` utilisent `name` en repli quand aucune clé de traduction n'est présente (catégories créées par l'utilisateur) (#115)
## [0.8.3] - 2026-04-19
### Ajouté

View file

@ -2,6 +2,9 @@
## [Unreleased]
### Added
- **IPC-aligned categories seed for new profiles**: brand-new profiles are now seeded with the v1 IPC (Indice des prix à la consommation) taxonomy — a structured hierarchy aligned with Statistics Canada consumer price index categories. Category labels are now translated dynamically from the `categoriesSeed.*` i18n namespace (FR/EN), so seed categories display in the user's current language. Existing profiles remain on the legacy v2 seed, marked via a new `categories_schema_version` user preference (a later migration wizard will offer the v2→v1 transition). Internally: nullable `categories.i18n_key` column added in migration v8 (additive only), `src/data/categoryTaxonomyV1.json` bundled as the TS-side source of truth, `CategoryTree` and `CategoryCombobox` renderers fall back to the raw `name` when no translation key is present (user-created rows) (#115)
## [0.8.3] - 2026-04-19
### Added

View file

@ -114,10 +114,13 @@ pub fn delete_profile_db(app: tauri::AppHandle, db_filename: String) -> Result<(
#[tauri::command]
pub fn get_new_profile_init_sql() -> Result<Vec<String>, String> {
Ok(vec![
database::CONSOLIDATED_SCHEMA.to_string(),
database::SEED_CATEGORIES.to_string(),
])
// Brand-new profiles ship with the v1 IPC-aligned category taxonomy: the
// consolidated schema bakes the v1 seed (categories + keywords + the
// categories_schema_version='v1' preference) directly. The legacy v2 seed
// migration still runs first because tauri-plugin-sql applies every
// declared migration on `Database.load`; the consolidated script then
// deletes the v2 rows and re-inserts the v1 rows in the 1000+ id range.
Ok(vec![database::CONSOLIDATED_SCHEMA.to_string()])
}
// Argon2id parameters for PIN hashing (same as export_import_commands.rs)

View file

@ -1,6 +1,9 @@
-- Consolidated schema for new profile databases
-- This file bakes in the base schema + all migrations (v3-v6)
-- Used ONLY for initializing new profile databases (not for the default profile)
-- This file bakes in the base schema + all migrations (v3-v8) and pre-seeds
-- the v1 IPC-aligned category taxonomy so that brand-new profiles immediately
-- use the new standard. Existing profiles keep their v2 seed and are only
-- tagged via the migration (categories_schema_version = 'v2').
-- Used ONLY for initializing new profile databases (not for the default profile).
CREATE TABLE IF NOT EXISTS import_sources (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -39,6 +42,7 @@ CREATE TABLE IF NOT EXISTS categories (
is_active INTEGER NOT NULL DEFAULT 1,
is_inputable INTEGER NOT NULL DEFAULT 1,
sort_order INTEGER NOT NULL DEFAULT 0,
i18n_key TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL
);
@ -177,8 +181,477 @@ CREATE INDEX IF NOT EXISTS idx_budget_entries_period ON budget_entries(year, mon
CREATE INDEX IF NOT EXISTS idx_adjustment_entries_adjustment ON adjustment_entries(adjustment_id);
CREATE INDEX IF NOT EXISTS idx_imported_files_source ON imported_files(source_id);
-- Default preferences
-- Default preferences (new profiles ship with the v1 IPC taxonomy)
INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('language', 'fr');
INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('theme', 'light');
INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('currency', 'EUR');
INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('date_format', 'DD/MM/YYYY');
INSERT OR REPLACE INTO user_preferences (key, value) VALUES ('categories_schema_version', 'v1');
-- ============================================================================
-- Seed v1 — IPC Statistique Canada-aligned, 3 levels, Canada/Québec
-- ----------------------------------------------------------------------------
-- Reset any pre-existing category data (possible when tauri-plugin-sql runs
-- the historical v2 seed migration on this fresh DB before this script
-- executes). Keywords/categories are wiped and re-inserted with the v1 IDs
-- (1000+ range) so existing references in migrations v3-v7 stay inert.
-- ============================================================================
DELETE FROM keywords;
UPDATE transactions SET category_id = NULL;
DELETE FROM categories;
-- LEVEL 1 — Roots (9 IPC components + Revenus + Transferts)
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1000, 'Revenus', NULL, 'income', '#16a34a', 0, 1, 'categoriesSeed.revenus.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1100, 'Alimentation', NULL, 'expense', '#ea580c', 0, 2, 'categoriesSeed.alimentation.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1200, 'Logement', NULL, 'expense', '#dc2626', 0, 3, 'categoriesSeed.logement.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1300, 'Ménage & ameublement', NULL, 'expense', '#ca8a04', 0, 4, 'categoriesSeed.menage.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1400, 'Vêtements & chaussures', NULL, 'expense', '#d946ef', 0, 5, 'categoriesSeed.vetements.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1500, 'Transport', NULL, 'expense', '#2563eb', 0, 6, 'categoriesSeed.transport.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1600, 'Santé & soins personnels', NULL, 'expense', '#f43f5e', 0, 7, 'categoriesSeed.sante.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1700, 'Loisirs, formation & lecture', NULL, 'expense', '#8b5cf6', 0, 8, 'categoriesSeed.loisirs.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1800, 'Boissons, tabac & cannabis', NULL, 'expense', '#7c3aed', 0, 9, 'categoriesSeed.consommation.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1900, 'Finances & obligations', NULL, 'expense', '#6b7280', 0, 10, 'categoriesSeed.finances.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1950, 'Transferts & placements', NULL, 'transfer', '#0ea5e9', 0, 11, 'categoriesSeed.transferts.root');
-- 1000 — Revenus
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1010, 'Emploi', 1000, 'income', '#22c55e', 0, 1, 'categoriesSeed.revenus.emploi.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1011, 'Paie régulière', 1010, 'income', '#22c55e', 1, 1, 'categoriesSeed.revenus.emploi.paie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1012, 'Primes & bonus', 1010, 'income', '#4ade80', 1, 2, 'categoriesSeed.revenus.emploi.primes');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1013, 'Travail autonome', 1010, 'income', '#86efac', 1, 3, 'categoriesSeed.revenus.emploi.autonome');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1020, 'Gouvernemental', 1000, 'income', '#16a34a', 0, 2, 'categoriesSeed.revenus.gouvernemental.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1021, 'Remboursement impôt', 1020, 'income', '#16a34a', 1, 1, 'categoriesSeed.revenus.gouvernemental.remboursementImpot');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1022, 'Allocations familiales', 1020, 'income', '#15803d', 1, 2, 'categoriesSeed.revenus.gouvernemental.allocations');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1023, 'Crédits TPS/TVQ', 1020, 'income', '#166534', 1, 3, 'categoriesSeed.revenus.gouvernemental.credits');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1024, 'Assurance-emploi / RQAP', 1020, 'income', '#14532d', 1, 4, 'categoriesSeed.revenus.gouvernemental.assuranceEmploi');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1030, 'Revenus de placement', 1000, 'income', '#10b981', 0, 3, 'categoriesSeed.revenus.placement.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1031, 'Intérêts & dividendes', 1030, 'income', '#10b981', 1, 1, 'categoriesSeed.revenus.placement.interets');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1032, 'Gains en capital', 1030, 'income', '#059669', 1, 2, 'categoriesSeed.revenus.placement.capital');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1033, 'Revenus locatifs', 1030, 'income', '#047857', 1, 3, 'categoriesSeed.revenus.placement.locatifs');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1090, 'Autres revenus', 1000, 'income', '#84cc16', 1, 9, 'categoriesSeed.revenus.autres');
-- 1100 — Alimentation
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1110, 'Épicerie & marché', 1100, 'expense', '#ea580c', 0, 1, 'categoriesSeed.alimentation.epicerie.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1111, 'Épicerie régulière', 1110, 'expense', '#ea580c', 1, 1, 'categoriesSeed.alimentation.epicerie.reguliere');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1112, 'Boucherie & poissonnerie', 1110, 'expense', '#c2410c', 1, 2, 'categoriesSeed.alimentation.epicerie.boucherie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1113, 'Boulangerie & pâtisserie', 1110, 'expense', '#9a3412', 1, 3, 'categoriesSeed.alimentation.epicerie.boulangerie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1114, 'Dépanneur', 1110, 'expense', '#7c2d12', 1, 4, 'categoriesSeed.alimentation.epicerie.depanneur');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1115, 'Marché & produits spécialisés', 1110, 'expense', '#fb923c', 1, 5, 'categoriesSeed.alimentation.epicerie.marche');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1120, 'Restauration', 1100, 'expense', '#f97316', 0, 2, 'categoriesSeed.alimentation.restauration.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1121, 'Restaurant', 1120, 'expense', '#f97316', 1, 1, 'categoriesSeed.alimentation.restauration.restaurant');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1122, 'Café & boulangerie rapide', 1120, 'expense', '#fb923c', 1, 2, 'categoriesSeed.alimentation.restauration.cafe');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1123, 'Restauration rapide', 1120, 'expense', '#fdba74', 1, 3, 'categoriesSeed.alimentation.restauration.fastfood');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1124, 'Livraison à domicile', 1120, 'expense', '#fed7aa', 1, 4, 'categoriesSeed.alimentation.restauration.livraison');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1125, 'Cantine & cafétéria', 1120, 'expense', '#ffedd5', 1, 5, 'categoriesSeed.alimentation.restauration.cantine');
-- 1200 — Logement
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1210, 'Habitation principale', 1200, 'expense', '#dc2626', 0, 1, 'categoriesSeed.logement.habitation.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1211, 'Loyer', 1210, 'expense', '#dc2626', 1, 1, 'categoriesSeed.logement.habitation.loyer');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1212, 'Hypothèque', 1210, 'expense', '#b91c1c', 1, 2, 'categoriesSeed.logement.habitation.hypotheque');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1213, 'Taxes municipales & scolaires', 1210, 'expense', '#991b1b', 1, 3, 'categoriesSeed.logement.habitation.taxes');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1214, 'Charges de copropriété', 1210, 'expense', '#7f1d1d', 1, 4, 'categoriesSeed.logement.habitation.copropriete');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1220, 'Services publics', 1200, 'expense', '#ef4444', 0, 2, 'categoriesSeed.logement.services.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1221, 'Électricité', 1220, 'expense', '#ef4444', 1, 1, 'categoriesSeed.logement.services.electricite');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1222, 'Gaz naturel', 1220, 'expense', '#f87171', 1, 2, 'categoriesSeed.logement.services.gaz');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1223, 'Chauffage (mazout, propane)', 1220, 'expense', '#fca5a5', 1, 3, 'categoriesSeed.logement.services.chauffage');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1224, 'Eau & égouts', 1220, 'expense', '#fecaca', 1, 4, 'categoriesSeed.logement.services.eau');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1230, 'Communications', 1200, 'expense', '#6366f1', 0, 3, 'categoriesSeed.logement.communications.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1231, 'Internet résidentiel', 1230, 'expense', '#6366f1', 1, 1, 'categoriesSeed.logement.communications.internet');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1232, 'Téléphonie mobile', 1230, 'expense', '#818cf8', 1, 2, 'categoriesSeed.logement.communications.mobile');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1233, 'Téléphonie résidentielle', 1230, 'expense', '#a5b4fc', 1, 3, 'categoriesSeed.logement.communications.residentielle');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1234, 'Câblodistribution & streaming TV', 1230, 'expense', '#c7d2fe', 1, 4, 'categoriesSeed.logement.communications.streamingTv');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1240, 'Entretien & réparations', 1200, 'expense', '#e11d48', 0, 4, 'categoriesSeed.logement.entretien.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1241, 'Entretien général', 1240, 'expense', '#e11d48', 1, 1, 'categoriesSeed.logement.entretien.general');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1242, 'Rénovations', 1240, 'expense', '#be123c', 1, 2, 'categoriesSeed.logement.entretien.renovations');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1243, 'Matériaux & outils', 1240, 'expense', '#9f1239', 1, 3, 'categoriesSeed.logement.entretien.materiaux');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1244, 'Aménagement paysager', 1240, 'expense', '#881337', 1, 4, 'categoriesSeed.logement.entretien.paysager');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1250, 'Assurance habitation', 1200, 'expense', '#14b8a6', 1, 5, 'categoriesSeed.logement.assurance');
-- 1300 — Ménage & ameublement
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1310, 'Ameublement', 1300, 'expense', '#ca8a04', 0, 1, 'categoriesSeed.menage.ameublement.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1311, 'Meubles', 1310, 'expense', '#ca8a04', 1, 1, 'categoriesSeed.menage.ameublement.meubles');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1312, 'Électroménagers', 1310, 'expense', '#a16207', 1, 2, 'categoriesSeed.menage.ameublement.electromenagers');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1313, 'Décoration', 1310, 'expense', '#854d0e', 1, 3, 'categoriesSeed.menage.ameublement.decoration');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1320, 'Fournitures ménagères', 1300, 'expense', '#eab308', 0, 2, 'categoriesSeed.menage.fournitures.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1321, 'Produits d''entretien', 1320, 'expense', '#eab308', 1, 1, 'categoriesSeed.menage.fournitures.entretien');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1322, 'Literie & linge de maison', 1320, 'expense', '#facc15', 1, 2, 'categoriesSeed.menage.fournitures.literie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1323, 'Vaisselle & ustensiles', 1320, 'expense', '#fde047', 1, 3, 'categoriesSeed.menage.fournitures.vaisselle');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1330, 'Services domestiques', 1300, 'expense', '#fbbf24', 0, 3, 'categoriesSeed.menage.services.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1331, 'Ménage & nettoyage', 1330, 'expense', '#fbbf24', 1, 1, 'categoriesSeed.menage.services.nettoyage');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1332, 'Buanderie & pressing', 1330, 'expense', '#fcd34d', 1, 2, 'categoriesSeed.menage.services.buanderie');
-- 1400 — Vêtements & chaussures
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1410, 'Vêtements adultes', 1400, 'expense', '#d946ef', 1, 1, 'categoriesSeed.vetements.adultes');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1420, 'Vêtements enfants', 1400, 'expense', '#c026d3', 1, 2, 'categoriesSeed.vetements.enfants');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1430, 'Chaussures', 1400, 'expense', '#a21caf', 1, 3, 'categoriesSeed.vetements.chaussures');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1440, 'Accessoires & bijoux', 1400, 'expense', '#86198f', 1, 4, 'categoriesSeed.vetements.accessoires');
-- 1500 — Transport
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1510, 'Véhicule personnel', 1500, 'expense', '#2563eb', 0, 1, 'categoriesSeed.transport.vehicule.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1511, 'Achat / location véhicule', 1510, 'expense', '#2563eb', 1, 1, 'categoriesSeed.transport.vehicule.achat');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1512, 'Essence', 1510, 'expense', '#1d4ed8', 1, 2, 'categoriesSeed.transport.vehicule.essence');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1513, 'Entretien & réparations auto', 1510, 'expense', '#1e40af', 1, 3, 'categoriesSeed.transport.vehicule.entretien');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1514, 'Immatriculation & permis', 1510, 'expense', '#1e3a8a', 1, 4, 'categoriesSeed.transport.vehicule.immatriculation');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1515, 'Stationnement & péages', 1510, 'expense', '#3b82f6', 1, 5, 'categoriesSeed.transport.vehicule.stationnement');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1516, 'Assurance auto', 1510, 'expense', '#60a5fa', 1, 6, 'categoriesSeed.transport.vehicule.assurance');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1520, 'Transport public', 1500, 'expense', '#0ea5e9', 0, 2, 'categoriesSeed.transport.public.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1521, 'Autobus & métro', 1520, 'expense', '#0ea5e9', 1, 1, 'categoriesSeed.transport.public.autobus');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1522, 'Train de banlieue', 1520, 'expense', '#0284c7', 1, 2, 'categoriesSeed.transport.public.train');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1523, 'Taxi & covoiturage', 1520, 'expense', '#0369a1', 1, 3, 'categoriesSeed.transport.public.taxi');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1530, 'Voyages longue distance', 1500, 'expense', '#38bdf8', 0, 3, 'categoriesSeed.transport.voyages.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1531, 'Avion', 1530, 'expense', '#38bdf8', 1, 1, 'categoriesSeed.transport.voyages.avion');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1532, 'Train & autocar', 1530, 'expense', '#7dd3fc', 1, 2, 'categoriesSeed.transport.voyages.trainAutocar');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1533, 'Hébergement', 1530, 'expense', '#bae6fd', 1, 3, 'categoriesSeed.transport.voyages.hebergement');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1534, 'Location véhicule voyage', 1530, 'expense', '#e0f2fe', 1, 4, 'categoriesSeed.transport.voyages.location');
-- 1600 — Santé & soins personnels
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1610, 'Soins médicaux', 1600, 'expense', '#f43f5e', 0, 1, 'categoriesSeed.sante.medicaux.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1611, 'Pharmacie', 1610, 'expense', '#f43f5e', 1, 1, 'categoriesSeed.sante.medicaux.pharmacie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1612, 'Consultations médicales', 1610, 'expense', '#e11d48', 1, 2, 'categoriesSeed.sante.medicaux.consultations');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1613, 'Dentiste & orthodontiste', 1610, 'expense', '#be123c', 1, 3, 'categoriesSeed.sante.medicaux.dentiste');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1614, 'Optométrie & lunettes', 1610, 'expense', '#9f1239', 1, 4, 'categoriesSeed.sante.medicaux.optometrie');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1615, 'Thérapies (physio, psycho, etc.)', 1610, 'expense', '#881337', 1, 5, 'categoriesSeed.sante.medicaux.therapies');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1616, 'Assurance santé complémentaire', 1610, 'expense', '#fb7185', 1, 6, 'categoriesSeed.sante.medicaux.assurance');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1620, 'Soins personnels', 1600, 'expense', '#fb7185', 0, 2, 'categoriesSeed.sante.personnels.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1621, 'Coiffure & esthétique', 1620, 'expense', '#fb7185', 1, 1, 'categoriesSeed.sante.personnels.coiffure');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1622, 'Produits de soins corporels', 1620, 'expense', '#fda4af', 1, 2, 'categoriesSeed.sante.personnels.soins');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1630, 'Assurance vie & invalidité', 1600, 'expense', '#14b8a6', 1, 3, 'categoriesSeed.sante.assuranceVie');
-- 1700 — Loisirs, formation & lecture
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1710, 'Divertissement', 1700, 'expense', '#8b5cf6', 0, 1, 'categoriesSeed.loisirs.divertissement.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1711, 'Cinéma & spectacles', 1710, 'expense', '#8b5cf6', 1, 1, 'categoriesSeed.loisirs.divertissement.cinema');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1712, 'Jeux vidéo & consoles', 1710, 'expense', '#a78bfa', 1, 2, 'categoriesSeed.loisirs.divertissement.jeux');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1713, 'Streaming vidéo', 1710, 'expense', '#c4b5fd', 1, 3, 'categoriesSeed.loisirs.divertissement.streamingVideo');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1714, 'Streaming musique & audio', 1710, 'expense', '#ddd6fe', 1, 4, 'categoriesSeed.loisirs.divertissement.streamingMusique');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1715, 'Jouets & passe-temps', 1710, 'expense', '#ede9fe', 1, 5, 'categoriesSeed.loisirs.divertissement.jouets');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1720, 'Sports & plein air', 1700, 'expense', '#22c55e', 0, 2, 'categoriesSeed.loisirs.sports.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1721, 'Abonnements sportifs', 1720, 'expense', '#22c55e', 1, 1, 'categoriesSeed.loisirs.sports.abonnements');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1722, 'Équipement sportif', 1720, 'expense', '#4ade80', 1, 2, 'categoriesSeed.loisirs.sports.equipement');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1723, 'Parcs & activités plein air', 1720, 'expense', '#86efac', 1, 3, 'categoriesSeed.loisirs.sports.parcs');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1730, 'Formation & éducation', 1700, 'expense', '#6366f1', 0, 3, 'categoriesSeed.loisirs.formation.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1731, 'Scolarité (frais)', 1730, 'expense', '#6366f1', 1, 1, 'categoriesSeed.loisirs.formation.scolarite');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1732, 'Matériel scolaire', 1730, 'expense', '#818cf8', 1, 2, 'categoriesSeed.loisirs.formation.materiel');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1733, 'Cours & certifications', 1730, 'expense', '#a5b4fc', 1, 3, 'categoriesSeed.loisirs.formation.cours');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1734, 'Abonnements professionnels', 1730, 'expense', '#c7d2fe', 1, 4, 'categoriesSeed.loisirs.formation.abonnements');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1740, 'Lecture & médias', 1700, 'expense', '#ec4899', 0, 4, 'categoriesSeed.loisirs.lecture.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1741, 'Livres', 1740, 'expense', '#ec4899', 1, 1, 'categoriesSeed.loisirs.lecture.livres');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1742, 'Journaux & magazines', 1740, 'expense', '#f472b6', 1, 2, 'categoriesSeed.loisirs.lecture.journaux');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1750, 'Animaux de compagnie', 1700, 'expense', '#a855f7', 0, 5, 'categoriesSeed.loisirs.animaux.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1751, 'Nourriture & accessoires animaux', 1750, 'expense', '#a855f7', 1, 1, 'categoriesSeed.loisirs.animaux.nourriture');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1752, 'Vétérinaire', 1750, 'expense', '#c084fc', 1, 2, 'categoriesSeed.loisirs.animaux.veterinaire');
-- 1800 — Boissons, tabac & cannabis
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1810, 'Alcool (SAQ, microbrasseries)', 1800, 'expense', '#7c3aed', 1, 1, 'categoriesSeed.consommation.alcool');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1820, 'Cannabis (SQDC)', 1800, 'expense', '#6d28d9', 1, 2, 'categoriesSeed.consommation.cannabis');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1830, 'Tabac', 1800, 'expense', '#5b21b6', 1, 3, 'categoriesSeed.consommation.tabac');
-- 1900 — Finances & obligations
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1910, 'Frais bancaires', 1900, 'expense', '#6b7280', 0, 1, 'categoriesSeed.finances.fraisBancaires.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1911, 'Frais de compte', 1910, 'expense', '#6b7280', 1, 1, 'categoriesSeed.finances.fraisBancaires.compte');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1912, 'Intérêts & frais de crédit', 1910, 'expense', '#9ca3af', 1, 2, 'categoriesSeed.finances.fraisBancaires.interets');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1913, 'Frais de change', 1910, 'expense', '#d1d5db', 1, 3, 'categoriesSeed.finances.fraisBancaires.change');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1920, 'Impôts & taxes', 1900, 'expense', '#dc2626', 0, 2, 'categoriesSeed.finances.impots.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1921, 'Impôt fédéral', 1920, 'expense', '#dc2626', 1, 1, 'categoriesSeed.finances.impots.federal');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1922, 'Impôt provincial', 1920, 'expense', '#b91c1c', 1, 2, 'categoriesSeed.finances.impots.provincial');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1923, 'Acomptes provisionnels', 1920, 'expense', '#991b1b', 1, 3, 'categoriesSeed.finances.impots.acomptes');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1930, 'Dons & cotisations', 1900, 'expense', '#ec4899', 0, 3, 'categoriesSeed.finances.dons.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1931, 'Dons de charité', 1930, 'expense', '#ec4899', 1, 1, 'categoriesSeed.finances.dons.charite');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1932, 'Cotisations professionnelles', 1930, 'expense', '#f472b6', 1, 2, 'categoriesSeed.finances.dons.professionnelles');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1933, 'Cotisations syndicales', 1930, 'expense', '#f9a8d4', 1, 3, 'categoriesSeed.finances.dons.syndicales');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1940, 'Cadeaux', 1900, 'expense', '#f43f5e', 1, 4, 'categoriesSeed.finances.cadeaux');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1945, 'Retrait cash', 1900, 'expense', '#57534e', 1, 5, 'categoriesSeed.finances.cash');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1946, 'Achats divers non catégorisés', 1900, 'expense', '#78716c', 1, 6, 'categoriesSeed.finances.divers');
-- 1950 — Transferts & placements
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1960, 'Épargne & placements', 1950, 'transfer', '#0ea5e9', 0, 1, 'categoriesSeed.transferts.epargne.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1961, 'REER / RRSP', 1960, 'transfer', '#0ea5e9', 1, 1, 'categoriesSeed.transferts.epargne.reer');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1962, 'CELI / TFSA', 1960, 'transfer', '#0284c7', 1, 2, 'categoriesSeed.transferts.epargne.celi');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1963, 'REEE / RESP', 1960, 'transfer', '#0369a1', 1, 3, 'categoriesSeed.transferts.epargne.reee');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1964, 'Compte non-enregistré', 1960, 'transfer', '#075985', 1, 4, 'categoriesSeed.transferts.epargne.nonEnregistre');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1965, 'Fonds d''urgence', 1960, 'transfer', '#0c4a6e', 1, 5, 'categoriesSeed.transferts.epargne.urgence');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1970, 'Remboursement de dette', 1950, 'transfer', '#7c3aed', 0, 2, 'categoriesSeed.transferts.dette.root');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1971, 'Paiement carte crédit', 1970, 'transfer', '#7c3aed', 1, 1, 'categoriesSeed.transferts.dette.carteCredit');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1972, 'Remboursement prêt étudiant', 1970, 'transfer', '#8b5cf6', 1, 2, 'categoriesSeed.transferts.dette.etudiant');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1973, 'Remboursement prêt perso', 1970, 'transfer', '#a78bfa', 1, 3, 'categoriesSeed.transferts.dette.personnel');
INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1980, 'Transferts internes', 1950, 'transfer', '#64748b', 1, 3, 'categoriesSeed.transferts.internes');
-- ============================================================================
-- Keywords — Canadian suppliers (150+ entries)
-- ============================================================================
-- Alimentation > Épicerie régulière (1111)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('METRO', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('IGA', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MAXI', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUPER C', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LOBLAWS', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROVIGO', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ADONIS', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WHOLE FOODS', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AVRIL', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('RACHELLE-BERY', 1111, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('COSTCO', 1111, 50);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WALMART', 1111, 50);
-- Épicerie > Boucherie (1112)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOUCHERIE', 1112, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('POISSONNERIE', 1112, 0);
-- Épicerie > Boulangerie (1113)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOULANGERIE', 1113, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PATISSERIE', 1113, 0);
-- Épicerie > Dépanneur (1114)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('COUCHE-TARD', 1114, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DEPANNEUR', 1114, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('7-ELEVEN', 1114, 0);
-- Restauration > Restaurant (1121)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('RESTAURANT', 1121, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BRASSERIE', 1121, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BISTRO', 1121, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUSHI', 1121, 0);
-- Restauration > Café (1122)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('STARBUCKS', 1122, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TIM HORTONS', 1122, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SECOND CUP', 1122, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('VAN HOUTTE', 1122, 0);
-- Restauration > Fast food (1123)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MCDONALD', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUBWAY', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('A&W', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BURGER KING', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('KFC', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DOMINOS', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PIZZA HUT', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELLE PROVINCE', 1123, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ST-HUBERT', 1123, 0);
-- Restauration > Livraison (1124)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DOORDASH', 1124, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DD/DOORDASH', 1124, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('UBER EATS', 1124, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SKIPTHEDISHES', 1124, 0);
-- Logement > Hypothèque (1212)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MTG/HYP', 1212, 0);
-- Logement > Taxes municipales (1213)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('M-ST-HILAIRE TX', 1213, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXES MUNICIPALES', 1213, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CSS PATRIOT', 1213, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXE SCOLAIRE', 1213, 0);
-- Électricité (1221)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('HYDRO-QUEBEC', 1221, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('HYDRO QUEBEC', 1221, 0);
-- Gaz (1222)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ENERGIR', 1222, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GAZ METRO', 1222, 0);
-- Internet (1231)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('VIDEOTRON', 1231, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELL INTERNET', 1231, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ORICOM', 1231, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('COGECO', 1231, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('EBOX', 1231, 0);
-- Mobile (1232)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('FIZZ', 1232, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('KOODO', 1232, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PUBLIC MOBILE', 1232, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('VIRGIN', 1232, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELL MOBILITE', 1232, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TELUS MOBILE', 1232, 0);
-- Entretien maison (1241)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('IKEA', 1241, 0);
-- Matériaux & outils (1243)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CANADIAN TIRE', 1243, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CANAC', 1243, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('RONA', 1243, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('HOME DEPOT', 1243, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BMR', 1243, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRINCESS AUTO', 1243, 0);
-- Assurance habitation (1250)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELAIR', 1250, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRYSM', 1250, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('INTACT ASSURANCE', 1250, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DESJARDINS ASSURANCE', 1250, 0);
-- Meubles (1311)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TANGUAY', 1311, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEON', 1311, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('STRUCTUBE', 1311, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BRICK', 1311, 0);
-- Électroménagers (1312)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BEST BUY', 1312, 0);
-- Décoration (1313)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOUCLAIR', 1313, 0);
-- Vêtements (1410)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('UNIQLO', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WINNERS', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SIMONS', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MARKS', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('H&M', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('OLD NAVY', 1410, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GAP', 1410, 0);
-- Transport — Essence (1512)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SHELL', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ESSO', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ULTRAMAR', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PETRO-CANADA', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PETRO CANADA', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CREVIER', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('HARNOIS', 1512, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('COUCHE-TARD ESSENCE', 1512, 10);
-- Permis / SAAQ (1514)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SAAQ', 1514, 0);
-- Transport public — autobus/métro (1521)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('STM', 1521, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('RTC', 1521, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('STL', 1521, 0);
-- Train de banlieue (1522)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE MONT-SAINT', 1522, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE SAINT-HUBERT', 1522, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE CENTRALE', 1522, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('EXO', 1522, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('REM', 1522, 0);
-- Taxi / Uber (1523)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('UBER', 1523, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LYFT', 1523, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXI', 1523, 0);
-- Avion (1531)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIR CANADA', 1531, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WESTJET', 1531, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIR TRANSAT', 1531, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PORTER', 1531, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AEROPORTS DE MONTREAL', 1531, 0);
-- Hébergement (1533)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIRBNB', 1533, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('HILTON', 1533, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MARRIOTT', 1533, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOOKING.COM', 1533, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('NORWEGIAN CRUISE', 1533, 0);
-- Pharmacie (1611)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('JEAN COUTU', 1611, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('FAMILIPRIX', 1611, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PHARMAPRIX', 1611, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROXIM', 1611, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('UNIPRIX', 1611, 0);
-- Thérapies (1615)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PHYSIOACTIF', 1615, 0);
-- Cinéma & spectacles (1711)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CINEPLEX', 1711, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CINEMA DU PARC', 1711, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TICKETMASTER', 1711, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CLUB SODA', 1711, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEPOINTDEVENTE', 1711, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('EVENBRITE', 1711, 0);
-- Jeux vidéo (1712)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('STEAMGAMES', 1712, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PLAYSTATION', 1712, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('NINTENDO', 1712, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('XBOX', 1712, 0);
-- Streaming vidéo (1713)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('NETFLIX', 1713, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRIMEVIDEO', 1713, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DISNEY PLUS', 1713, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CRAVE', 1713, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('APPLE TV', 1713, 0);
-- Streaming musique (1714)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SPOTIFY', 1714, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('APPLE MUSIC', 1714, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('YOUTUBE MUSIC', 1714, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TIDAL', 1714, 0);
-- Jouets & hobbies (1715)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEGO', 1715, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('TOYS R US', 1715, 0);
-- Équipement sportif (1722)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MOUNTAIN EQUIPMENT', 1722, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('LA CORDEE', 1722, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DECATHLON', 1722, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SPORTS EXPERTS', 1722, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ATMOSPHERE', 1722, 0);
-- Parcs & activités (1723)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SEPAQ', 1723, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('BLOC SHOP', 1723, 0);
-- Lecture (1741)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('RENAUD-BRAY', 1741, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('INDIGO', 1741, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ARCHAMBAULT', 1741, 0);
-- Animaux — nourriture (1751)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('MONDOU', 1751, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PET SMART', 1751, 0);
-- Alcool (1810)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SAQ', 1810, 0);
-- Cannabis (1820)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('SQDC', 1820, 0);
-- Frais bancaires (1911)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROGRAMME PERFORMANCE', 1911, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('FRAIS MENSUELS', 1911, 0);
-- Impôts (1921, 1922)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('GOUV. QUEBEC', 1922, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('REVENU QUEBEC', 1922, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ARC IMPOT', 1921, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CRA TAX', 1921, 0);
-- Dons de charité (1931)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('OXFAM', 1931, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CENTRAIDE', 1931, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('FPA', 1931, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CROIX-ROUGE', 1931, 0);
-- Cotisations professionnelles (1932)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('ORDRE DES COMPTABL', 1932, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('CPA CANADA', 1932, 0);
-- Cadeaux (1940)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DANS UN JARDIN', 1940, 0);
-- Divers (1946) — catch-all marketplace
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AMAZON', 1946, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AMZN', 1946, 0);
-- Placements (1964)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WS INVESTMENTS', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('WEALTHSIMPLE', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PEAK INVESTMENT', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DYNAMIC FUND', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('FIDELITY', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('AGF', 1964, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('QUESTRADE', 1964, 0);
-- Paie (1011)
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PAY/PAY', 1011, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('DEPOT PAIE', 1011, 0);
INSERT INTO keywords (keyword, category_id, priority) VALUES ('PAYROLL', 1011, 0);

View file

@ -82,6 +82,19 @@ pub fn run() {
UPDATE keywords SET category_id = 312 WHERE keyword = 'INS/ASS' AND category_id = 31;",
kind: MigrationKind::Up,
},
// Migration v8 — additive: tag existing profiles with the v2 categories
// taxonomy and add a nullable i18n_key column on categories so the v1
// IPC seed (applied only to brand-new profiles via consolidated_schema)
// can store translation keys. Existing v2 profiles are untouched: the
// column defaults to NULL (falling back to the category's `name`) and
// the preference is a no-op INSERT OR IGNORE so re-runs are safe.
Migration {
version: 8,
description: "add i18n_key to categories and categories_schema_version preference",
sql: "ALTER TABLE categories ADD COLUMN i18n_key TEXT;
INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('categories_schema_version', 'v2');",
kind: MigrationKind::Up,
},
];
tauri::Builder::default()

View file

@ -129,7 +129,9 @@ function TreeRowContent({
className="w-3 h-3 rounded-full flex-shrink-0"
style={{ backgroundColor: node.color ?? "#9ca3af" }}
/>
<span className="flex-1 truncate">{node.name}</span>
<span className="flex-1 truncate">
{node.i18n_key ? t(node.i18n_key, { defaultValue: node.name }) : node.name}
</span>
<TypeBadge type={node.type} />
{node.keyword_count > 0 && (
<span className="text-[11px] text-[var(--muted-foreground)]">

View file

@ -1,4 +1,5 @@
import { useState, useRef, useEffect, useCallback, useId, useMemo } from "react";
import { useTranslation } from "react-i18next";
import type { Category } from "../../shared/types";
interface CategoryComboboxProps {
@ -54,6 +55,7 @@ export default function CategoryCombobox({
onExtraSelect,
activeExtra,
}: CategoryComboboxProps) {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [query, setQuery] = useState("");
const [highlightIndex, setHighlightIndex] = useState(0);
@ -66,15 +68,24 @@ export default function CategoryCombobox({
const depths = useMemo(() => computeDepths(categories), [categories]);
// Resolve the display name for a category: seed rows carry an i18n_key that
// we translate with name as defaultValue; user-created rows just use name.
const displayName = useCallback(
(c: Category) => (c.i18n_key ? t(c.i18n_key, { defaultValue: c.name }) : c.name),
[t]
);
const selectedCategory = categories.find((c) => c.id === value);
const displayLabel =
activeExtra != null
? extraOptions?.find((o) => o.value === activeExtra)?.label ?? ""
: selectedCategory?.name ?? "";
: selectedCategory
? displayName(selectedCategory)
: "";
const normalizedQuery = normalize(query);
const filtered = query
? categories.filter((c) => normalize(c.name).includes(normalizedQuery))
? categories.filter((c) => normalize(displayName(c)).includes(normalizedQuery))
: categories;
const filteredExtras = extraOptions
@ -228,7 +239,7 @@ export default function CategoryCombobox({
style={depth > 0 ? { paddingLeft: `calc(${compact ? "0.5rem" : "0.75rem"} + ${depth * 1}rem)` } : undefined}
>
<span className="whitespace-pre">{indent}</span>
{cat.name}
{displayName(cat)}
</li>
);
})}

View file

@ -0,0 +1,498 @@
{
"version": "v1",
"description": "IPC Statistique Canada-aligned category taxonomy, 3 levels, Canada/Québec. Derived from src-tauri/src/database/consolidated_schema.sql — keep the two in sync when rolling a new seed version.",
"roots": [
{
"id": 1000,
"name": "Revenus",
"i18n_key": "categoriesSeed.revenus.root",
"type": "income",
"color": "#16a34a",
"sort_order": 1,
"children": [
{
"id": 1010,
"name": "Emploi",
"i18n_key": "categoriesSeed.revenus.emploi.root",
"type": "income",
"color": "#22c55e",
"sort_order": 1,
"children": [
{ "id": 1011, "name": "Paie régulière", "i18n_key": "categoriesSeed.revenus.emploi.paie", "type": "income", "color": "#22c55e", "sort_order": 1, "children": [] },
{ "id": 1012, "name": "Primes & bonus", "i18n_key": "categoriesSeed.revenus.emploi.primes", "type": "income", "color": "#4ade80", "sort_order": 2, "children": [] },
{ "id": 1013, "name": "Travail autonome", "i18n_key": "categoriesSeed.revenus.emploi.autonome", "type": "income", "color": "#86efac", "sort_order": 3, "children": [] }
]
},
{
"id": 1020,
"name": "Gouvernemental",
"i18n_key": "categoriesSeed.revenus.gouvernemental.root",
"type": "income",
"color": "#16a34a",
"sort_order": 2,
"children": [
{ "id": 1021, "name": "Remboursement impôt", "i18n_key": "categoriesSeed.revenus.gouvernemental.remboursementImpot", "type": "income", "color": "#16a34a", "sort_order": 1, "children": [] },
{ "id": 1022, "name": "Allocations familiales", "i18n_key": "categoriesSeed.revenus.gouvernemental.allocations", "type": "income", "color": "#15803d", "sort_order": 2, "children": [] },
{ "id": 1023, "name": "Crédits TPS/TVQ", "i18n_key": "categoriesSeed.revenus.gouvernemental.credits", "type": "income", "color": "#166534", "sort_order": 3, "children": [] },
{ "id": 1024, "name": "Assurance-emploi / RQAP", "i18n_key": "categoriesSeed.revenus.gouvernemental.assuranceEmploi", "type": "income", "color": "#14532d", "sort_order": 4, "children": [] }
]
},
{
"id": 1030,
"name": "Revenus de placement",
"i18n_key": "categoriesSeed.revenus.placement.root",
"type": "income",
"color": "#10b981",
"sort_order": 3,
"children": [
{ "id": 1031, "name": "Intérêts & dividendes", "i18n_key": "categoriesSeed.revenus.placement.interets", "type": "income", "color": "#10b981", "sort_order": 1, "children": [] },
{ "id": 1032, "name": "Gains en capital", "i18n_key": "categoriesSeed.revenus.placement.capital", "type": "income", "color": "#059669", "sort_order": 2, "children": [] },
{ "id": 1033, "name": "Revenus locatifs", "i18n_key": "categoriesSeed.revenus.placement.locatifs", "type": "income", "color": "#047857", "sort_order": 3, "children": [] }
]
},
{ "id": 1090, "name": "Autres revenus", "i18n_key": "categoriesSeed.revenus.autres", "type": "income", "color": "#84cc16", "sort_order": 9, "children": [] }
]
},
{
"id": 1100,
"name": "Alimentation",
"i18n_key": "categoriesSeed.alimentation.root",
"type": "expense",
"color": "#ea580c",
"sort_order": 2,
"children": [
{
"id": 1110,
"name": "Épicerie & marché",
"i18n_key": "categoriesSeed.alimentation.epicerie.root",
"type": "expense",
"color": "#ea580c",
"sort_order": 1,
"children": [
{ "id": 1111, "name": "Épicerie régulière", "i18n_key": "categoriesSeed.alimentation.epicerie.reguliere", "type": "expense", "color": "#ea580c", "sort_order": 1, "children": [] },
{ "id": 1112, "name": "Boucherie & poissonnerie", "i18n_key": "categoriesSeed.alimentation.epicerie.boucherie", "type": "expense", "color": "#c2410c", "sort_order": 2, "children": [] },
{ "id": 1113, "name": "Boulangerie & pâtisserie", "i18n_key": "categoriesSeed.alimentation.epicerie.boulangerie", "type": "expense", "color": "#9a3412", "sort_order": 3, "children": [] },
{ "id": 1114, "name": "Dépanneur", "i18n_key": "categoriesSeed.alimentation.epicerie.depanneur", "type": "expense", "color": "#7c2d12", "sort_order": 4, "children": [] },
{ "id": 1115, "name": "Marché & produits spécialisés", "i18n_key": "categoriesSeed.alimentation.epicerie.marche", "type": "expense", "color": "#fb923c", "sort_order": 5, "children": [] }
]
},
{
"id": 1120,
"name": "Restauration",
"i18n_key": "categoriesSeed.alimentation.restauration.root",
"type": "expense",
"color": "#f97316",
"sort_order": 2,
"children": [
{ "id": 1121, "name": "Restaurant", "i18n_key": "categoriesSeed.alimentation.restauration.restaurant", "type": "expense", "color": "#f97316", "sort_order": 1, "children": [] },
{ "id": 1122, "name": "Café & boulangerie rapide", "i18n_key": "categoriesSeed.alimentation.restauration.cafe", "type": "expense", "color": "#fb923c", "sort_order": 2, "children": [] },
{ "id": 1123, "name": "Restauration rapide", "i18n_key": "categoriesSeed.alimentation.restauration.fastfood", "type": "expense", "color": "#fdba74", "sort_order": 3, "children": [] },
{ "id": 1124, "name": "Livraison à domicile", "i18n_key": "categoriesSeed.alimentation.restauration.livraison", "type": "expense", "color": "#fed7aa", "sort_order": 4, "children": [] },
{ "id": 1125, "name": "Cantine & cafétéria", "i18n_key": "categoriesSeed.alimentation.restauration.cantine", "type": "expense", "color": "#ffedd5", "sort_order": 5, "children": [] }
]
}
]
},
{
"id": 1200,
"name": "Logement",
"i18n_key": "categoriesSeed.logement.root",
"type": "expense",
"color": "#dc2626",
"sort_order": 3,
"children": [
{
"id": 1210,
"name": "Habitation principale",
"i18n_key": "categoriesSeed.logement.habitation.root",
"type": "expense",
"color": "#dc2626",
"sort_order": 1,
"children": [
{ "id": 1211, "name": "Loyer", "i18n_key": "categoriesSeed.logement.habitation.loyer", "type": "expense", "color": "#dc2626", "sort_order": 1, "children": [] },
{ "id": 1212, "name": "Hypothèque", "i18n_key": "categoriesSeed.logement.habitation.hypotheque", "type": "expense", "color": "#b91c1c", "sort_order": 2, "children": [] },
{ "id": 1213, "name": "Taxes municipales & scolaires", "i18n_key": "categoriesSeed.logement.habitation.taxes", "type": "expense", "color": "#991b1b", "sort_order": 3, "children": [] },
{ "id": 1214, "name": "Charges de copropriété", "i18n_key": "categoriesSeed.logement.habitation.copropriete", "type": "expense", "color": "#7f1d1d", "sort_order": 4, "children": [] }
]
},
{
"id": 1220,
"name": "Services publics",
"i18n_key": "categoriesSeed.logement.services.root",
"type": "expense",
"color": "#ef4444",
"sort_order": 2,
"children": [
{ "id": 1221, "name": "Électricité", "i18n_key": "categoriesSeed.logement.services.electricite", "type": "expense", "color": "#ef4444", "sort_order": 1, "children": [] },
{ "id": 1222, "name": "Gaz naturel", "i18n_key": "categoriesSeed.logement.services.gaz", "type": "expense", "color": "#f87171", "sort_order": 2, "children": [] },
{ "id": 1223, "name": "Chauffage (mazout, propane)", "i18n_key": "categoriesSeed.logement.services.chauffage", "type": "expense", "color": "#fca5a5", "sort_order": 3, "children": [] },
{ "id": 1224, "name": "Eau & égouts", "i18n_key": "categoriesSeed.logement.services.eau", "type": "expense", "color": "#fecaca", "sort_order": 4, "children": [] }
]
},
{
"id": 1230,
"name": "Communications",
"i18n_key": "categoriesSeed.logement.communications.root",
"type": "expense",
"color": "#6366f1",
"sort_order": 3,
"children": [
{ "id": 1231, "name": "Internet résidentiel", "i18n_key": "categoriesSeed.logement.communications.internet", "type": "expense", "color": "#6366f1", "sort_order": 1, "children": [] },
{ "id": 1232, "name": "Téléphonie mobile", "i18n_key": "categoriesSeed.logement.communications.mobile", "type": "expense", "color": "#818cf8", "sort_order": 2, "children": [] },
{ "id": 1233, "name": "Téléphonie résidentielle", "i18n_key": "categoriesSeed.logement.communications.residentielle", "type": "expense", "color": "#a5b4fc", "sort_order": 3, "children": [] },
{ "id": 1234, "name": "Câblodistribution & streaming TV", "i18n_key": "categoriesSeed.logement.communications.streamingTv", "type": "expense", "color": "#c7d2fe", "sort_order": 4, "children": [] }
]
},
{
"id": 1240,
"name": "Entretien & réparations",
"i18n_key": "categoriesSeed.logement.entretien.root",
"type": "expense",
"color": "#e11d48",
"sort_order": 4,
"children": [
{ "id": 1241, "name": "Entretien général", "i18n_key": "categoriesSeed.logement.entretien.general", "type": "expense", "color": "#e11d48", "sort_order": 1, "children": [] },
{ "id": 1242, "name": "Rénovations", "i18n_key": "categoriesSeed.logement.entretien.renovations", "type": "expense", "color": "#be123c", "sort_order": 2, "children": [] },
{ "id": 1243, "name": "Matériaux & outils", "i18n_key": "categoriesSeed.logement.entretien.materiaux", "type": "expense", "color": "#9f1239", "sort_order": 3, "children": [] },
{ "id": 1244, "name": "Aménagement paysager", "i18n_key": "categoriesSeed.logement.entretien.paysager", "type": "expense", "color": "#881337", "sort_order": 4, "children": [] }
]
},
{ "id": 1250, "name": "Assurance habitation", "i18n_key": "categoriesSeed.logement.assurance", "type": "expense", "color": "#14b8a6", "sort_order": 5, "children": [] }
]
},
{
"id": 1300,
"name": "Ménage & ameublement",
"i18n_key": "categoriesSeed.menage.root",
"type": "expense",
"color": "#ca8a04",
"sort_order": 4,
"children": [
{
"id": 1310,
"name": "Ameublement",
"i18n_key": "categoriesSeed.menage.ameublement.root",
"type": "expense",
"color": "#ca8a04",
"sort_order": 1,
"children": [
{ "id": 1311, "name": "Meubles", "i18n_key": "categoriesSeed.menage.ameublement.meubles", "type": "expense", "color": "#ca8a04", "sort_order": 1, "children": [] },
{ "id": 1312, "name": "Électroménagers", "i18n_key": "categoriesSeed.menage.ameublement.electromenagers", "type": "expense", "color": "#a16207", "sort_order": 2, "children": [] },
{ "id": 1313, "name": "Décoration", "i18n_key": "categoriesSeed.menage.ameublement.decoration", "type": "expense", "color": "#854d0e", "sort_order": 3, "children": [] }
]
},
{
"id": 1320,
"name": "Fournitures ménagères",
"i18n_key": "categoriesSeed.menage.fournitures.root",
"type": "expense",
"color": "#eab308",
"sort_order": 2,
"children": [
{ "id": 1321, "name": "Produits d'entretien", "i18n_key": "categoriesSeed.menage.fournitures.entretien", "type": "expense", "color": "#eab308", "sort_order": 1, "children": [] },
{ "id": 1322, "name": "Literie & linge de maison", "i18n_key": "categoriesSeed.menage.fournitures.literie", "type": "expense", "color": "#facc15", "sort_order": 2, "children": [] },
{ "id": 1323, "name": "Vaisselle & ustensiles", "i18n_key": "categoriesSeed.menage.fournitures.vaisselle", "type": "expense", "color": "#fde047", "sort_order": 3, "children": [] }
]
},
{
"id": 1330,
"name": "Services domestiques",
"i18n_key": "categoriesSeed.menage.services.root",
"type": "expense",
"color": "#fbbf24",
"sort_order": 3,
"children": [
{ "id": 1331, "name": "Ménage & nettoyage", "i18n_key": "categoriesSeed.menage.services.nettoyage", "type": "expense", "color": "#fbbf24", "sort_order": 1, "children": [] },
{ "id": 1332, "name": "Buanderie & pressing", "i18n_key": "categoriesSeed.menage.services.buanderie", "type": "expense", "color": "#fcd34d", "sort_order": 2, "children": [] }
]
}
]
},
{
"id": 1400,
"name": "Vêtements & chaussures",
"i18n_key": "categoriesSeed.vetements.root",
"type": "expense",
"color": "#d946ef",
"sort_order": 5,
"children": [
{ "id": 1410, "name": "Vêtements adultes", "i18n_key": "categoriesSeed.vetements.adultes", "type": "expense", "color": "#d946ef", "sort_order": 1, "children": [] },
{ "id": 1420, "name": "Vêtements enfants", "i18n_key": "categoriesSeed.vetements.enfants", "type": "expense", "color": "#c026d3", "sort_order": 2, "children": [] },
{ "id": 1430, "name": "Chaussures", "i18n_key": "categoriesSeed.vetements.chaussures", "type": "expense", "color": "#a21caf", "sort_order": 3, "children": [] },
{ "id": 1440, "name": "Accessoires & bijoux", "i18n_key": "categoriesSeed.vetements.accessoires", "type": "expense", "color": "#86198f", "sort_order": 4, "children": [] }
]
},
{
"id": 1500,
"name": "Transport",
"i18n_key": "categoriesSeed.transport.root",
"type": "expense",
"color": "#2563eb",
"sort_order": 6,
"children": [
{
"id": 1510,
"name": "Véhicule personnel",
"i18n_key": "categoriesSeed.transport.vehicule.root",
"type": "expense",
"color": "#2563eb",
"sort_order": 1,
"children": [
{ "id": 1511, "name": "Achat / location véhicule", "i18n_key": "categoriesSeed.transport.vehicule.achat", "type": "expense", "color": "#2563eb", "sort_order": 1, "children": [] },
{ "id": 1512, "name": "Essence", "i18n_key": "categoriesSeed.transport.vehicule.essence", "type": "expense", "color": "#1d4ed8", "sort_order": 2, "children": [] },
{ "id": 1513, "name": "Entretien & réparations auto", "i18n_key": "categoriesSeed.transport.vehicule.entretien", "type": "expense", "color": "#1e40af", "sort_order": 3, "children": [] },
{ "id": 1514, "name": "Immatriculation & permis", "i18n_key": "categoriesSeed.transport.vehicule.immatriculation", "type": "expense", "color": "#1e3a8a", "sort_order": 4, "children": [] },
{ "id": 1515, "name": "Stationnement & péages", "i18n_key": "categoriesSeed.transport.vehicule.stationnement", "type": "expense", "color": "#3b82f6", "sort_order": 5, "children": [] },
{ "id": 1516, "name": "Assurance auto", "i18n_key": "categoriesSeed.transport.vehicule.assurance", "type": "expense", "color": "#60a5fa", "sort_order": 6, "children": [] }
]
},
{
"id": 1520,
"name": "Transport public",
"i18n_key": "categoriesSeed.transport.public.root",
"type": "expense",
"color": "#0ea5e9",
"sort_order": 2,
"children": [
{ "id": 1521, "name": "Autobus & métro", "i18n_key": "categoriesSeed.transport.public.autobus", "type": "expense", "color": "#0ea5e9", "sort_order": 1, "children": [] },
{ "id": 1522, "name": "Train de banlieue", "i18n_key": "categoriesSeed.transport.public.train", "type": "expense", "color": "#0284c7", "sort_order": 2, "children": [] },
{ "id": 1523, "name": "Taxi & covoiturage", "i18n_key": "categoriesSeed.transport.public.taxi", "type": "expense", "color": "#0369a1", "sort_order": 3, "children": [] }
]
},
{
"id": 1530,
"name": "Voyages longue distance",
"i18n_key": "categoriesSeed.transport.voyages.root",
"type": "expense",
"color": "#38bdf8",
"sort_order": 3,
"children": [
{ "id": 1531, "name": "Avion", "i18n_key": "categoriesSeed.transport.voyages.avion", "type": "expense", "color": "#38bdf8", "sort_order": 1, "children": [] },
{ "id": 1532, "name": "Train & autocar", "i18n_key": "categoriesSeed.transport.voyages.trainAutocar", "type": "expense", "color": "#7dd3fc", "sort_order": 2, "children": [] },
{ "id": 1533, "name": "Hébergement", "i18n_key": "categoriesSeed.transport.voyages.hebergement", "type": "expense", "color": "#bae6fd", "sort_order": 3, "children": [] },
{ "id": 1534, "name": "Location véhicule voyage", "i18n_key": "categoriesSeed.transport.voyages.location", "type": "expense", "color": "#e0f2fe", "sort_order": 4, "children": [] }
]
}
]
},
{
"id": 1600,
"name": "Santé & soins personnels",
"i18n_key": "categoriesSeed.sante.root",
"type": "expense",
"color": "#f43f5e",
"sort_order": 7,
"children": [
{
"id": 1610,
"name": "Soins médicaux",
"i18n_key": "categoriesSeed.sante.medicaux.root",
"type": "expense",
"color": "#f43f5e",
"sort_order": 1,
"children": [
{ "id": 1611, "name": "Pharmacie", "i18n_key": "categoriesSeed.sante.medicaux.pharmacie", "type": "expense", "color": "#f43f5e", "sort_order": 1, "children": [] },
{ "id": 1612, "name": "Consultations médicales", "i18n_key": "categoriesSeed.sante.medicaux.consultations", "type": "expense", "color": "#e11d48", "sort_order": 2, "children": [] },
{ "id": 1613, "name": "Dentiste & orthodontiste", "i18n_key": "categoriesSeed.sante.medicaux.dentiste", "type": "expense", "color": "#be123c", "sort_order": 3, "children": [] },
{ "id": 1614, "name": "Optométrie & lunettes", "i18n_key": "categoriesSeed.sante.medicaux.optometrie", "type": "expense", "color": "#9f1239", "sort_order": 4, "children": [] },
{ "id": 1615, "name": "Thérapies (physio, psycho, etc.)", "i18n_key": "categoriesSeed.sante.medicaux.therapies", "type": "expense", "color": "#881337", "sort_order": 5, "children": [] },
{ "id": 1616, "name": "Assurance santé complémentaire", "i18n_key": "categoriesSeed.sante.medicaux.assurance", "type": "expense", "color": "#fb7185", "sort_order": 6, "children": [] }
]
},
{
"id": 1620,
"name": "Soins personnels",
"i18n_key": "categoriesSeed.sante.personnels.root",
"type": "expense",
"color": "#fb7185",
"sort_order": 2,
"children": [
{ "id": 1621, "name": "Coiffure & esthétique", "i18n_key": "categoriesSeed.sante.personnels.coiffure", "type": "expense", "color": "#fb7185", "sort_order": 1, "children": [] },
{ "id": 1622, "name": "Produits de soins corporels", "i18n_key": "categoriesSeed.sante.personnels.soins", "type": "expense", "color": "#fda4af", "sort_order": 2, "children": [] }
]
},
{ "id": 1630, "name": "Assurance vie & invalidité", "i18n_key": "categoriesSeed.sante.assuranceVie", "type": "expense", "color": "#14b8a6", "sort_order": 3, "children": [] }
]
},
{
"id": 1700,
"name": "Loisirs, formation & lecture",
"i18n_key": "categoriesSeed.loisirs.root",
"type": "expense",
"color": "#8b5cf6",
"sort_order": 8,
"children": [
{
"id": 1710,
"name": "Divertissement",
"i18n_key": "categoriesSeed.loisirs.divertissement.root",
"type": "expense",
"color": "#8b5cf6",
"sort_order": 1,
"children": [
{ "id": 1711, "name": "Cinéma & spectacles", "i18n_key": "categoriesSeed.loisirs.divertissement.cinema", "type": "expense", "color": "#8b5cf6", "sort_order": 1, "children": [] },
{ "id": 1712, "name": "Jeux vidéo & consoles", "i18n_key": "categoriesSeed.loisirs.divertissement.jeux", "type": "expense", "color": "#a78bfa", "sort_order": 2, "children": [] },
{ "id": 1713, "name": "Streaming vidéo", "i18n_key": "categoriesSeed.loisirs.divertissement.streamingVideo", "type": "expense", "color": "#c4b5fd", "sort_order": 3, "children": [] },
{ "id": 1714, "name": "Streaming musique & audio", "i18n_key": "categoriesSeed.loisirs.divertissement.streamingMusique", "type": "expense", "color": "#ddd6fe", "sort_order": 4, "children": [] },
{ "id": 1715, "name": "Jouets & passe-temps", "i18n_key": "categoriesSeed.loisirs.divertissement.jouets", "type": "expense", "color": "#ede9fe", "sort_order": 5, "children": [] }
]
},
{
"id": 1720,
"name": "Sports & plein air",
"i18n_key": "categoriesSeed.loisirs.sports.root",
"type": "expense",
"color": "#22c55e",
"sort_order": 2,
"children": [
{ "id": 1721, "name": "Abonnements sportifs", "i18n_key": "categoriesSeed.loisirs.sports.abonnements", "type": "expense", "color": "#22c55e", "sort_order": 1, "children": [] },
{ "id": 1722, "name": "Équipement sportif", "i18n_key": "categoriesSeed.loisirs.sports.equipement", "type": "expense", "color": "#4ade80", "sort_order": 2, "children": [] },
{ "id": 1723, "name": "Parcs & activités plein air", "i18n_key": "categoriesSeed.loisirs.sports.parcs", "type": "expense", "color": "#86efac", "sort_order": 3, "children": [] }
]
},
{
"id": 1730,
"name": "Formation & éducation",
"i18n_key": "categoriesSeed.loisirs.formation.root",
"type": "expense",
"color": "#6366f1",
"sort_order": 3,
"children": [
{ "id": 1731, "name": "Scolarité (frais)", "i18n_key": "categoriesSeed.loisirs.formation.scolarite", "type": "expense", "color": "#6366f1", "sort_order": 1, "children": [] },
{ "id": 1732, "name": "Matériel scolaire", "i18n_key": "categoriesSeed.loisirs.formation.materiel", "type": "expense", "color": "#818cf8", "sort_order": 2, "children": [] },
{ "id": 1733, "name": "Cours & certifications", "i18n_key": "categoriesSeed.loisirs.formation.cours", "type": "expense", "color": "#a5b4fc", "sort_order": 3, "children": [] },
{ "id": 1734, "name": "Abonnements professionnels", "i18n_key": "categoriesSeed.loisirs.formation.abonnements", "type": "expense", "color": "#c7d2fe", "sort_order": 4, "children": [] }
]
},
{
"id": 1740,
"name": "Lecture & médias",
"i18n_key": "categoriesSeed.loisirs.lecture.root",
"type": "expense",
"color": "#ec4899",
"sort_order": 4,
"children": [
{ "id": 1741, "name": "Livres", "i18n_key": "categoriesSeed.loisirs.lecture.livres", "type": "expense", "color": "#ec4899", "sort_order": 1, "children": [] },
{ "id": 1742, "name": "Journaux & magazines", "i18n_key": "categoriesSeed.loisirs.lecture.journaux", "type": "expense", "color": "#f472b6", "sort_order": 2, "children": [] }
]
},
{
"id": 1750,
"name": "Animaux de compagnie",
"i18n_key": "categoriesSeed.loisirs.animaux.root",
"type": "expense",
"color": "#a855f7",
"sort_order": 5,
"children": [
{ "id": 1751, "name": "Nourriture & accessoires animaux", "i18n_key": "categoriesSeed.loisirs.animaux.nourriture", "type": "expense", "color": "#a855f7", "sort_order": 1, "children": [] },
{ "id": 1752, "name": "Vétérinaire", "i18n_key": "categoriesSeed.loisirs.animaux.veterinaire", "type": "expense", "color": "#c084fc", "sort_order": 2, "children": [] }
]
}
]
},
{
"id": 1800,
"name": "Boissons, tabac & cannabis",
"i18n_key": "categoriesSeed.consommation.root",
"type": "expense",
"color": "#7c3aed",
"sort_order": 9,
"children": [
{ "id": 1810, "name": "Alcool (SAQ, microbrasseries)", "i18n_key": "categoriesSeed.consommation.alcool", "type": "expense", "color": "#7c3aed", "sort_order": 1, "children": [] },
{ "id": 1820, "name": "Cannabis (SQDC)", "i18n_key": "categoriesSeed.consommation.cannabis", "type": "expense", "color": "#6d28d9", "sort_order": 2, "children": [] },
{ "id": 1830, "name": "Tabac", "i18n_key": "categoriesSeed.consommation.tabac", "type": "expense", "color": "#5b21b6", "sort_order": 3, "children": [] }
]
},
{
"id": 1900,
"name": "Finances & obligations",
"i18n_key": "categoriesSeed.finances.root",
"type": "expense",
"color": "#6b7280",
"sort_order": 10,
"children": [
{
"id": 1910,
"name": "Frais bancaires",
"i18n_key": "categoriesSeed.finances.fraisBancaires.root",
"type": "expense",
"color": "#6b7280",
"sort_order": 1,
"children": [
{ "id": 1911, "name": "Frais de compte", "i18n_key": "categoriesSeed.finances.fraisBancaires.compte", "type": "expense", "color": "#6b7280", "sort_order": 1, "children": [] },
{ "id": 1912, "name": "Intérêts & frais de crédit", "i18n_key": "categoriesSeed.finances.fraisBancaires.interets", "type": "expense", "color": "#9ca3af", "sort_order": 2, "children": [] },
{ "id": 1913, "name": "Frais de change", "i18n_key": "categoriesSeed.finances.fraisBancaires.change", "type": "expense", "color": "#d1d5db", "sort_order": 3, "children": [] }
]
},
{
"id": 1920,
"name": "Impôts & taxes",
"i18n_key": "categoriesSeed.finances.impots.root",
"type": "expense",
"color": "#dc2626",
"sort_order": 2,
"children": [
{ "id": 1921, "name": "Impôt fédéral", "i18n_key": "categoriesSeed.finances.impots.federal", "type": "expense", "color": "#dc2626", "sort_order": 1, "children": [] },
{ "id": 1922, "name": "Impôt provincial", "i18n_key": "categoriesSeed.finances.impots.provincial", "type": "expense", "color": "#b91c1c", "sort_order": 2, "children": [] },
{ "id": 1923, "name": "Acomptes provisionnels", "i18n_key": "categoriesSeed.finances.impots.acomptes", "type": "expense", "color": "#991b1b", "sort_order": 3, "children": [] }
]
},
{
"id": 1930,
"name": "Dons & cotisations",
"i18n_key": "categoriesSeed.finances.dons.root",
"type": "expense",
"color": "#ec4899",
"sort_order": 3,
"children": [
{ "id": 1931, "name": "Dons de charité", "i18n_key": "categoriesSeed.finances.dons.charite", "type": "expense", "color": "#ec4899", "sort_order": 1, "children": [] },
{ "id": 1932, "name": "Cotisations professionnelles", "i18n_key": "categoriesSeed.finances.dons.professionnelles", "type": "expense", "color": "#f472b6", "sort_order": 2, "children": [] },
{ "id": 1933, "name": "Cotisations syndicales", "i18n_key": "categoriesSeed.finances.dons.syndicales", "type": "expense", "color": "#f9a8d4", "sort_order": 3, "children": [] }
]
},
{ "id": 1940, "name": "Cadeaux", "i18n_key": "categoriesSeed.finances.cadeaux", "type": "expense", "color": "#f43f5e", "sort_order": 4, "children": [] },
{ "id": 1945, "name": "Retrait cash", "i18n_key": "categoriesSeed.finances.cash", "type": "expense", "color": "#57534e", "sort_order": 5, "children": [] },
{ "id": 1946, "name": "Achats divers non catégorisés", "i18n_key": "categoriesSeed.finances.divers", "type": "expense", "color": "#78716c", "sort_order": 6, "children": [] }
]
},
{
"id": 1950,
"name": "Transferts & placements",
"i18n_key": "categoriesSeed.transferts.root",
"type": "transfer",
"color": "#0ea5e9",
"sort_order": 11,
"children": [
{
"id": 1960,
"name": "Épargne & placements",
"i18n_key": "categoriesSeed.transferts.epargne.root",
"type": "transfer",
"color": "#0ea5e9",
"sort_order": 1,
"children": [
{ "id": 1961, "name": "REER / RRSP", "i18n_key": "categoriesSeed.transferts.epargne.reer", "type": "transfer", "color": "#0ea5e9", "sort_order": 1, "children": [] },
{ "id": 1962, "name": "CELI / TFSA", "i18n_key": "categoriesSeed.transferts.epargne.celi", "type": "transfer", "color": "#0284c7", "sort_order": 2, "children": [] },
{ "id": 1963, "name": "REEE / RESP", "i18n_key": "categoriesSeed.transferts.epargne.reee", "type": "transfer", "color": "#0369a1", "sort_order": 3, "children": [] },
{ "id": 1964, "name": "Compte non-enregistré", "i18n_key": "categoriesSeed.transferts.epargne.nonEnregistre", "type": "transfer", "color": "#075985", "sort_order": 4, "children": [] },
{ "id": 1965, "name": "Fonds d'urgence", "i18n_key": "categoriesSeed.transferts.epargne.urgence", "type": "transfer", "color": "#0c4a6e", "sort_order": 5, "children": [] }
]
},
{
"id": 1970,
"name": "Remboursement de dette",
"i18n_key": "categoriesSeed.transferts.dette.root",
"type": "transfer",
"color": "#7c3aed",
"sort_order": 2,
"children": [
{ "id": 1971, "name": "Paiement carte crédit", "i18n_key": "categoriesSeed.transferts.dette.carteCredit", "type": "transfer", "color": "#7c3aed", "sort_order": 1, "children": [] },
{ "id": 1972, "name": "Remboursement prêt étudiant", "i18n_key": "categoriesSeed.transferts.dette.etudiant", "type": "transfer", "color": "#8b5cf6", "sort_order": 2, "children": [] },
{ "id": 1973, "name": "Remboursement prêt perso", "i18n_key": "categoriesSeed.transferts.dette.personnel", "type": "transfer", "color": "#a78bfa", "sort_order": 3, "children": [] }
]
},
{ "id": 1980, "name": "Transferts internes", "i18n_key": "categoriesSeed.transferts.internes", "type": "transfer", "color": "#64748b", "sort_order": 3, "children": [] }
]
}
]
}

View file

@ -1002,5 +1002,233 @@
"body": "Your feedback will be sent to feedback.lacompagniemaximus.com so we can improve the app. This requires an internet connection and is an exception to the app's 100% local operation.",
"accept": "I agree"
}
},
"categoriesSeed": {
"revenus": {
"root": "Income",
"emploi": {
"root": "Employment",
"paie": "Regular paycheque",
"primes": "Bonuses & premiums",
"autonome": "Self-employment"
},
"gouvernemental": {
"root": "Government",
"remboursementImpot": "Tax refund",
"allocations": "Family allowances",
"credits": "GST/QST credits",
"assuranceEmploi": "Employment insurance / QPIP"
},
"placement": {
"root": "Investment income",
"interets": "Interest & dividends",
"capital": "Capital gains",
"locatifs": "Rental income"
},
"autres": "Other income"
},
"alimentation": {
"root": "Food",
"epicerie": {
"root": "Groceries & markets",
"reguliere": "Regular groceries",
"boucherie": "Butcher & fishmonger",
"boulangerie": "Bakery & pastry",
"depanneur": "Convenience store",
"marche": "Markets & specialty food"
},
"restauration": {
"root": "Dining out",
"restaurant": "Restaurant",
"cafe": "Coffee shop & quick bakery",
"fastfood": "Fast food",
"livraison": "Home delivery",
"cantine": "Cafeteria"
}
},
"logement": {
"root": "Housing",
"habitation": {
"root": "Primary residence",
"loyer": "Rent",
"hypotheque": "Mortgage",
"taxes": "Municipal & school taxes",
"copropriete": "Condo fees"
},
"services": {
"root": "Utilities",
"electricite": "Electricity",
"gaz": "Natural gas",
"chauffage": "Heating (oil, propane)",
"eau": "Water & sewer"
},
"communications": {
"root": "Communications",
"internet": "Home internet",
"mobile": "Mobile phone",
"residentielle": "Landline phone",
"streamingTv": "Cable & TV streaming"
},
"entretien": {
"root": "Maintenance & repairs",
"general": "General maintenance",
"renovations": "Renovations",
"materiaux": "Materials & tools",
"paysager": "Landscaping"
},
"assurance": "Home insurance"
},
"menage": {
"root": "Household & furnishings",
"ameublement": {
"root": "Furnishings",
"meubles": "Furniture",
"electromenagers": "Appliances",
"decoration": "Decoration"
},
"fournitures": {
"root": "Household supplies",
"entretien": "Cleaning supplies",
"literie": "Bedding & linens",
"vaisselle": "Dishes & utensils"
},
"services": {
"root": "Domestic services",
"nettoyage": "Cleaning services",
"buanderie": "Laundry & dry cleaning"
}
},
"vetements": {
"root": "Clothing & footwear",
"adultes": "Adult clothing",
"enfants": "Children's clothing",
"chaussures": "Footwear",
"accessoires": "Accessories & jewelry"
},
"transport": {
"root": "Transportation",
"vehicule": {
"root": "Personal vehicle",
"achat": "Vehicle purchase / lease",
"essence": "Gasoline",
"entretien": "Auto maintenance & repairs",
"immatriculation": "Registration & licence",
"stationnement": "Parking & tolls",
"assurance": "Auto insurance"
},
"public": {
"root": "Public transit",
"autobus": "Bus & subway",
"train": "Commuter train",
"taxi": "Taxi & ride-sharing"
},
"voyages": {
"root": "Long-distance travel",
"avion": "Air travel",
"trainAutocar": "Train & coach",
"hebergement": "Lodging",
"location": "Travel car rental"
}
},
"sante": {
"root": "Health & personal care",
"medicaux": {
"root": "Medical care",
"pharmacie": "Pharmacy",
"consultations": "Medical consultations",
"dentiste": "Dentist & orthodontist",
"optometrie": "Optometry & eyewear",
"therapies": "Therapies (physio, psych, etc.)",
"assurance": "Supplemental health insurance"
},
"personnels": {
"root": "Personal care",
"coiffure": "Haircare & esthetics",
"soins": "Personal care products"
},
"assuranceVie": "Life & disability insurance"
},
"loisirs": {
"root": "Leisure, education & reading",
"divertissement": {
"root": "Entertainment",
"cinema": "Cinema & shows",
"jeux": "Video games & consoles",
"streamingVideo": "Video streaming",
"streamingMusique": "Music & audio streaming",
"jouets": "Toys & hobbies"
},
"sports": {
"root": "Sports & outdoors",
"abonnements": "Sports memberships",
"equipement": "Sports equipment",
"parcs": "Parks & outdoor activities"
},
"formation": {
"root": "Education & training",
"scolarite": "Tuition fees",
"materiel": "School supplies",
"cours": "Courses & certifications",
"abonnements": "Professional subscriptions"
},
"lecture": {
"root": "Reading & media",
"livres": "Books",
"journaux": "Newspapers & magazines"
},
"animaux": {
"root": "Pets",
"nourriture": "Pet food & supplies",
"veterinaire": "Veterinarian"
}
},
"consommation": {
"root": "Beverages, tobacco & cannabis",
"alcool": "Alcohol (SAQ, microbreweries)",
"cannabis": "Cannabis (SQDC)",
"tabac": "Tobacco"
},
"finances": {
"root": "Finances & obligations",
"fraisBancaires": {
"root": "Bank fees",
"compte": "Account fees",
"interets": "Interest & credit fees",
"change": "Currency exchange fees"
},
"impots": {
"root": "Taxes",
"federal": "Federal income tax",
"provincial": "Provincial income tax",
"acomptes": "Instalment payments"
},
"dons": {
"root": "Donations & dues",
"charite": "Charitable donations",
"professionnelles": "Professional dues",
"syndicales": "Union dues"
},
"cadeaux": "Gifts",
"cash": "Cash withdrawal",
"divers": "Miscellaneous uncategorized purchases"
},
"transferts": {
"root": "Transfers & investments",
"epargne": {
"root": "Savings & investments",
"reer": "RRSP",
"celi": "TFSA",
"reee": "RESP",
"nonEnregistre": "Non-registered account",
"urgence": "Emergency fund"
},
"dette": {
"root": "Debt repayment",
"carteCredit": "Credit card payment",
"etudiant": "Student loan repayment",
"personnel": "Personal loan repayment"
},
"internes": "Internal transfers"
}
}
}

View file

@ -1002,5 +1002,233 @@
"body": "Votre feedback sera envoyé à feedback.lacompagniemaximus.com pour que nous puissions améliorer l'application. Cette opération nécessite une connexion Internet et constitue une exception au fonctionnement 100 % local de l'application.",
"accept": "J'accepte"
}
},
"categoriesSeed": {
"revenus": {
"root": "Revenus",
"emploi": {
"root": "Emploi",
"paie": "Paie régulière",
"primes": "Primes & bonus",
"autonome": "Travail autonome"
},
"gouvernemental": {
"root": "Gouvernemental",
"remboursementImpot": "Remboursement impôt",
"allocations": "Allocations familiales",
"credits": "Crédits TPS/TVQ",
"assuranceEmploi": "Assurance-emploi / RQAP"
},
"placement": {
"root": "Revenus de placement",
"interets": "Intérêts & dividendes",
"capital": "Gains en capital",
"locatifs": "Revenus locatifs"
},
"autres": "Autres revenus"
},
"alimentation": {
"root": "Alimentation",
"epicerie": {
"root": "Épicerie & marché",
"reguliere": "Épicerie régulière",
"boucherie": "Boucherie & poissonnerie",
"boulangerie": "Boulangerie & pâtisserie",
"depanneur": "Dépanneur",
"marche": "Marché & produits spécialisés"
},
"restauration": {
"root": "Restauration",
"restaurant": "Restaurant",
"cafe": "Café & boulangerie rapide",
"fastfood": "Restauration rapide",
"livraison": "Livraison à domicile",
"cantine": "Cantine & cafétéria"
}
},
"logement": {
"root": "Logement",
"habitation": {
"root": "Habitation principale",
"loyer": "Loyer",
"hypotheque": "Hypothèque",
"taxes": "Taxes municipales & scolaires",
"copropriete": "Charges de copropriété"
},
"services": {
"root": "Services publics",
"electricite": "Électricité",
"gaz": "Gaz naturel",
"chauffage": "Chauffage (mazout, propane)",
"eau": "Eau & égouts"
},
"communications": {
"root": "Communications",
"internet": "Internet résidentiel",
"mobile": "Téléphonie mobile",
"residentielle": "Téléphonie résidentielle",
"streamingTv": "Câblodistribution & streaming TV"
},
"entretien": {
"root": "Entretien & réparations",
"general": "Entretien général",
"renovations": "Rénovations",
"materiaux": "Matériaux & outils",
"paysager": "Aménagement paysager"
},
"assurance": "Assurance habitation"
},
"menage": {
"root": "Ménage & ameublement",
"ameublement": {
"root": "Ameublement",
"meubles": "Meubles",
"electromenagers": "Électroménagers",
"decoration": "Décoration"
},
"fournitures": {
"root": "Fournitures ménagères",
"entretien": "Produits d'entretien",
"literie": "Literie & linge de maison",
"vaisselle": "Vaisselle & ustensiles"
},
"services": {
"root": "Services domestiques",
"nettoyage": "Ménage & nettoyage",
"buanderie": "Buanderie & pressing"
}
},
"vetements": {
"root": "Vêtements & chaussures",
"adultes": "Vêtements adultes",
"enfants": "Vêtements enfants",
"chaussures": "Chaussures",
"accessoires": "Accessoires & bijoux"
},
"transport": {
"root": "Transport",
"vehicule": {
"root": "Véhicule personnel",
"achat": "Achat / location véhicule",
"essence": "Essence",
"entretien": "Entretien & réparations auto",
"immatriculation": "Immatriculation & permis",
"stationnement": "Stationnement & péages",
"assurance": "Assurance auto"
},
"public": {
"root": "Transport public",
"autobus": "Autobus & métro",
"train": "Train de banlieue",
"taxi": "Taxi & covoiturage"
},
"voyages": {
"root": "Voyages longue distance",
"avion": "Avion",
"trainAutocar": "Train & autocar",
"hebergement": "Hébergement",
"location": "Location véhicule voyage"
}
},
"sante": {
"root": "Santé & soins personnels",
"medicaux": {
"root": "Soins médicaux",
"pharmacie": "Pharmacie",
"consultations": "Consultations médicales",
"dentiste": "Dentiste & orthodontiste",
"optometrie": "Optométrie & lunettes",
"therapies": "Thérapies (physio, psycho, etc.)",
"assurance": "Assurance santé complémentaire"
},
"personnels": {
"root": "Soins personnels",
"coiffure": "Coiffure & esthétique",
"soins": "Produits de soins corporels"
},
"assuranceVie": "Assurance vie & invalidité"
},
"loisirs": {
"root": "Loisirs, formation & lecture",
"divertissement": {
"root": "Divertissement",
"cinema": "Cinéma & spectacles",
"jeux": "Jeux vidéo & consoles",
"streamingVideo": "Streaming vidéo",
"streamingMusique": "Streaming musique & audio",
"jouets": "Jouets & passe-temps"
},
"sports": {
"root": "Sports & plein air",
"abonnements": "Abonnements sportifs",
"equipement": "Équipement sportif",
"parcs": "Parcs & activités plein air"
},
"formation": {
"root": "Formation & éducation",
"scolarite": "Scolarité (frais)",
"materiel": "Matériel scolaire",
"cours": "Cours & certifications",
"abonnements": "Abonnements professionnels"
},
"lecture": {
"root": "Lecture & médias",
"livres": "Livres",
"journaux": "Journaux & magazines"
},
"animaux": {
"root": "Animaux de compagnie",
"nourriture": "Nourriture & accessoires animaux",
"veterinaire": "Vétérinaire"
}
},
"consommation": {
"root": "Boissons, tabac & cannabis",
"alcool": "Alcool (SAQ, microbrasseries)",
"cannabis": "Cannabis (SQDC)",
"tabac": "Tabac"
},
"finances": {
"root": "Finances & obligations",
"fraisBancaires": {
"root": "Frais bancaires",
"compte": "Frais de compte",
"interets": "Intérêts & frais de crédit",
"change": "Frais de change"
},
"impots": {
"root": "Impôts & taxes",
"federal": "Impôt fédéral",
"provincial": "Impôt provincial",
"acomptes": "Acomptes provisionnels"
},
"dons": {
"root": "Dons & cotisations",
"charite": "Dons de charité",
"professionnelles": "Cotisations professionnelles",
"syndicales": "Cotisations syndicales"
},
"cadeaux": "Cadeaux",
"cash": "Retrait cash",
"divers": "Achats divers non catégorisés"
},
"transferts": {
"root": "Transferts & placements",
"epargne": {
"root": "Épargne & placements",
"reer": "REER",
"celi": "CELI",
"reee": "REEE",
"nonEnregistre": "Compte non-enregistré",
"urgence": "Fonds d'urgence"
},
"dette": {
"root": "Remboursement de dette",
"carteCredit": "Paiement carte crédit",
"etudiant": "Remboursement prêt étudiant",
"personnel": "Remboursement prêt perso"
},
"internes": "Transferts internes"
}
}
}

View file

@ -12,6 +12,7 @@ interface CategoryRow {
is_inputable: boolean;
sort_order: number;
keyword_count: number;
i18n_key: string | null;
}
export async function getAllCategoriesWithCounts(): Promise<CategoryRow[]> {

View file

@ -37,6 +37,13 @@ export interface Category {
is_active: boolean;
is_inputable: boolean;
sort_order: number;
/**
* Translation key into `src/i18n/locales/*.json` under `categoriesSeed.*`.
* Populated by the v1 IPC-aligned seed; NULL for user-created categories
* and for v2 seed rows on existing profiles. Renderers must fall back to
* `name` when absent.
*/
i18n_key?: string | null;
created_at: string;
}
@ -489,6 +496,7 @@ export interface CategoryTreeNode {
is_inputable: boolean;
sort_order: number;
keyword_count: number;
i18n_key: string | null;
children: CategoryTreeNode[];
}