feat(balance): data layer — vehicle_type + custom_label migrations, starters, service (#202)
Bilan axe véhicule (Étape 1) data foundation: separate the fiscal envelope
(now balance_accounts.vehicle_type) from the asset class (the category).
- Migration v12 (additive): add vehicle_type (fiscal enum, nullable) to
balance_accounts + custom_label to balance_categories; backfill the envelope
onto ex-tfsa/rrsp accounts (cash stays NULL); defensive recovery of any seed
i18n_key overwritten by free text (bug I).
- Migration v13 (reclass, conditional/idempotent): re-link ex-tfsa/rrsp accounts
to the `other` asset class and deactivate the two envelope seeds.
- consolidated_schema.sql: 2 new columns, 5 asset-class seeds (no tfsa/rrsp),
CELI/REER starters re-pointed to `other` + vehicle_type (avoids NULL FK).
- Types: BalanceVehicleType, custom_label / vehicle_type / category_custom_label.
- Service: normalizeVehicleType + vehicle_type_invalid; CRUD writes the new
columns; SELECT/JOINs read them back; STARTER_ACCOUNTS + proposeStarterAccounts
(is_active=1 + vehicle_type) + getStarterCollisions adjusted.
- Tests: Rust chain v9→v13 (snapshot_lines identical, transfers intact, archived
ex-tfsa covered, seeds deactivated, v13 EXISTS guard, idempotence, CHECK reject)
+ consolidated complete (5 categories, 4 starters, 0 NULL FK); TS service +
StarterAccountsModal specs. No diff to migrations <= v11.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>