| Entreprise | Plan | Provision | Bons actifs | Statut |
|---|---|---|---|---|
| Sonatel SA | Premium | 12 400 000 F | 342 | ● Actif |
| Auchan Sénégal | Standard | 5 200 000 F | 128 | ● Actif |
| CDE BTP | Standard | 800 000 F | 45 | ● KYB en cours |
kado est une plateforme PWA de chèques cadeaux digitaux conçue pour le Sénégal et l'UEMOA. Elle permet aux entreprises d'émettre des bons dématérialisés à leurs employés, qui les utilisent chez des commerçants partenaires via un simple QR code — sans application à télécharger, sans carte bancaire, sans espèces.
| Source de revenus | Mécanisme | Taux | Exemple |
|---|---|---|---|
| Commission transaction | Prélevée sur chaque validation QR | 2% du montant | Bon 10 000 FCFA → 200 FCFA commission kado |
| Abonnement SaaS | Abonnement mensuel par entreprise | 30 000 FCFA / mois (Standard) 60 000 FCFA / mois (Premium) |
5 entreprises × 30 000 = 150 000 FCFA/mois |
| Soldes expirés | Bons non utilisés à expiration (J+180) | 100% du solde restant | Résiduel, non planifié |
| Composant | Technologie | Hébergement | Rôle |
|---|---|---|---|
| API Backend | NestJS 10 · TypeScript · Prisma 5 | Railway | Logique métier, auth, paiements |
| Frontend Web | Next.js 15 · React 19 · PWA | Vercel | Toutes les interfaces utilisateur |
| Base de données | PostgreSQL 16 | Railway | Données persistantes, ledger |
| Cache / Queues | Redis 7 · Bull | Railway | OTP, sessions, jobs asynchrones |
| SMS | Nexah (principal) · Twilio (fallback) | Cloud | OTP, notifications bons |
| Paiements | Wave Mobile Money · Orange Money | Cloud | Approvisionnement + reversements |
| Monitoring | Sentry | Cloud | Alertes erreurs production |
Le bénéficiaire se connecte via son numéro de téléphone sénégalais (+221). Un code à 6 chiffres est envoyé par SMS, valable 5 minutes. Après 3 échecs consécutifs, le compte est bloqué 30 minutes.
La page principale affiche le solde total disponible en FCFA et la liste des bons actifs avec leur statut. 4 onglets permettent d'accéder aux offres flash, commerçants proches et programme fidélité.
| Fonctionnalité | Description | Route |
|---|---|---|
| Authentification OTP | Connexion par SMS, code 6 chiffres, TTL 5 min | /app/login |
| Portefeuille | Solde total, liste bons actifs/expirés/utilisés, animation count-up | /app/wallet |
| QR Code plein écran | Affichage QR avec timer expiration, Screen Wake Lock (écran allumé), mode offline | /app/wallet/[id] |
| Historique transactions | Toutes les validations d'un bon avec date/commerçant/montant | /app/wallet/[id]/history |
| Paiement direct | Payer un commerçant par montant libre sur un bon sélectionné | /app/pay |
| Scanner QR commerçant | Scanner le QR d'un commerçant pour initier un paiement | /app/scan |
| Offres flash | Promotions limitées dans le temps par les commerçants proches | Onglet Wallet |
| Commerçants proches | Carte des partenaires kado avec géolocalisation | Onglet Wallet |
| Programme fidélité | Points accumulés par commerçant, solde et historique | Onglet Wallet |
| Activation invitation | Premier accès via lien SMS envoyé par l'entreprise | /join/[token] |
| Fonctionnalité | Description | Détail |
|---|---|---|
| Connexion sécurisée | JWT + PIN ou OTP SMS selon le rôle | Rôles COMPANY_ADMIN / COMPANY_VIEWER |
| Tableau de bord | KPIs en temps réel : provision, bons émis, consommé | Mise à jour automatique |
| Émission unitaire | Un bon à la fois pour un bénéficiaire | Notification SMS automatique au bénéficiaire |
| Import CSV | Jusqu'à 500 collaborateurs en une opération | Rapport d'erreurs ligne par ligne |
| Émission programmée | Planifier l'émission à une date future (scheduledAt) | Cron job d'émission automatique |
| Gestion collaborateurs | Liste des invitations envoyées et leur statut | PENDING / ACCEPTED / EXPIRED |
| Annulation de bon | Annuler un bon non encore utilisé → remboursement provision | Écriture ledger CANCEL |
| Suivi consommation | Quel commerçant, quel bénéficiaire, quel montant | Données anonymisées (RGPD) |
| Rapport RSE / Impact | Commerçants locaux soutenus, bénéficiaires uniques, montant total | Onglet Impact social |
| Gestion trésorerie | Historique des approvisionnements, solde disponible | Wave + OM + virement + chèque |
/app/scan) — caméra active immédiatement, sans menu intermédiaire.Le commerçant peut consulter ses transactions du jour, son chiffre d'affaires et l'historique de ses reversements Wave/Orange Money.
| Fonctionnalité | Description | Détail |
|---|---|---|
| Saisie montant (pavé) | Clavier numérique dédié, max 1 000 000 FCFA | Validation en centimes côté API |
| QR de paiement commerçant | POS génère un QR que le bénéficiaire scanne avec son app kado (/app/scan) | TTL 3 min, polling statut |
| Scanner QR bénéficiaire (optionnel) | Mode alternatif : le commerçant scanne le QR affiché sur l'app du client | ZXing library, front/back camera |
| Confirmation animée | Fond vert, vibration, son — retour sensoriel fort | navigator.vibrate([200]) |
| Dashboard revenus | CA du jour, net après commission, nb transactions | Mise à jour en temps réel |
| Historique reversements | Liste des virements Wave/OM avec référence | Référence SETTLE-{id}-{date} |
| Connexion PIN | Code PIN 4 chiffres pour sécuriser le terminal | bcrypt hash en DB |
| Entreprise | Plan | Provision | Bons actifs | Statut |
|---|---|---|---|---|
| Sonatel SA | Premium | 12 400 000 F | 342 | ● Actif |
| Auchan Sénégal | Standard | 5 200 000 F | 128 | ● Actif |
| CDE BTP | Standard | 800 000 F | 45 | ● KYB en cours |
| Fonctionnalité | Description |
|---|---|
| KPIs temps réel | Volume total, bons actifs/expirés, commissions du mois, nb entreprises et commerçants |
| Gestion entreprises | Liste, activation KYB, modification plan SaaS, historique provisions |
| Gestion commerçants | Activation, suspension, catégorie, géolocalisation, historique transactions |
| Supervision bons | Recherche par code/bénéficiaire, détail cycle de vie, annulation manuelle |
| Trésorerie kado | Revenus commissions + SaaS, solde, historique 6 mois, graphiques |
| Ledger comptable | Journal INSERT ONLY, toutes les écritures, vérification invariant débit=crédit |
| Pipeline leads | Entreprises et commerçants prospects, statut NOUVEAU→SIGNÉ, notes de suivi |
| Génération documents | Rapports PDF (CA, reversements, provisions), export CSV |
| Alertes fraude | Détection patterns suspects : validations exactes, pics volume +300%, répétitions |
/auth/otp/send, /auth/otp/verify et /health nécessitent un header Authorization: Bearer {access_token}.{"phone": "+221771234567"}{"phone": "...", "code": "123456"}{accessToken, refreshToken, user}{"refreshToken": "family.token"}{"merchantId": "...", "amount": 850000} (centimes). Transaction atomique avec SELECT FOR UPDATE.{"phone": "...", "amountCentimes": 2500000, "type": "MEAL_TICKET", "note": "..."}{"amountCentimes": 850000}. TTL 3 min.x-wave-signature{"status":"ok","checks":{"database":"ok","redis":"ok"},"timestamp":"..."}| Token | TTL | Contenu | Stockage |
|---|---|---|---|
| Access Token | 15 minutes | sub, role, phone, companyId | Mémoire JS (jamais localStorage) |
| Refresh Token | 30 jours | Famille + token aléatoire | DB (hashé SHA-256) |
| Usage | Mécanisme | Vérification |
|---|---|---|
| QR codes bons | Payload JSON signé avec HMAC_VOUCHER_SECRET | timingSafeEqual (anti timing attack) |
| Webhooks Wave | Corps HTTP signé avec WAVE_WEBHOOK_SECRET | timingSafeEqual |
| Webhooks Orange Money | Corps HTTP signé avec OM_WEBHOOK_SECRET | timingSafeEqual |
| Protection | Implémentation | Valeur |
|---|---|---|
| Rate limiting global | ThrottlerGuard (NestJS) | 100 req/min par IP |
| Rate limiting OTP | @Throttle sur /auth/otp/send | 3 req/min par IP |
| Blocage OTP | Redis counter + TTL | 30 min après 3 échecs |
| CORS restreint | ALLOWED_ORIGINS depuis .env | kado.sn uniquement |
| Helmet HTTP headers | helmet() NestJS | XSS, CSRF, clickjacking |
| Validation DTOs | class-validator + whitelist:true | Propriétés inconnues rejetées |
| Transactions atomiques | Prisma $transaction + SELECT FOR UPDATE | Zéro race condition |
| Mots de passe/PIN | bcrypt rounds:10 | Irréversible |
| Monitoring erreurs | Sentry | Alertes temps réel |
LedgerService.assertBalanced() avant chaque insertion.
| Type d'écriture | Débit | Crédit |
|---|---|---|
| PROVISION | WAVE_RECEIVE / OM_RECEIVE | PROVISION_COMPANY:{id} |
| ISSUE (émission bon) | PROVISION_COMPANY:{id} | VOUCHER_LIABILITY:{id} |
| REDEEM (validation) | VOUCHER_LIABILITY:{id} | MERCHANT_PAYABLE:{id} (95%) + REVENUE_COMMISSION (5%) |
| EXPIRE | VOUCHER_LIABILITY:{id} | EXPIRED_FORFEIT |
| CANCEL | VOUCHER_LIABILITY:{id} | PROVISION_COMPANY:{id} |
| SETTLE | MERCHANT_PAYABLE:{id} | MERCHANT_SETTLED:{id} |
| SAAS_REVENUE | COMPANY_ACCOUNT:{id} | REVENUE_SAAS |