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é 60 secondes)
- Système de fidélité avec 5 paliers (Bronze, Silver, Gold, Platine, 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 | Prisma |
Mapping objet-relationnel, migrations |
| Stockage fichiers | AWS S3 |
Logos partenaires, documents KBIS |
| Logs/Analytics | MongoDB |
Données non structurées, logs d'événements |
1.4 Entités Principales
Le modèle comporte 16 entités principales organisées en 4 domaines fonctionnels :
Domaine Utilisateurs
- • Users : Comptes clients mobile
- • AdminUsers : Comptes administrateurs
- • Cards : Cartes bancaires liées
- • BankAccounts : IBAN pour virements
Domaine Partenaires
- • Merchants : Commerces affiliés
- • MerchantSubscriptions : Abonnements premium
- • Campaigns : Campagnes promotionnelles
Domaine Transactions
- • Transactions : Achats détectés
- • PointsLedger : Journal des points (FIFO)
- • QRCodes : Paiement commerçant (60s)
- • Withdrawals : Demandes de virement
Domaine Système
- • LoyaltyTiers : Configuration des paliers
- • UserLoyaltyProgress : Progression par partenaire
- • Notifications : Centre de notifications
- • AuditLogs : Journal d'audit
MODÈLE CONCEPTUEL DE DONNÉES (MCD)
2.1 Diagramme Entités-Relations
Le diagramme PlantUML peut être rendu via PlantUML Server
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é |
| biometric_enabled | BOOLEAN |
DEFAULT FALSE |
Biométrie mobile activée |
| status | VARCHAR(20) |
DEFAULT 'active' |
Statut : active, suspended, deleted, pending_verification |
| loyalty_tier | VARCHAR(20) |
DEFAULT 'bronze' |
Palier global : bronze, silver, gold, platinum, 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é Cards (Cartes Bancaires)
Cartes bancaires liées via solution OpenBanking (Budget Insight, Plaid, Tink). Permet la détection automatique des transactions.
Cards
Cartes bancaires liées via OpenBanking| Attribut | Type | Contraintes | Description |
|---|---|---|---|
| id | UUID |
PK |
Identifiant unique |
| user_id | UUID |
FK → users.id, NOT NULL |
Référence utilisateur |
| bank_name | VARCHAR(100) |
NOT NULL |
Nom de la banque (ex: BNP Paribas) |
| card_token | VARCHAR(255) |
NOT NULL |
Token sécurisé fourni par solution bancaire |
| card_last4 | VARCHAR(4) |
NOT NULL |
4 derniers chiffres de la carte |
| card_type | VARCHAR(20) |
NULL |
Type : VISA, MASTERCARD, CB |
| is_primary | BOOLEAN |
DEFAULT FALSE |
Carte principale par défaut |
| is_active | BOOLEAN |
DEFAULT TRUE |
Carte active pour détection |
| linked_at | TIMESTAMP |
DEFAULT NOW() |
Date de liaison |
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é Merchants (Partenaires)
Commerces affiliés à REWAPP.
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 commerçant.
Merchants
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 |
| merchant_id | UUID |
FK → merchants.id, NOT NULL |
Référence partenaire |
| card_id | UUID |
FK → cards.id, NOT NULL |
Carte utilisée |
| 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é PointsLedger (Journal des Points)
Journal comptable des crédits/débits de points. Implémente la méthode FIFO pour l'expiration (points les plus anciens dépensés en premier).
RÈGLES MÉTIER
- Validité points : 12 mois à partir de la date de crédit
- Méthode FIFO : Les points les plus anciens sont dépensés en premier
- Notifications : J-30 et J-7 avant expiration
PointsLedger
Journal comptable des points - 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 → withdrawals.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, +12 mois) |
2.8 Entité QRCodes
Codes QR générés pour paiement cashback commerçant. Validité 60 secondes, usage unique, signature HMAC-SHA256.
RÈGLES MÉTIER QR CODE
- Validité : 60 secondes exactement
- Usage : UNIQUE (toute réutilisation rejetée)
- Points bloqués : Dès la génération
- Expiration automatique : Points débloqués après 60s
QRCodes
Paiement commerçant - 60s, 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 = 1,05€) |
| status | VARCHAR(20) |
DEFAULT 'active' |
Statut : active, used, expired, cancelled |
| expires_at | TIMESTAMP |
NOT NULL |
Expiration (génération + 60 secondes) |
| used_at | TIMESTAMP |
NULL |
Date d'utilisation (scan) |
2.9 Entité Withdrawals (Virements)
Demandes de conversion points → virement bancaire. Seuil minimum 100 points, délai 2-3 semaines maximum.
RÈGLES MÉTIER VIREMENT
- Seuil minimum : 100 points (= 9,50€ après conversion)
- Ratio : 10 points = 0,95€ (-5% vs valeur nominale)
- Délai : 2-3 semaines maximum
- Annulation : Possible uniquement si statut = 'pending'
Withdrawals
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 = 0,95€) |
| 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 5 paliers de fidélité avec bonus cashback progressifs.
Configuration des Paliers par Défaut
| Palier | Bonus | Seuil par défaut | Ordre |
|---|---|---|---|
| 🥉 Bronze | +0% | 0€ | 1 |
| 🥈 Silver | +5% | 500€ | 2 |
| 🥇 Gold | +10% | 1 500€ | 3 |
| 💎 Platine | +15% | 3 000€ | 4 |
| 💠 Diamant | +20% | 10 000€ | 5 |
2.11-2.16 Autres Entités
Notifications
Centre de notifications multi-canal (push, email, in-app, SMS)MerchantSubscriptions
Abonnements premium partenaires (49€/mois ou 490€/an)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)UserLoyaltyProgress
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,
biometric_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', 'platinum', '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,
merchant_id UUID NOT NULL REFERENCES merchants(id) ON DELETE RESTRICT,
card_id UUID NOT NULL REFERENCES cards(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 points_ledger (
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 merchants USING GIST (
ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)
) WHERE latitude IS NOT NULL AND longitude IS NOT NULL;
CREATE INDEX idx_merchants_category ON merchants(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 PointsLedger (FIFO expiration)
CREATE INDEX idx_points_ledger_expiry ON points_ledger(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,10€)
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 = 0,95€)
CREATE OR REPLACE FUNCTION calculate_withdrawal_amount(points INTEGER)
RETURNS DECIMAL AS $$
BEGIN
RETURN ROUND(points * 0.095, 2);
END;
$$ LANGUAGE plpgsql;
-- Fonction de calcul montant QR code (10 points = 1,05€)
CREATE OR REPLACE FUNCTION calculate_qr_amount(points INTEGER)
RETURNS DECIMAL AS $$
BEGIN
RETURN ROUND(points * 0.105, 2);
END;
$$ LANGUAGE plpgsql;
RELATIONS ET CARDINALITÉS
Cardinalités des Relations
| Relation | Cardinalité | Description |
|---|---|---|
| Users → Cards | 1:N | Un utilisateur peut avoir plusieurs cartes |
| 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 |
| Merchants → 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 |
|---|---|---|---|
| cards | user_id | CASCADE | Suppression user = suppression cartes |
| transactions | user_id | RESTRICT | Empêche suppression si transactions |
| withdrawals | user_id | RESTRICT | Empêche suppression si virements |
| points_ledger | user_id | CASCADE | Suppression user = suppression points |
| merchants | validated_by | SET NULL | Conservation si admin supprimé |
RÈGLES MÉTIER IMPLÉMENTÉES
RÈGLE FONDAMENTALE
1 point = 0,10€
Points = Montant × Taux Cashback × (1 + Bonus Palier) × 10
Exemple : Achat 85€ chez partenaire 4%, client Silver (+5%)
Points = 85 × 0.04 × 1.05 × 10 = 35 points
Paliers de Fidélité
| Palier | Bonus | Seuil |
|---|---|---|
| 🥉 Bronze | +0% | 0€ |
| 🥈 Silver | +5% | 500€ |
| 🥇 Gold | +10% | 1 500€ |
| 💎 Platine | +15% | 3 000€ |
| 💠 Diamant | +20% | 10 000€ |
OPTIMISATIONS ET PERFORMANCES
Cache Redis (TTL)
| Donnée | TTL |
|---|---|
| Solde points utilisateur | 5 min |
| QR codes actifs | 60s |
| Sessions utilisateur | 24h |
| Taux cashback partenaires | 15 min |
Politique d'Archivage
| Données | Rétention | Action |
|---|---|---|
| Transactions > 2 ans | 24 mois | → S3 (Parquet) |
| Audit logs > 1 an | 12 mois | → S3 |
| 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, Cards, BankAccounts | 30K users, 45K cards |
| Partenaires | Merchants, Subscriptions, Campaigns | 600 merchants |
| Transactions | Transactions, PointsLedger, QRCodes | 500K tx, 1M mouvements |
| Système | LoyaltyProgress, Notifications, AuditLogs | 2M notifs |
- 1 point = 0,10€
- Virement : 10 pts = 0,95€ (-5%)
- QR Code : 10 pts = 1,05€ (+5%)
- Validité : 12 mois (FIFO)
- QR Code : 60s, usage unique
- Seuil virement : 100 pts min
- 5 paliers par partenaire
- Validation partenaires : Admin obligatoire
- 2FA Admin : Obligatoire