Toutes les améliorations

Chaque semaine, la plateforme s'enrichit de nouvelles fonctionnalités, d'améliorations d'ergonomie et de corrections d'incidents. Voici l'historique complet.

Récemment livré

Ajouté (super-admin)

  • Monitoring & incidents centralisés : nouvelle page /super-admin/monitoring — santé infra (latence DB), tableau par institution (users actifs, dernière connexion, activité 7j, notifications échouées 7j). Sur la fiche tenant, carte « Activity & incidents » : notifications en échec (canal, template, destinataire, erreur) + 25 derniers événements d'audit. Endpoints GET /v1/super-admin/monitoring/health et GET /v1/super-admin/tenants/:id/activity (agrégation cross-schéma défensive, cache 30 s).
  • Feature flags par tenant : le super-admin active/désactive des fonctionnalités par institution (Mobile Money, reporting réglementaire, portail membre, agent terrain, webhooks). Colonne Tenant.features (JSONB, migration 2026-07-05-tenant-features.sql). Enforcement backend via @RequiresFeature(...) + FeatureGuard global : les endpoints d'une fonctionnalité désactivée renvoient 403. Toggles dans la console super-admin (fiche tenant → Features), effet immédiat (invalidation du cache tenant). Défaut : tout activé (rétro-compat, features = null).
  • Gestion des comptes utilisateurs d'un tenant depuis la console super-admin (fiche tenant → « Back-office accounts ») :
    • Lister les users back-office d'une institution (rôle, statut, 2FA, dernière connexion)
    • Réinitialiser le mot de passe d'un user → mdp temporaire généré (10 caractères lisibles) + mustChangePassword forcé, retourné une fois
    • Activer / désactiver un compte (garde-fou : impossible de désactiver le dernier DIRECTOR actif)
    • Désactiver le 2FA d'un user (dépannage perte de device TOTP)
    • Endpoints GET/POST /v1/super-admin/tenants/:id/users*, toutes les actions sensibles auditées (SuperAdminAuditLog).

Corrections

  • Super-admin — déconnexion au clic sur un tenant : le layout redirigeait vers /super-admin/login pendant la réhydratation du store persistant (le token était momentanément null), éjectant l'opérateur dès qu'une page chargeait « en dur » (deep link /tenants/:id, rechargement). Ajout d'un flag _hasHydrated (onRehydrateStorage) : la redirection n'est décidée qu'une fois le localStorage lu.
  • Super-admin — tables manquantes en prod : public."SuperAdmin" / public."SuperAdminAuditLog" n'avaient jamais été créées (modèle ajouté après le bootstrap initial, db:push non rejoué). Migration 2026-06-24-super-admin-tables.sql ajoutée (idempotente).

Site public

  • Refonte de la home kairos-mfi.com — contenu passé d'un ton technique (SaaS, multi-tenant, PostgreSQL) à un ton descriptif orienté bénéfices utilisateur : « Vos membres reprennent le contrôle de leur épargne », « Vos agents rentrent le soir avec des chiffres, pas des feuilles volantes », etc.
  • Illustration animée dans le hero : téléphone stylisé montrant l'app membre (solde, transactions, échéance) + badges flottants (notification push, résumé "Ma journée" agent). Animations CSS pures (float, fade-slide, pop-in) — respecte prefers-reduced-motion.
  • Bibliothèque d'icônes SVG inline (landing/svg-icons.mjs) — 16 illustrations sur mesure (smartphone, agent, ledger, chart, etc.). Pas de dépendance externe, teinte pilotée par currentColor.
  • Nouvelles sections : "Pour chaque personne dans votre institution" (6 personas), "Comment ça se passe" (4 étapes de mise en route), "Améliorations en continu" (dernière version du changelog en preview), CTA final ("Demander une démo").
  • Scroll reveal via IntersectionObserver inline (~15 lignes JS, pas de lib externe).
  • landing/hero.md, landing/highlights.md, landing/personas.md restent éditables — le script build-landing.mjs extrait les sections et assemble le HTML.

Site public

  • Landing kairos-mfi.com : site statique généré automatiquement à partir de landing/hero.md, landing/highlights.md, CHANGELOG.md, docs/manuels/*.md et docs/modules/*.md. HTML/CSS minimal (~140 KB total), pas de framework, build < 100ms.
  • Pages : / (landing marketing avec features + dernières évolutions), /docs/ (index manuels + modules), /changelog.html (historique complet), un fichier HTML par manuel et par module.
  • Le build est intégré à scripts/deploy.sh : node scripts/build-landing.mjs tourne avant le docker compose up.
  • CTAs landing → app.kairos-mfi.com (espace pro) et app.kairos-mfi.com/portal (espace membre). Sous-domaine app. à créer en infra (cf. CHANGELOG ci-dessous).

Sur le terrain

  • Décaissement de crédit en tournée : nouvel endpoint POST /v1/field-agent/loan-disbursement (rôles FIELD_AGENT, DIRECTOR). L'agent livre du cash au membre directement chez lui pour un prêt préalablement APPROVED par un DIRECTOR ou CREDIT_MANAGER. Sépération des pouvoirs : l'agent ne décide pas, il livre.
  • Délègue toute la logique métier (échéancier, écritures comptables OHADA, passage à ACTIVE, SMS, push, webhook LOAN_DISBURSED) à LoansService.disburse() en mode "cash direct" (toAccountId: undefined). Ajoute juste un audit log field-agent.loan-disbursement tagué canal terrain.
  • GET /v1/field-agent/my-day retourne désormais aussi totalDisbursement (cash sorti vers les membres) en plus de totalDeposit et totalRepayment (cash collecté).
  • Mobile agent : bouton « Décaisser crédit » sur la fiche membre (visible si au moins un prêt en statut APPROVED). Sheet de confirmation affichant le montant approuvé (non modifiable), champ notes libres. Liste « Crédits à décaisser » en bandeau jaune sur la fiche pour signaler la tâche.

Nouveautés

  • Push notifications FCM : intégration Firebase Cloud Messaging v1 côté backend (provider OAuth2 service account, fallback Expo Push préservé pour clients RN/Expo). Câblage automatique sur dépôt / retrait / remboursement / décaissement / rappels d'échéance (cron). Module mobile : firebase_messaging + register au login, unregister au logout, SnackBar foreground, notif système background.
  • Mobile agent — Création de membre : formulaire simplifié (FAB sur liste membres) → POST /v1/members → membre PENDING en attente de validation KYC.
  • Mobile agent — Dépôt cash + remboursement crédit en tournée : bottom sheet sur la fiche membre, opérations sans session caisse, SMS de confirmation au membre.
  • Mobile agent — Carte « Ma journée » : résumé temps réel des opérations collectées (GET /v1/field-agent/my-day).
  • Mobile membre — Détail compte + transactions paginées : tap sur un compte → historique avec scroll infini.
  • Mobile membre — Détail crédit + échéancier : statut, prochaine échéance, retards.
  • Mobile membre — Change-password depuis le profil.
  • Mobile membre — Mot de passe oublié par SMS OTP (flow 2 étapes).
  • Web back-office — Bouton « Activer / Réinitialiser portail » sur la fiche membre (DIRECTOR, CREDIT_MANAGER, FIELD_AGENT). Génère un mot de passe temporaire 10 caractères lisibles si body vide.
  • Backend — Module FieldAgent : 3 endpoints (POST /v1/field-agent/cash-deposit, POST /v1/field-agent/loan-repayment, GET /v1/field-agent/my-day) — opérations cash en tournée hors session caisse.
  • Backend — Reset mot de passe portail membre par SMS OTP : POST /v1/portal/auth/password-reset/{request,confirm} (réutilise l'infrastructure OtpCode existante).

Améliorations

  • TenantMiddleware : le bypass de résolution tenant pour /portal/* matche maintenant strictement /v1/portal/ au lieu de toute URL contenant /portal/. Corrige le 500 Cannot read properties of undefined (reading 'schema') qui survenait sur POST /v1/members/:id/portal/enable.
  • POST /v1/members/:id/portal/enable autorise désormais FIELD_AGENT (DIRECTOR, CREDIT_MANAGER, FIELD_AGENT). Body vide → génère un mot de passe temporaire et le retourne (temporaryPassword).

Corrections

  • Mobile : login membre lisait data['token'] (n'existait pas) au lieu de data['accessToken']. Provoquait un crash type 'Null' is not a subtype of type 'String'.
  • Mobile : les Decimal Prisma arrivent en string ; parseAmount() helper ajouté pour parser robustement (num ou string).
  • Mobile : /portal/accounts et /portal/loans renvoient { items: [...] }, pas une List directe.
  • Mobile agent : la fiche membre tentait d'appeler /members/:id/accounts qui n'existe pas. Comptes et crédits sont désormais extraits directement de GET /v1/members/:id (déjà inclus via include).
  • Hostinger SMTP : .env.prod exposait SMTP_PASSWORD alors que SmtpEmailProvider lit SMTP_PASS. Renommé pour rétablir l'envoi d'emails (KYC, invitations).

Versions antérieures

Les évolutions livrées avant la mise en place de ce changelog sont listées dans les manuels par rôle (docs/manuels/) et dans les docs techniques par module (docs/modules/).