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é 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 point = 0,20€
💳 Bancaire : 10 pts = 2,00€ (sans pénalité)
🛍️ Commerçant : 10 pts = 2,00€
📅 Validité : Illimitée (désactivée par défaut — configurable)
♾️ 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 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
2

MODÈLE CONCEPTUEL DE DONNÉES (MCD)

2.1 Diagramme Entités-Relations

Diagramme MCD - REWAPP
Modèle Conceptuel de Données REWAPP

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

AuditLogs

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.

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,
    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
);
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,
    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);
SQL Table recoins_transactions
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

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

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

RELATIONS ET CARDINALITÉS

Cardinalités des Relations

Relation Cardinalité Description
Users → bank_accounts1:NUn utilisateur peut avoir plusieurs comptes bancaires
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
partners → 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
bank_accountsuser_idCASCADESuppression user = suppression comptes
transactionsuser_idRESTRICTEmpêche suppression si transactions
client_payoutsuser_idRESTRICTEmpêche suppression si virements
points_ledgeruser_idCASCADESuppression user = suppression points
partnersvalidated_bySET NULLConservation si admin supprimé
5

RÈGLES MÉTIER IMPLÉMENTÉES

RÈGLE FONDAMENTALE

1 point = 0,20€

Formule de calcul
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
2,00€ 10 pts → Virement
2,00€ 10 pts → QR Code
Désactivée Validité (configurable)
15 min QR Code validité

Paliers de Fidélité

PalierTaux bancaireSeuils lifetime
🥉 Bronze1%0 points
🥈 Silver2%350 points
🥇 Gold3%700 points
💠 Diamant5%1 000 points
6

OPTIMISATIONS ET PERFORMANCES

Cache Redis (TTL)

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

Politique d'Archivage

DonnéesRétentionAction
Transactions > 2 ans24 mois→ MinIO (Parquet)
Audit logs > 1 an12 mois→ MinIO
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, bank_accounts, BankAccounts, Referrals30K users, 45K accounts
Partenairespartners, PartnerSubscription, Campaigns, Events600 partners
TransactionsTransactions, recoins_transactions, QRCodes, client_payouts500K tx, 1M mouvements
SystèmePartnerTier, Notifications, AuditLogs2M 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