Aller au contenu

Lemonway account / profile / wallet

Tables Kysely + Zod pour les entités Lemonway, en remplacement progressif du JSONB customers.lemonway / special_purpose_vehicule.json.lemonway.

État

Étape Statut
Schéma Flyway + Zod + repos CRUD Fait (Phase 0)
Dual-write SPV (create + sync v1/v2 + isBlocked) Fait — lectures restent sur SPV.json
Dual-write investisseur Pas en DB — customers.lemonway JSONB seulement
Backfill SPV oneshot Script scripts/lemonway/backfill-spv-lemonway-tables.script.ts
Switch lecture + purge JSON SPV Prochaine PR
Cutover lecture investisseur Hors scope
properties.lemonwayWalletId (option C) Hors scope

Hiérarchie

flowchart TD
  Account[lemonway_account]
  Profile[lemonway_profile]
  Wallet[lemonway_wallet]
  Account -->|"1-N (unique par type)"| Profile
  Profile -->|"0-N"| Wallet
Table Rôle PK
lemonway_account Compte Lemonway (identité INDIVIDUAL ou LEGAL_ENTITY) id_view (uuid, depuis json.id)
lemonway_profile Profil onboarding (PROJECT_HOLDER | LENDER) id_view
lemonway_wallet Wallet (statut KYC, IBAN virtuel optionnel) id_view (json.internalId)

Contraintes :

  • lemonway_profile : UNIQUE (lemonwayAccountId_view, type_view)
  • lemonway_wallet : UNIQUE (lemonwayExternalId_view)
  • lemonway_wallet.lemonwayProfileId optionnel — SPV onboarding v1 = wallet sans account/profile ; v2 = account + profile mandatory, wallet optionnel jusqu’à acceptation KYB
  • Cutover v1 → v2 : un même lemonway_account peut porter N SPV (plusieurs wallets PROJECT_HOLDER sur le compte Lemonway). Dual-write upsert le même account + le profile PROJECT_HOLDER unique ; chaque SPV garde son wallet. SPV.json.lemonway.account.id est alors partagé.

Migrations :

Lookups JSONB account.id / wallet.externalId (customers + SPV) : hors Flyway — à jouer en prod avant le merge — CREATE INDEX CONCURRENTLY.

Dual-write SPV

Orchestrateur : lemonway-tables-dual-write.service.ts

  • SpvLemonwayDualWriteService

Écrit les deux côtés dans la même safePgTransaction TypeORM :

  • insertSpvOnboardingV2 / updateSpvOnboardingV2 → special_purpose_vehicule + lemonway_account / profile / wallet
  • updateSpvWallet → SPV + wallet (v1 sync / isBlocked)
  • Admin editSPV ne touche pas lemonway (réécrit depuis la DB) — hors dual-write

Mapper LW → PgSchema : mappers/lemonway-pg.mapper.ts

Backfill oneshot (tables lemonway seules, sans toucher SPV.json) : scripts/lemonway/backfill-spv-lemonway-tables.script.ts — repos + mapper en Kysely (ky_safePgTransaction({ isDryRun })).

Lien SPV ↔ tables = IDs déjà dans SPV.json.lemonway (account.id, profile.id, wallet.internalId) — pas de colonnes FK physiques.

Repositories

Module Méthodes
Account insertOne, updateOne, upsertOne, upsertOneWithTypeorm, findById, getByIdAndLock
Profile idem + findByAccountId, findByAccountIdAndType, listWithNonTerminalStatus
Wallet idem + findByExternalId

Mutations Kysely : trx obligatoire (ky_safePgTransaction). Mutations TypeORM : transac: EntityManager pour dual-write depuis les flows SPV legacy.

Source API Lemonway

Liens