v1.0 Novembre 2025
Document 4.2

Modèle de Données
MCD - MLD

La solution de cashback nouvelle génération

24 novembre 2025
Version 1.0
PostgreSQL 15+
1

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 point = 0,10€
💳 Bancaire : 10 pts = 0,95€ (-5%)
🛍️ Commerçant : 10 pts = 1,05€ (+5%)
📅 Validité : 12 mois (FIFO)
♾️ Plafond points : ILLIMITÉ

1.2 Principes de Modélisation

3NF Normalisation
Index Performance
AES-256 Sécurité
Audit Traçabilité
  • 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
2

MODÈLE CONCEPTUEL DE DONNÉES (MCD)

2.1 Diagramme Entités-Relations

Diagramme MCD - REWAPP

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
email 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
email 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 partenaires

AuditLogs

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.

3

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

SQL Table Users
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
);
SQL Table Transactions (partitionnée)
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);
SQL Table PointsLedger
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

SQL Index stratégiques
-- 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

SQL Fonctions de calcul
-- 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;
4

RELATIONS ET CARDINALITÉS

Cardinalités des Relations

Relation Cardinalité Description
Users → Cards1:NUn utilisateur peut avoir plusieurs cartes
Users → BankAccounts1:0..1Un utilisateur a au maximum un compte bancaire
Users → Transactions1:NUn utilisateur peut avoir plusieurs transactions
Users → PointsLedger1:NUn utilisateur a plusieurs mouvements de points
Merchants → Transactions1:NUn partenaire reçoit plusieurs transactions
Transactions → PointsLedger1:NUne transaction génère des mouvements de points
QRCodes → PointsLedger1:0..1Un QR code utilisé génère un débit
Withdrawals → PointsLedger1:1Un virement génère un débit de points

Comportement ON DELETE

Table FK ON DELETE Justification
cardsuser_idCASCADESuppression user = suppression cartes
transactionsuser_idRESTRICTEmpêche suppression si transactions
withdrawalsuser_idRESTRICTEmpêche suppression si virements
points_ledgeruser_idCASCADESuppression user = suppression points
merchantsvalidated_bySET NULLConservation si admin supprimé
5

RÈGLES MÉTIER IMPLÉMENTÉES

RÈGLE FONDAMENTALE

1 point = 0,10€

Formule de calcul
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
0,95€ 10 pts → Virement (-5%)
1,05€ 10 pts → QR Code (+5%)
12 mois Validité (FIFO)
60s QR Code validité

Paliers de Fidélité

PalierBonusSeuil
🥉 Bronze+0%0€
🥈 Silver+5%500€
🥇 Gold+10%1 500€
💎 Platine+15%3 000€
💠 Diamant+20%10 000€
6

OPTIMISATIONS ET PERFORMANCES

Cache Redis (TTL)

DonnéeTTL
Solde points utilisateur5 min
QR codes actifs60s
Sessions utilisateur24h
Taux cashback partenaires15 min

Politique d'Archivage

DonnéesRétentionAction
Transactions > 2 ans24 mois→ S3 (Parquet)
Audit logs > 1 an12 mois→ S3
Notifications lues > 6 mois6 moisSupprimées
QR codes expirés > 3 mois3 moisSupprimés
7

RÉCAPITULATIF

Volumes Estimés (Année 1)

DomaineEntitésVolume
UtilisateursUsers, Cards, BankAccounts30K users, 45K cards
PartenairesMerchants, Subscriptions, Campaigns600 merchants
TransactionsTransactions, PointsLedger, QRCodes500K tx, 1M mouvements
SystèmeLoyaltyProgress, Notifications, AuditLogs2M 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