Modèle de Données
MCD - MLD
La solution de cashback nouvelle génération
VUE D'ENSEMBLE DU MODÈLE DE DONNÉES
1.1 Introduction
Le modèle de données de REWAPP est conçu pour supporter l'ensemble des fonctionnalités de la plateforme de cashback nouvelle génération :
- Cashback bancaire direct avec virement sous 2-3 semaines
- Cashback commerçant via QR code (validité 15 minutes)
- Système de fidélité avec 4 paliers (Bronze, Silver, Gold, Diamant)
- Gestion des partenaires avec validation admin obligatoire
- Traçabilité complète des transactions et mouvements de points
RÈGLES FONDAMENTALES
1.2 Principes de Modélisation
- Normalisation : Respect de la 3ème forme normale (3NF) pour éviter la redondance des données
- Performance : Index stratégiques sur les colonnes fréquemment interrogées
- Intégrité : Contraintes de clés étrangères, contraintes CHECK, triggers
- Audit : Traçabilité complète via AuditLogs pour toutes les modifications sensibles
- Sécurité : Chiffrement AES-256 des données sensibles, hashage bcrypt des mots de passe
- Scalabilité : Partitionnement des tables volumineuses, stratégie d'archivage
1.3 Technologies de Stockage
Stack de Stockage
| Composant | Technologie | Usage |
|---|---|---|
| Base principale | PostgreSQL 15+ |
Données relationnelles structurées |
| Cache | Redis 7+ |
Sessions, QR codes actifs, calculs temps réel |
| ORM | TypeORM |
Mapping objet-relationnel, migrations |
| Stockage fichiers | stockage serveur local (MinIO) |
Logos partenaires, documents KBIS |
1.4 Entités Principales
Le modèle comporte 28 entités principales organisées en 4 domaines fonctionnels :
Domaine Utilisateurs
- • Users : Comptes clients mobile
- • AdminUsers : Comptes administrateurs
- • bank_accounts : Cartes bancaires liées (Plaid)
- • BankAccounts : IBAN pour virements SEPA
- • Referrals : Parrainage (filleuls, bonus)
Domaine Partenaires
- • partners : Commerces affiliés
- • PartnerSubscription : Abonnements premium
- • Campaigns : Campagnes promotionnelles
- • Events : Événements exclusifs partenaires
Domaine Transactions
- • Transactions : Achats détectés (Plaid)
- • recoins_transactions : Journal des points (FIFO)
- • QRCodes : Paiement commerçant (15 min)
- • client_payouts : Demandes de virement
- • cashback_reclaims : Cashbacks réclamés
Domaine Système
- • CashbackTierConfig : Configuration des 4 paliers
- • PartnerTier : Progression par partenaire
- • Notifications : Centre de notifications
- • AuditLogs : Journal d'audit
MODÈLE CONCEPTUEL DE DONNÉES (MCD)
2.1 Diagramme Entités-Relations
2.2 Entité Users (Utilisateurs)
Gestion des comptes clients de l'application mobile REWAPP.
Users
Comptes clients de l'application mobile| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK, DEFAULT |
Identifiant unique |
VARCHAR(255) |
UNIQUE, NOT NULL |
Adresse email de connexion | |
| password_hash | VARCHAR(255) |
NOT NULL |
Mot de passe hashé (bcrypt) |
| first_name | VARCHAR(100) |
NOT NULL |
Prénom |
| last_name | VARCHAR(100) |
NOT NULL |
Nom de famille |
| phone | VARCHAR(20) |
NULL |
Numéro de téléphone (optionnel) |
| birth_date | DATE |
NULL |
Date de naissance (vérification 18+ ans) |
| email_verified | BOOLEAN |
DEFAULT FALSE |
Email vérifié |
| two_factor_enabled | BOOLEAN |
DEFAULT FALSE |
2FA activé |
| status | VARCHAR(20) |
DEFAULT 'active' |
Statut : active, suspended, deleted, pending_verification |
| loyalty_tier | VARCHAR(20) |
DEFAULT 'bronze' |
Palier global : bronze, silver, gold, diamond |
| total_points_earned | INTEGER |
DEFAULT 0 |
Total historique de points gagnés |
| total_spent_eur | DECIMAL(10,2) |
DEFAULT 0 |
Total dépensé (calcul palier) |
| created_at | TIMESTAMP |
DEFAULT NOW() |
Date de création |
| deleted_at | TIMESTAMP |
NULL |
Soft delete (RGPD) |
2.3 Entité bank_accounts (Comptes Bancaires Plaid)
Comptes bancaires liés via Plaid OpenBanking. Permet la détection automatique des transactions bancaires.
bank_accounts
Comptes bancaires liés via Plaid OpenBanking| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| plaid_account_id | VARCHAR(255) |
NOT NULL, UNIQUE |
ID compte Plaid |
| plaid_item_id | VARCHAR(255) |
NOT NULL |
ID Item Plaid (connexion banque) |
| bank_name | VARCHAR(100) |
NOT NULL |
Nom de la banque (ex: BNP Paribas) |
| account_mask | VARCHAR(4) |
NOT NULL |
4 derniers chiffres du compte |
| account_type | VARCHAR(20) |
NULL |
Type : checking, savings |
| is_primary | BOOLEAN |
DEFAULT FALSE |
Compte principal par défaut |
| is_active | BOOLEAN |
DEFAULT TRUE |
Compte actif pour détection |
| linked_at | TIMESTAMP |
DEFAULT NOW() |
Date de liaison Plaid |
2.4 Entité BankAccounts (Comptes Bancaires)
IBAN pour virements cashback bancaire. Stockage chiffré AES-256.
BankAccounts
IBAN pour virements SEPA - Chiffré AES-256| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| iban_encrypted | VARCHAR(255) |
NOT NULL |
IBAN chiffré AES-256 |
| iban_hash | VARCHAR(64) |
NOT NULL |
Hash SHA-256 de l'IBAN (recherche) |
| bic | VARCHAR(11) |
NULL |
Code BIC de la banque |
| account_holder_name | VARCHAR(255) |
NOT NULL |
Nom du titulaire du compte |
| is_verified | BOOLEAN |
DEFAULT FALSE |
IBAN vérifié (micro-virement) |
| is_default | BOOLEAN |
DEFAULT FALSE |
Compte par défaut pour virements |
2.5 Entité partners (Partenaires/Commerces)
Commerces affiliés à REWAPP avec validation admin obligatoire.
VALIDATION MANUELLE OBLIGATOIRE
Tous les partenaires doivent être validés par un administrateur avant activation. Le taux de cashback est UNIQUE pour TOUS les produits du partenaire.
partners
Commerces affiliés avec configuration cashback| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| name | VARCHAR(255) |
NOT NULL |
Nom commercial |
| legal_name | VARCHAR(255) |
NOT NULL |
Raison sociale |
| siret | VARCHAR(14) |
UNIQUE, NOT NULL |
Numéro SIRET |
VARCHAR(255) |
NOT NULL |
Email de contact principal | |
| category | VARCHAR(50) |
NOT NULL |
Catégorie : restaurant, retail, services, beauty, leisure, health |
| cashback_rate | DECIMAL(5,2) |
NOT NULL, DEFAULT 3.00 |
Taux de cashback % (UNIQUE tous produits) |
| latitude | DECIMAL(10,8) |
NULL |
GPS latitude (géolocalisation) |
| longitude | DECIMAL(11,8) |
NULL |
GPS longitude |
| status | VARCHAR(20) |
DEFAULT 'pending' |
Statut : pending, active, inactive, rejected, suspended |
| validation_status | VARCHAR(20) |
DEFAULT 'pending' |
Validation admin : pending, approved, rejected |
| validated_by | UUID |
FK → admin_users.id |
Admin ayant validé |
| is_premium | BOOLEAN |
DEFAULT FALSE |
Abonnement premium actif (49€/mois) |
| opening_hours | JSONB |
NULL |
Horaires d'ouverture (JSON) |
2.6 Entité Transactions
Historique des achats détectés automatiquement via la solution bancaire. Génère des points selon le taux du partenaire et le palier de l'utilisateur.
Transactions
Achats détectés automatiquement - Table partitionnée par mois| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| partner_id | UUID |
FK → partners.id, NOT NULL |
Référence partenaire |
| bank_account_id | UUID |
FK → bank_accounts.id, NOT NULL |
Compte bancaire utilisé |
| external_transaction_id | VARCHAR(255) |
UNIQUE |
ID fourni par solution bancaire |
| amount | DECIMAL(10,2) |
NOT NULL |
Montant en EUR |
| transaction_date | TIMESTAMP |
NOT NULL |
Date/heure de la transaction |
| status | VARCHAR(20) |
DEFAULT 'pending' |
Statut : pending, validated, cancelled, refunded |
| points_credited | INTEGER |
DEFAULT 0 |
Points crédités (calculés) |
| loyalty_tier_bonus | DECIMAL(5,2) |
DEFAULT 0 |
Bonus % appliqué selon palier |
2.7 Entité recoins_transactions (Journal des Points)
Journal comptable des crédits/débits de recoines. Implémente la méthode FIFO pour l'expiration (points les plus anciens dépensés en premier).
RÈGLES MÉTIER
- Validité recoines : Désactivée par défaut (0 = jamais), configurable via CASHBACK_EXPIRATION_MONTHS
- Méthode FIFO : Uniquement si expiration activée
- Notifications : J-30 et J-7 avant expiration (si activée)
recoins_transactions
Journal comptable des recoines - Méthode FIFO| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| transaction_id | UUID |
FK → transactions.id, NULL |
Référence transaction (si crédit achat) |
| qr_code_id | UUID |
FK → qr_codes.id, NULL |
Référence QR code (si débit QR) |
| withdrawal_id | UUID |
FK → client_payouts.id, NULL |
Référence virement (si débit virement) |
| type | VARCHAR(20) |
NOT NULL |
Type : credit, debit, expiration, adjustment |
| amount | INTEGER |
NOT NULL |
Points (positif=crédit, négatif=débit) |
| balance_after | INTEGER |
NOT NULL |
Solde après opération |
| source | VARCHAR(50) |
NOT NULL |
Origine : transaction, qr_payment, withdrawal, campaign, bonus, expiration, admin_adjustment |
| expiry_date | DATE |
NULL |
Date d'expiration (crédit uniquement, configurable — 0 = jamais) |
2.8 Entité QRCodes
Codes QR générés pour paiement cashback commerçant. Validité 15 minutes, usage unique, signature HMAC-SHA256.
RÈGLES MÉTIER QR CODE
- Validité : 15 minutes exactement
- Usage : UNIQUE (toute réutilisation rejetée)
- Recoines bloqués : Dès la génération
- Expiration automatique : Recoines débloqués après 15 min
QRCodes
Paiement commerçant - 15 min, usage unique| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| merchant_id | UUID |
FK → merchants.id, NULL |
Partenaire cible (NULL si générique) |
| code | VARCHAR(255) |
UNIQUE, NOT NULL |
Code QR (UUID + timestamp signé) |
| signature | VARCHAR(64) |
NOT NULL |
Signature HMAC-SHA256 |
| points_amount | INTEGER |
NOT NULL, CHECK >= 10 |
Nombre de points à débiter |
| euro_amount | DECIMAL(10,2) |
NOT NULL |
Équivalence EUR (10pts = 2,00€) |
| status | VARCHAR(20) |
DEFAULT 'active' |
Statut : active, used, expired, cancelled |
| expires_at | TIMESTAMP |
NOT NULL |
Expiration (génération + 15 minutes) |
| used_at | TIMESTAMP |
NULL |
Date d'utilisation (scan) |
2.9 Entité client_payouts (Virements)
Demandes de conversion recoines → virement bancaire. Seuil minimum 100 recoines, traitement sous 2-3 jours ouvrés.
RÈGLES MÉTIER VIREMENT
- Seuil minimum : 50 recoins (= 10,00€ après conversion)
- Ratio : 10 recoins = 2,00€ (ratio identique partout)
- Délai : 2-3 jours ouvrés maximum
- Annulation : Possible uniquement si statut = 'pending'
client_payouts
Demandes de virement bancaire| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| bank_account_id | UUID |
FK → bank_accounts.id, NOT NULL |
Compte bancaire destination |
| request_number | VARCHAR(50) |
UNIQUE, NOT NULL |
Numéro de demande (WR-2025-001234) |
| points_amount | INTEGER |
NOT NULL, CHECK >= 100 |
Points à convertir (minimum 100) |
| euro_amount | DECIMAL(10,2) |
NOT NULL |
Montant EUR (10pts = 2,00€) |
| status | VARCHAR(20) |
DEFAULT 'pending' |
Statut : pending, processing, completed, cancelled, failed |
| requested_at | TIMESTAMP |
DEFAULT NOW() |
Date de demande |
| completed_at | TIMESTAMP |
NULL |
Date de complétion |
2.10 Entité LoyaltyTiers (Paliers Fidélité)
Configuration des 4 paliers de fidélité avec bonus cashback progressifs.
Configuration des Paliers par Défaut
| Palier | Bonus | Seuil par défaut | Ordre |
|---|---|---|---|
| 🥉 Bronze | 1% bancaire (établissement configurable) | 0€ | 1 |
| 🥈 Silver | 2% bancaire (établissement configurable) | 500€ | 2 |
| 🥇 Gold | 3% bancaire (établissement configurable) | 1 500€ | 3 |
| 💠 Diamant | 5% bancaire (taux par défaut — configurable) | 10 000€ | 4 |
2.11-2.16 Autres Entités
Notifications
Centre de notifications multi-canal (push, email, in-app, SMS)PartnerSubscription
Abonnements premium partenaires (tarif configurable via admin)Campaigns
Campagnes marketing et promotions créées par les partenairesAuditLogs
Traçabilité complète de toutes les actions sensibles pour conformitéAdminUsers
Comptes administrateurs avec 2FA obligatoire (Super Admin, Admin, Support)PartnerTier
Progression fidélité par utilisateur par partenaire (12 mois glissants)RÈGLE PALIER PAR PARTENAIRE
Le palier est calculé sur les 12 derniers mois glissants, par partenaire. Un utilisateur peut avoir des paliers différents chez différents partenaires. Recalcul automatique quotidien à 2h00.
MODÈLE LOGIQUE DE DONNÉES (MLD)
3.1 Schéma Relationnel PostgreSQL
Le schéma PostgreSQL implémente le MCD avec les optimisations suivantes :
- UUID comme clé primaire (sécurité, distribution)
- Contraintes CHECK pour validation des données
- Index stratégiques pour les requêtes fréquentes
- Triggers pour audit automatique
- Partitionnement pour les tables volumineuses
3.2 Scripts DDL des Tables
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
phone VARCHAR(20),
birth_date DATE,
email_verified BOOLEAN DEFAULT FALSE,
two_factor_enabled BOOLEAN DEFAULT FALSE,
status VARCHAR(20) DEFAULT 'active'
CHECK (status IN ('active', 'suspended', 'deleted', 'pending_verification')),
loyalty_tier VARCHAR(20) DEFAULT 'bronze'
CHECK (loyalty_tier IN ('bronze', 'silver', 'gold', 'diamond')),
total_points_earned INTEGER DEFAULT 0,
total_spent_eur DECIMAL(10,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
deleted_at TIMESTAMP
);
CREATE TABLE transactions (
id UUID DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
partner_id UUID NOT NULL REFERENCES partners(id) ON DELETE RESTRICT,
bank_account_id UUID NOT NULL REFERENCES bank_accounts(id) ON DELETE RESTRICT,
external_transaction_id VARCHAR(255) UNIQUE,
amount DECIMAL(10,2) NOT NULL CHECK (amount > 0),
currency VARCHAR(3) DEFAULT 'EUR',
transaction_date TIMESTAMP NOT NULL,
status VARCHAR(20) DEFAULT 'pending'
CHECK (status IN ('pending', 'validated', 'cancelled', 'refunded')),
points_credited INTEGER DEFAULT 0,
loyalty_tier_bonus DECIMAL(5,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (id, transaction_date)
) PARTITION BY RANGE (transaction_date);
CREATE TABLE recoins_transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
transaction_id UUID,
qr_code_id UUID,
withdrawal_id UUID,
type VARCHAR(20) NOT NULL
CHECK (type IN ('credit', 'debit', 'expiration', 'adjustment')),
amount INTEGER NOT NULL,
balance_after INTEGER NOT NULL,
source VARCHAR(50) NOT NULL
CHECK (source IN ('transaction', 'qr_payment', 'withdrawal',
'campaign', 'bonus', 'expiration', 'admin_adjustment')),
expiry_date DATE,
created_at TIMESTAMP DEFAULT NOW()
);
3.3 Index et Optimisations
-- Index Table Users
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_status ON users(status) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_loyalty_tier ON users(loyalty_tier);
-- Index Table Merchants (avec géolocalisation)
CREATE INDEX idx_merchants_location ON partners USING GIST (
ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)
) WHERE latitude IS NOT NULL AND longitude IS NOT NULL;
CREATE INDEX idx_partners_category ON partners(category, status);
-- Index Table Transactions
CREATE INDEX idx_transactions_user_id ON transactions(user_id, transaction_date DESC);
CREATE INDEX idx_transactions_merchant_id ON transactions(merchant_id, transaction_date DESC);
-- Index Table recoins_transactions (FIFO expiration)
CREATE INDEX idx_recoins_expiry ON recoins_transactions(expiry_date)
WHERE type = 'credit' AND expiry_date IS NOT NULL;
-- Index Table QRCodes (expiration)
CREATE INDEX idx_qr_codes_expires ON qr_codes(expires_at) WHERE status = 'active';
3.4 Fonctions Métier
-- Fonction de calcul des points (1 point = 0,20€)
CREATE OR REPLACE FUNCTION calculate_points(
amount_eur DECIMAL, cashback_rate DECIMAL, tier_bonus DECIMAL
) RETURNS INTEGER AS $$
BEGIN
RETURN FLOOR(amount_eur * (cashback_rate / 100) * (1 + tier_bonus / 100) * 10);
END;
$$ LANGUAGE plpgsql;
-- Fonction de calcul montant virement (10 points = 2,00€)
CREATE OR REPLACE FUNCTION calculate_withdrawal_amount(points INTEGER)
RETURNS DECIMAL AS $$
BEGIN
RETURN ROUND(points * 0.200, 2);
END;
$$ LANGUAGE plpgsql;
-- Fonction de calcul montant QR code (10 points = 2,00€)
CREATE OR REPLACE FUNCTION calculate_qr_amount(points INTEGER)
RETURNS DECIMAL AS $$
BEGIN
RETURN ROUND(points * 0.200, 2);
END;
$$ LANGUAGE plpgsql;
RELATIONS ET CARDINALITÉS
Cardinalités des Relations
| Relation | Cardinalité | Description |
|---|---|---|
| Users → bank_accounts | 1:N | Un utilisateur peut avoir plusieurs comptes bancaires |
| Users → BankAccounts | 1:0..1 | Un utilisateur a au maximum un compte bancaire |
| Users → Transactions | 1:N | Un utilisateur peut avoir plusieurs transactions |
| Users → PointsLedger | 1:N | Un utilisateur a plusieurs mouvements de points |
| partners → Transactions | 1:N | Un partenaire reçoit plusieurs transactions |
| Transactions → PointsLedger | 1:N | Une transaction génère des mouvements de points |
| QRCodes → PointsLedger | 1:0..1 | Un QR code utilisé génère un débit |
| Withdrawals → PointsLedger | 1:1 | Un virement génère un débit de points |
Comportement ON DELETE
| Table | FK | ON DELETE | Justification |
|---|---|---|---|
| bank_accounts | user_id | CASCADE | Suppression user = suppression comptes |
| transactions | user_id | RESTRICT | Empêche suppression si transactions |
| client_payouts | user_id | RESTRICT | Empêche suppression si virements |
| points_ledger | user_id | CASCADE | Suppression user = suppression points |
| partners | validated_by | SET NULL | Conservation si admin supprimé |
RÈGLES MÉTIER IMPLÉMENTÉES
RÈGLE FONDAMENTALE
1 point = 0,20€
Points = Montant × Taux Cashback × (1 + Bonus Palier) × 10
Exemple : Achat 85€ chez partenaire 4%, client Silver (2%)
Points = 85 × 0.04 × 1.02 × 10 = 35 points
Paliers de Fidélité
| Palier | Taux bancaire | Seuils lifetime |
|---|---|---|
| 🥉 Bronze | 1% | 0 points |
| 🥈 Silver | 2% | 350 points |
| 🥇 Gold | 3% | 700 points |
| 💠 Diamant | 5% | 1 000 points |
OPTIMISATIONS ET PERFORMANCES
Cache Redis (TTL)
| Donnée | TTL |
|---|---|
| Solde points utilisateur | 5 min |
| QR codes actifs | 15 min |
| Sessions utilisateur | 24h |
| Taux cashback partenaires | 15 min |
Politique d'Archivage
| Données | Rétention | Action |
|---|---|---|
| Transactions > 2 ans | 24 mois | → MinIO (Parquet) |
| Audit logs > 1 an | 12 mois | → MinIO |
| Notifications lues > 6 mois | 6 mois | Supprimées |
| QR codes expirés > 3 mois | 3 mois | Supprimés |
RÉCAPITULATIF
Volumes Estimés (Année 1)
| Domaine | Entités | Volume |
|---|---|---|
| Utilisateurs | Users, bank_accounts, BankAccounts, Referrals | 30K users, 45K accounts |
| Partenaires | partners, PartnerSubscription, Campaigns, Events | 600 partners |
| Transactions | Transactions, recoins_transactions, QRCodes, client_payouts | 500K tx, 1M mouvements |
| Système | PartnerTier, Notifications, AuditLogs | 2M notifs |
- 1 point = 0,20€
- Virement : 10 pts = 2,00€
- QR Code : 10 pts = 2,00€
- Validité : 12 mois (FIFO)
- QR Code : 15 min, usage unique
- Seuil virement : 100 pts min
- 4 paliers par partenaire (Bronze/Silver/Gold/Diamond)
- Validation partenaires : Admin obligatoire
- 2FA Admin : Obligatoire