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.lemonwayProfileIdoptionnel — SPV onboarding v1 = wallet sans account/profile ; v2 = account + profile mandatory, wallet optionnel jusqu’à acceptation KYB- Cutover v1 → v2 : un même
lemonway_accountpeut porter N SPV (plusieurs walletsPROJECT_HOLDERsur le compte Lemonway). Dual-writeupsertle même account + le profilePROJECT_HOLDERunique ; chaque SPV garde son wallet.SPV.json.lemonway.account.idest alors partagé.
Migrations :
V202608020740__create-lemonway-account-and-wallet.sqlV202608091030__lemonway-wallet-profile-id-nullable.sql
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/walletupdateSpvWallet→ SPV + wallet (v1 sync / isBlocked)- Admin
editSPVne touche paslemonway(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¶
onboarding.get-account.endpoint.ts— account + profiles (identité complète pourlemonway_account.json)- Wallet legacy v2 API :
getAccount(externalId / spvId)
Liens¶
- P2P : lemonway-p2p
- Recertif KYC (notif 53/54) et source
manual(script Excel + relance BO Technique) : kyc-update-webhooks.md - Enregistrement tables :
database.ts