DST - Dossier de spécification technique

DAT - Dossier d'Architecture Technique Arpelin

1. Objectif du document

Ce document décrit l'implémentation technique détaillée du logiciel Arpelin, CMS cloud avec modules de caisse enregistreuse et bornes de commande certifiés NF525. Il constitue le référentiel technique d'implémentation conformément aux exigences du paragraphe 4.3.1 du référentiel NF525.

2. Architecture technique générale

2.1. Vue d'ensemble de l'architecture

┌─────────────────────────────────────────────────────────────┐
│                    INTERNET (HTTPS/TLS)                    │
└─────────────────────┬───────────────────────────────────────┘

┌─────────────────────▼───────────────────────────────────────┐
│                 NGINX 1.24 (Load Balancer)                 │
│           Certificats SSL/TLS automatiques                 │
└─────────────────────┬───────────────────────────────────────┘

┌─────────────────────▼───────────────────────────────────────┐
│                  PHP-FPM 8.3 (FastCGI)                     │
│             Gestion sessions + Cache opcache               │
└─────────────────────┬───────────────────────────────────────┘

┌─────────────────────▼───────────────────────────────────────┐
│                  MARIADB 10.11.13                          │
│            Bases dédiées par client isolées                │
└─────────────────────┬───────────────────────────────────────┘

┌─────────────────────▼───────────────────────────────────────┐
│                VPS OVH Ubuntu 24.04.2 LTS                  │
│               x86_64 GNU/Linux 6.8.0-60                    │
└─────────────────────────────────────────────────────────────┘

2.2. Caractéristiques techniques

  • Plateforme : Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)

  • Serveur web : Nginx 1.24 avec modules SSL/TLS

  • Moteur PHP : PHP-FPM 8.3 avec opcache activé

  • Base de données : MariaDB 10.11.13 (compatible MySQL)

  • Chiffrement : HTTPS/TLS obligatoire (certificats automatiques)

  • Versioning : Git local pour gestion du code source

3. Architecture applicative

3.1. Structure des répertoires et modules

/var/www/
├── _main/                          ← Code CMS commun (versionné Git)
│   ├── core/                      ← Moteur principal
│   │   ├── router.php            ← Routeur principal URLs
│   │   ├── session.php           ← Gestion sessions sécurisées
│   │   ├── auth.php              ← Authentification utilisateurs
│   │   └── database.php          ← Couche d'abstraction BDD
│   ├── modules/                   ← Modules fonctionnels
│   │   ├── caisse/               ← Module caisse NF525 ⭐
│   │   │   ├── interface.php     ← Interface caisse
│   │   │   ├── validation.php    ← Validation transactions
│   │   │   ├── tickets.php       ← Génération tickets
│   │   │   └── logs.php          ← Traçabilité NF525
│   │   ├── borne/                ← Module bornes commande ⭐
│   │   │   ├── interface.php     ← Interface client autonome
│   │   │   ├── catalogue.php     ← Affichage produits
│   │   │   └── commande.php      ← Processus commande
│   │   ├── cloturesv              ← Module clôtures ⭐
│   │   │   ├── automatique.php   ← Clôtures programmées
│   │   │   ├── manuelle.php      ← Clôtures à la demande
│   │   │   └── rapports.php      ← Génération rapports
│   │   └── backoffice/           ← Administration
│   │       ├── articles.php      ← Gestion catalogue
│   │       ├── users.php         ← Gestion utilisateurs
│   │       └── stats.php         ← Statistiques/rapports
│   ├── themes/                    ← Templates d'affichage
│   │   ├── caisse/               ← Templates caisse
│   │   ├── borne/                ← Templates borne
│   │   └── admin/                ← Templates administration
│   └── api/                       ← Interfaces API
│       ├── payments/             ← Intégrations paiement
│       │   ├── sumup.php         ← API SumUp
│       │   ├── smilenpay.php     ← API Smile&Pay
│       │   └── satispay.php      ← API Satispay
│       └── webhooks/             ← Retours paiement
├── _files/                        ← Scripts privés (versionné Git)
│   ├── config/                   ← Configuration système
│   │   ├── database.conf         ← Paramètres BDD
│   │   ├── security.conf         ← Paramètres sécurité
│   │   └── nf525.conf            ← Configuration NF525
│   ├── security/                 ← Fonctions sécurité
│   │   ├── encryption.php        ← Chiffrement/déchiffrement
│   │   ├── hash.php              ← Fonctions hashage
│   │   └── signature.php         ← Signatures électroniques
│   ├── database/                 ← Accès base de données
│   │   ├── connect.php           ← Connexions BDD
│   │   ├── migrations.php        ← Scripts migration
│   │   └── backup.php            ← Sauvegardes automatiques
│   └── nf525/                    ← Conformité NF525 ⭐
│       ├── jet.php               ← Journal évènements techniques
│       ├── archivage.php         ← Archivage données
│       ├── integrite.php         ← Contrôle intégrité
│       └── export.php            ← Export conformité
├── cms_client1/                   ← Instance client 1
│   ├── index.php                 ← Point d'entrée
│   ├── .htaccess                 ← Règles réécriture
│   └── assets/                   ← Ressources client
└── .git/                          ← Dépôt Git versioning

3.2. Architecture modulaire

3.2.1. Moteur principal (Core)

  • Router : Gestion des URLs et routage vers modules appropriés

  • Session Manager : Gestion sessions sécurisées 8h avec régénération token

  • Auth Manager : Authentification multi-rôles (Caissier/Manager/Admin)

  • Database Layer : Couche d'abstraction pour accès aux bases de données

3.2.2. Modules NF525 ⭐

  • Module Caisse : Interface encaissement, validation, génération tickets

  • Module Bornes : Interface client autonome, intégration caisse

  • Module Clôtures : Automatiques (cron) et manuelles (droits)

  • Module Archivage : Conservation données figées, exports conformité

3.2.3. API et intégrations

  • Payment APIs : SumUp, Smile&Pay, Satispay

  • Webhooks : Retours validation paiement temps réel

  • Export APIs : Formats conformes audit (CSV/PDF)

4. Base de données - Architecture technique

4.1. Modèle de données NF525 ⭐

4.1.1. Tables critiques conformité

Table transactions (données figées) ⭐

CREATE TABLE transactions (
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    panier_id INT(11) NOT NULL,                    -- Numéro ticket
    user_id VARCHAR(255) NOT NULL,                 -- Caissier responsable
    transaction_date DATETIME NOT NULL,            -- Horodatage précis
    total_ht DECIMAL(10,2) NOT NULL,              -- Total HT
    total_tva DECIMAL(10,2) NOT NULL,             -- Total TVA
    total_ttc DECIMAL(10,2) NOT NULL,             -- Total TTC
    payment_method VARCHAR(50) NOT NULL,           -- Moyen paiement
    ticket_content TEXT NOT NULL,                  -- Contenu ticket figé
    signature VARCHAR(255) NOT NULL,               -- Signature électronique
    hash_control VARCHAR(64) NOT NULL,             -- Hash contrôle
    is_immutable TINYINT(1) DEFAULT 1,            -- Indicateur figé
    INDEX idx_date (transaction_date),
    INDEX idx_user (user_id),
    INDEX idx_panier (panier_id)
) ENGINE=InnoDB;

Table logs (audit JET) ⭐

CREATE TABLE logs (
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    user_id VARCHAR(255) NOT NULL,                 -- Utilisateur action
    action TEXT NOT NULL,                          -- Description action
    function VARCHAR(50) NOT NULL,                 -- Code fonction
    log_date DATETIME NOT NULL,                    -- Horodatage précis
    signature TEXT NOT NULL,                       -- Signature données
    current_hash VARCHAR(64) NOT NULL,             -- Hash action actuelle
    previous_hash VARCHAR(64) NOT NULL,            -- Hash précédent (chaîne)
    data_before TEXT,                              -- Données avant
    data_after TEXT,                               -- Données après
    ip_address VARCHAR(45),                        -- Adresse IP
    INDEX idx_date (log_date),
    INDEX idx_user (user_id),
    INDEX idx_function (function),
    INDEX idx_hash_chain (current_hash, previous_hash)
) ENGINE=InnoDB;

Table closures (clôtures) ⭐

CREATE TABLE closures (
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    closure_number VARCHAR(50) NOT NULL UNIQUE,    -- Numéro clôture
    closure_type ENUM('AUTO', 'MANUAL') NOT NULL,  -- Type clôture
    period_start DATETIME NOT NULL,                -- Début période
    period_end DATETIME NOT NULL,                  -- Fin période
    closure_date DATETIME NOT NULL,                -- Date clôture
    user_id VARCHAR(255),                          -- Utilisateur (si manuelle)
    total_ht DECIMAL(12,2) NOT NULL,              -- Total HT période
    total_tva DECIMAL(12,2) NOT NULL,             -- Total TVA période
    total_ttc DECIMAL(12,2) NOT NULL,             -- Total TTC période
    payment_methods_detail TEXT NOT NULL,          -- Détail moyens paiement
    tva_detail TEXT NOT NULL,                      -- Détail TVA par taux
    transactions_count INT(11) NOT NULL,           -- Nombre transactions
    report_content LONGTEXT NOT NULL,              -- Rapport complet
    hash_previous VARCHAR(64),                     -- Hash clôture précédente
    hash_current VARCHAR(64) NOT NULL,             -- Hash clôture actuelle
    signature VARCHAR(255) NOT NULL,               -- Signature cryptographique
    is_locked TINYINT(1) DEFAULT 1,               -- Verrou modification
    INDEX idx_date (closure_date),
    INDEX idx_period (period_start, period_end),
    INDEX idx_hash_chain (hash_current, hash_previous)
) ENGINE=InnoDB;

4.1.2. Tables fonctionnelles

Table articles

CREATE TABLE articles (
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,                    -- Nom article
    price_ttc DECIMAL(8,2) NOT NULL,              -- Prix TTC
    tva_rate DECIMAL(4,2) NOT NULL,               -- Taux TVA
    barcode VARCHAR(255),                          -- Code-barres
    category_id INT(11),                           -- Catégorie
    stock_quantity INT(11) DEFAULT NULL,           -- Stock (si géré)
    stock_enabled TINYINT(1) DEFAULT 0,           -- Gestion stock activée
    is_active TINYINT(1) DEFAULT 1,               -- Article actif
    created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_barcode (barcode),
    INDEX idx_category (category_id),
    INDEX idx_active (is_active)
) ENGINE=InnoDB;

Table users

CREATE TABLE users (
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL UNIQUE,        -- Nom utilisateur
    email VARCHAR(255) NOT NULL UNIQUE,           -- Email
    password_hash VARCHAR(255) NOT NULL,          -- Mot de passe hashé
    role ENUM('CAISSIER', 'MANAGER', 'ADMIN') NOT NULL,
    first_name VARCHAR(255),                       -- Prénom
    last_name VARCHAR(255),                        -- Nom
    is_active TINYINT(1) DEFAULT 1,               -- Compte actif
    last_login DATETIME,                           -- Dernière connexion
    created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_username (username),
    INDEX idx_email (email),
    INDEX idx_role (role)
) ENGINE=InnoDB;

4.2. Isolation des données par client

4.2.1. Stratégie multi-tenant

  • Base dédiée : Chaque client a sa propre base MySQL

  • Convention nommage : cms_domaine-client_extension

  • Isolation complète : Aucune donnée partagée entre clients

  • Résolution automatique : Via nom de domaine d'accès

4.2.2. Gestion des connexions

// Connexion dynamique selon domaine
function getClientDatabase($domain) {
    $sanitized = preg_replace('/[^a-zA-Z0-9_-]/', '', $domain);
    $dbName = 'cms_' . str_replace(['.', '-'], '_', $sanitized);
    return new PDO("mysql:host=localhost;dbname=$dbName", 
                   $username, $password, $options);
}

5. Implémentation de la sécurité

5.1. Authentification et sessions

5.1.1. Gestion des sessions sécurisées

// Configuration session sécurisée
ini_set('session.cookie_secure', 1);        // HTTPS uniquement
ini_set('session.cookie_httponly', 1);      // Pas d'accès JavaScript
ini_set('session.use_strict_mode', 1);      // Mode strict
ini_set('session.gc_maxlifetime', 28800);   // 8 heures
session_regenerate_id(true);                // Régénération token

5.1.2. Hashage mots de passe

// Hashage sécurisé (PHP 8.3)
$hashedPassword = password_hash($password, PASSWORD_ARGON2ID, [
    'memory_cost' => 65536,
    'time_cost' => 4,
    'threads' => 3
]);

5.2. Chiffrement et signatures ⭐

5.2.1. Hashage SHA-256 pour intégrité

function generateHash($data) {
    return hash('sha256', json_encode($data) . SALT_NF525);
}

function generateTransactionSignature($transaction) {
    $data = [
        'id' => $transaction['id'],
        'date' => $transaction['transaction_date'],
        'total' => $transaction['total_ttc'],
        'user' => $transaction['user_id']
    ];
    return generateHash($data);
}

5.2.2. Signature électronique tickets ⭐

function generateTicketSignature($ticketData) {
    // Signature complète (255 caractères)
    $fullSignature = hash('sha256', serialize($ticketData) . SECRET_KEY);
    
    // Extrait pour ticket (positions 3, 7, 13, 19)
    $extractSignature = substr($fullSignature, 3, 1) . 
                       substr($fullSignature, 7, 1) . 
                       substr($fullSignature, 13, 1) . 
                       substr($fullSignature, 19, 1);
    
    return [
        'full' => $fullSignature,
        'extract' => strtoupper($extractSignature)
    ];
}

5.3. Protection HTTPS/TLS

5.3.1. Configuration Nginx

server {
    listen 443 ssl http2;
    server_name *.arpelin.com;
    
    # Certificats SSL automatiques
    ssl_certificate /etc/ssl/certs/arpelin.crt;
    ssl_certificate_key /etc/ssl/private/arpelin.key;
    
    # Configuration TLS moderne
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    
    # Headers sécurité
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    
    # Redirection HTTP vers HTTPS
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
}

6. Implémentation modules NF525 ⭐

6.1. Module caisse enregistreuse

6.1.1. Processus de validation transaction

function validateTransaction($cartData, $paymentData, $userId) {
    // 1. Validation des données
    if (!validateCartIntegrity($cartData)) {
        throw new Exception("Erreur intégrité panier");
    }
    
    // 2. Calcul totaux automatiques
    $totals = calculateTotals($cartData);
    
    // 3. Génération numéro ticket unique
    $ticketNumber = generateTicketNumber();
    
    // 4. Création transaction immutable
    $transaction = [
        'panier_id' => $ticketNumber,
        'user_id' => $userId,
        'transaction_date' => date('Y-m-d H:i:s'),
        'total_ht' => $totals['ht'],
        'total_tva' => $totals['tva'],
        'total_ttc' => $totals['ttc'],
        'payment_method' => $paymentData['method'],
        'ticket_content' => generateTicketContent($cartData, $totals),
        'signature' => generateTransactionSignature($transaction),
        'hash_control' => generateHash($transaction)
    ];
    
    // 5. Insertion BDD (données figées)
    insertTransaction($transaction);
    
    // 6. Log audit JET
    logAction('TRANSACTION_VALIDATE', $userId, $transaction);
    
    // 7. Génération ticket client
    return generatePrintableTicket($transaction);
}

6.1.2. Génération tickets conformes

function generateTicketContent($cartData, $totals) {
    $ticket = [];
    
    // En-tête obligatoire
    $ticket[] = getCompanyHeader();
    $ticket[] = str_repeat('-', 40);
    
    // Détail articles
    foreach ($cartData['items'] as $item) {
        $ticket[] = sprintf("%-20s %2dx%6.2f %8.2f",
            substr($item['name'], 0, 20),
            $item['quantity'],
            $item['price'],
            $item['total']
        );
    }
    
    $ticket[] = str_repeat('-', 40);
    
    // Totaux TVA par taux
    foreach ($totals['tva_detail'] as $rate => $amount) {
        $ticket[] = sprintf("TVA %4.1f%% %26.2f", $rate, $amount);
    }
    
    $ticket[] = str_repeat('-', 40);
    $ticket[] = sprintf("TOTAL TTC %28.2f", $totals['ttc']);
    $ticket[] = sprintf("Payé par %s %20.2f", 
        $paymentData['method'], $paymentData['amount']);
    
    // Footer obligatoire NF525
    $ticket[] = str_repeat('-', 40);
    $ticket[] = sprintf("Ticket N° %s", $ticketNumber);
    $ticket[] = date('d/m/Y H:i:s');
    $ticket[] = sprintf("Signature: %s", $extractSignature);
    
    return implode("\n", $ticket);
}

6.2. Journal d'évènements techniques (JET) ⭐

6.2.1. Enregistrement automatique

function logAction($actionCode, $userId, $data = null, $before = null) {
    // Récupération hash précédent
    $previousHash = getLastLogHash();
    
    // Préparation log
    $logData = [
        'user_id' => $userId,
        'action' => getActionDescription($actionCode),
        'function' => $actionCode,
        'log_date' => date('Y-m-d H:i:s'),
        'data_before' => $before ? json_encode($before) : null,
        'data_after' => $data ? json_encode($data) : null,
        'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
        'previous_hash' => $previousHash
    ];
    
    // Génération signature et hash
    $logData['signature'] = generateLogSignature($logData);
    $logData['current_hash'] = generateHash($logData);
    
    // Insertion base (ajout uniquement)
    insertLog($logData);
}

6.2.2. Codes d'action standardisés

const JET_ACTIONS = [
    'ORDER_PICKUP' => 'Commande retirée',
    'ORDER_DELETE' => 'Commande supprimée',
    'UNPAID_ORDER_DELETE' => 'Commande non payée supprimée',
    'CANCEL_ENTRY' => 'Annulation d\'entrée',
    'PRICE_MODIFY' => 'Modification de prix',
    'DISCOUNT_ITEM' => 'Remise sur article',
    'DISCOUNT_GLOBAL' => 'Remise globale',
    'CART_VIEW' => 'Consultation panier',
    'CART_UPDATE' => 'Mise à jour panier',
    'CART_GLOBAL' => 'Action globale panier',
    'TRANSACTION_VALIDATE' => 'Validation transaction',
    'CLOSURE_AUTO' => 'Clôture automatique',
    'CLOSURE_MANUAL' => 'Clôture manuelle'
];

6.3. Système de clôtures ⭐

6.3.1. Clôtures automatiques (cron)

// Script cron quotidien (00:00)
function executeAutomaticClosure($type = 'DAILY') {
    $periods = [
        'DAILY' => [
            'start' => date('Y-m-d 00:00:00', strtotime('-1 day')),
            'end' => date('Y-m-d 23:59:59', strtotime('-1 day'))
        ],
        'MONTHLY' => [
            'start' => date('Y-m-01 00:00:00', strtotime('-1 month')),
            'end' => date('Y-m-t 23:59:59', strtotime('-1 month'))
        ],
        'YEARLY' => [
            'start' => date('Y-01-01 00:00:00', strtotime('-1 year')),
            'end' => date('Y-12-31 23:59:59', strtotime('-1 year'))
        ]
    ];
    
    $period = $periods[$type];
    
    // Récupération transactions période
    $transactions = getTransactionsByPeriod($period['start'], $period['end']);
    
    // Calculs automatiques
    $totals = calculatePeriodTotals($transactions);
    $paymentMethods = calculatePaymentMethods($transactions);
    $tvaDetails = calculateTvaDetails($transactions);
    
    // Génération rapport
    $report = generateClosureReport($type, $period, $totals, 
                                  $paymentMethods, $tvaDetails);
    
    // Hash et signature
    $previousHash = getLastClosureHash();
    $currentHash = generateHash($report);
    $signature = generateClosureSignature($report);
    
    // Sauvegarde clôture
    saveClosureData([
        'closure_number' => generateClosureNumber(),
        'closure_type' => 'AUTO',
        'period_start' => $period['start'],
        'period_end' => $period['end'],
        'closure_date' => date('Y-m-d H:i:s'),
        'total_ht' => $totals['ht'],
        'total_tva' => $totals['tva'],
        'total_ttc' => $totals['ttc'],
        'payment_methods_detail' => json_encode($paymentMethods),
        'tva_detail' => json_encode($tvaDetails),
        'transactions_count' => count($transactions),
        'report_content' => $report,
        'hash_previous' => $previousHash,
        'hash_current' => $currentHash,
        'signature' => $signature
    ]);
    
    // Log action
    logAction('CLOSURE_AUTO', 'SYSTEM', $closureData);
}

7. Intégrations APIs de paiement

7.1. Architecture modulaire paiements

7.1.1. Interface commune

interface PaymentProcessorInterface {
    public function initializePayment($amount, $currency, $orderId);
    public function processPayment($paymentData);
    public function handleWebhook($webhookData);
    public function validatePayment($transactionId);
}

7.1.2. Implémentation SumUp

class SumUpProcessor implements PaymentProcessorInterface {
    private $apiKey;
    private $merchantCode;
    
    public function initializePayment($amount, $currency, $orderId) {
        $endpoint = 'https://api.sumup.com/v0.1/checkouts';
        
        $data = [
            'checkout_reference' => $orderId,
            'amount' => $amount,
            'currency' => $currency,
            'merchant_code' => $this->merchantCode,
            'description' => 'Commande Arpelin #' . $orderId
        ];
        
        return $this->makeApiCall($endpoint, $data);
    }
    
    public function handleWebhook($webhookData) {
        // Validation signature webhook
        if (!$this->validateWebhookSignature($webhookData)) {
            throw new Exception('Webhook signature invalide');
        }
        
        // Traitement retour paiement
        $orderId = $webhookData['checkout_reference'];
        $status = $webhookData['status'];
        
        if ($status === 'PAID') {
            return $this->confirmPayment($orderId, $webhookData);
        }
        
        return false;
    }
}

7.2. Gestion des webhooks

7.2.1. Endpoint unifié webhooks

// /api/webhooks/payment.php
function handlePaymentWebhook($provider, $data) {
    // Log réception webhook
    logAction('WEBHOOK_RECEIVED', 'SYSTEM', [
        'provider' => $provider,
        'data' => $data
    ]);
    
    try {
        // Routage selon provider
        $processor = PaymentProcessorFactory::create($provider);
        $result = $processor->handleWebhook($data);
        
        if ($result) {
            // Mise à jour commande
            updateOrderStatus($result['order_id'], 'PAID');
            
            // Log succès
            logAction('PAYMENT_CONFIRMED', 'SYSTEM', $result);
            
            return ['status' => 'success'];
        }
        
    } catch (Exception $e) {
        // Log erreur
        logAction('WEBHOOK_ERROR', 'SYSTEM', [
            'error' => $e->getMessage(),
            'provider' => $provider
        ]);
        
        return ['status' => 'error', 'message' => $e->getMessage()];
    }
}

8. Système de sauvegarde et archivage

8.1. Sauvegardes automatiques

8.1.1. Script de sauvegarde quotidienne

#!/bin/bash
# /etc/cron.daily/arpelin-backup

BACKUP_DIR="/var/backups/arpelin"
DATE=$(date +%Y%m%d)
RETENTION_DAYS=7

# Sauvegarde de toutes les bases clients
for db in $(mysql -e "SHOW DATABASES LIKE 'cms_%';" | grep cms_); do
    echo "Sauvegarde base $db..."
    mysqldump --single-transaction --routines --triggers $db > \
        "$BACKUP_DIR/${db}_${DATE}.sql"
    gzip "$BACKUP_DIR/${db}_${DATE}.sql"
done

# Sauvegarde fichiers clients
tar -czf "$BACKUP_DIR/files_${DATE}.tar.gz" /var/www/cms_*/assets/

# Nettoyage anciennes sauvegardes
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "Sauvegarde terminée: $(date)"

8.1.2. Vérification intégrité sauvegardes

function verifyBackupIntegrity($backupFile) {
    // Vérification taille minimale
    if (filesize($backupFile) < 1024) {
        return false;
    }
    
    // Test décompression
    if (substr($backupFile, -3) === '.gz') {
        $testCommand = "gunzip -t " . escapeshellarg($backupFile);
        exec($testCommand, $output, $returnCode);
        return $returnCode === 0;
    }
    
    return true;
}

8.2. Archivage données NF525 ⭐

8.2.1. Processus d'archivage automatique

function archiveNF525Data($closureId) {
    $closure = getClosureById($closureId);
    
    // Génération archive période
    $archiveData = [
        'closure_id' => $closureId,
        'period_start' => $closure['period_start'],
        'period_end' => $closure['period_end'],
        'transactions' => getTransactionsByPeriod(
            $closure['period_start'], 
            $closure['period_end']
        ),
        'logs' => getLogsByPeriod(
            $closure['period_start'], 
            $closure['period_end']
        ),
        'closure_data' => $closure
    ];
    
    // Génération fichier archive
    $archiveFile = generateArchiveFile($archiveData);
    
    // Calcul empreinte
    $archiveHash = hash_file('sha256', $archiveFile);
    
    // Enregistrement référence archive
    saveArchiveReference([
        'closure_id' => $closureId,
        'archive_file' => basename($archiveFile),
        'archive_path' => $archiveFile,
        'archive_hash' => $archiveHash,
        'archive_date' => date('Y-m-d H:i:s'),
        'file_size' => filesize($archiveFile)
    ]);
    
    return $archiveFile;
}

9. Monitoring et surveillance

9.1. Surveillance système

9.1.1. Monitoring performances

function checkSystemHealth() {
    $health = [
        'timestamp' => date('Y-m-d H:i:s'),
        'disk_usage' => disk_free_space('/') / disk_total_space('/') * 100,
        'memory_usage' => memory_get_usage(true) / (1024 * 1024),
        'load_average' => sys_getloadavg()[0],
        'database_status' => checkDatabaseConnections(),
        'ssl_certificate' => checkSSLCertificate(),
        'backup_status' => checkLastBackup()
    ];
    
    // Alertes si seuils dépassés
    if ($health['disk_usage'] > 90) {
        sendAlert('Espace disque critique: ' . $health['disk_usage'] . '%');
    }
    
    return $health;
}

9.1.2. Logs d'accès et erreurs

# Configuration Nginx logging
access_log /var/log/nginx/arpelin_access.log combined;
error_log /var/log/nginx/arpelin_error.log warn;

# Format personnalisé pour audit
log_format audit_format '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $bytes_sent '
                        '"$http_referer" "$http_user_agent" '
                        '$request_time $upstream_response_time';

9.2. Contrôle intégrité NF525 ⭐

9.2.1. Vérification chaîne de logs

function verifyLogChainIntegrity($startDate = null, $endDate = null) {
    $logs = getLogs($startDate, $endDate, 'ORDER BY id ASC');
    $errors = [];
    
    for ($i = 1; $i < count($logs); $i++) {
        $current = $logs[$i];
        $previous = $logs[$i - 1];
        
        // Vérification chaînage
        if ($current['previous_hash'] !== $previous['current_hash']) {
            $errors[] = [
                'type' => 'CHAIN_BREAK',
                'log_id' => $current['id'],
                'message' => 'Rupture chaîne entre logs ' . 
                           $previous['id'] . ' et ' . $current['id']
            ];
        }
        
        // Vérification hash actuel
        $calculatedHash = generateHash($current);
        if ($calculatedHash !== $current['current_hash']) {
            $errors[] = [
                'type' => 'HASH_INVALID',
                'log_id' => $current['id'],
                'message' => 'Hash invalide pour log ' . $current['id']
            ];
        }
    }
    
    return [
        'valid' => empty($errors),
        'errors' => $errors,
        'total_logs' => count($logs),
        'verification_date' => date('Y-m-d H:i:s')
    ];
}

9.2.2. Export conformité audit

function exportAuditData($startDate, $endDate, $format = 'CSV') {
    // Récupération données période
    $transactions = getTransactionsByPeriod($startDate, $endDate);
    $logs = getLogsByPeriod($startDate, $endDate);
    $closures = getClosuresByPeriod($startDate, $endDate);
    
    // Vérification intégrité avant export
    $integrityCheck = verifyLogChainIntegrity($startDate, $endDate);
    
    // Génération export
    $exportData = [
        'metadata' => [
            'export_date' => date('Y-m-d H:i:s'),
            'period_start' => $startDate,
            'period_end' => $endDate,
            'format' => $format,
            'integrity_verified' => $integrityCheck['valid']
        ],
        'transactions' => $transactions,
        'logs' => $logs,
        'closures' => $closures,
        'integrity_report' => $integrityCheck
    ];
    
    // Calcul hash export
    $exportHash = generateHash($exportData);
    $exportData['export_hash'] = $exportHash;
    
    // Génération fichier selon format
    switch ($format) {
        case 'CSV':
            return generateCSVExport($exportData);
        case 'JSON':
            return json_encode($exportData, JSON_PRETTY_PRINT);
        case 'PDF':
            return generatePDFReport($exportData);
        default:
            throw new Exception('Format non supporté');
    }
}

10. Déploiement et gestion des versions

10.1. Système de versioning Git

10.1.1. Structure branches

main
├── production     ← Version stable déployée
├── staging        ← Tests pré-production
├── development    ← Développement actif
└── hotfix/*       ← Corrections urgentes

10.1.2. Script de déploiement

#!/bin/bash
# deploy.sh

VERSION=$1
BACKUP_DIR="/var/backups/deployments"

if [ -z "$VERSION" ]; then
    echo "Usage: ./deploy.sh <version>"
    exit 1
fi

echo "Déploiement version $VERSION..."

# Sauvegarde version actuelle
cd /var/www
tar -czf "$BACKUP_DIR/pre-deploy-$(date +%Y%m%d-%H%M%S).tar.gz" _main/ _files/

# Mise à jour code
git fetch origin
git checkout $VERSION

# Vérification intégrité
if ! git verify-tag $VERSION; then
    echo "ERREUR: Tag non signé ou invalide"
    exit 1
fi

# Tests automatiques
php /var/www/_files/tests/integrity_check.php
if [ $? -ne 0 ]; then
    echo "ERREUR: Tests d'intégrité échoués"
    exit 1
fi

# Rechargement configuration
systemctl reload nginx
systemctl reload php8.3-fpm

echo "Déploiement $VERSION terminé avec succès"

10.2. Tests automatiques

10.2.1. Tests d'intégrité NF525

// /var/www/_files/tests/integrity_check.php
class NF525IntegrityTests {
    
    public function testDatabaseSchema() {
        $requiredTables = [
            'transactions', 'logs', 'closures', 
            'articles', 'users', 'archives'
        ];
        
        foreach ($requiredTables as $table) {
            if (!$this->tableExists($table)) {
                throw new Exception("Table manquante: $table");
            }
        }
        
        return true;
    }
    
    public function testSignatureFunctions() {
        $testData = ['test' => 'data', 'timestamp' => time()];
        
        // Test génération signature
        $signature = generateHash($testData);
        if (strlen($signature) !== 64) {
            throw new Exception("Signature invalide");
        }
        
        // Test reproductibilité
        $signature2 = generateHash($testData);
        if ($signature !== $signature2) {
            throw new Exception("Signatures non reproductibles");
        }
        
        return true;
    }
    
    public function testLogChaining() {
        // Test sur les 100 derniers logs
        $logs = getLastLogs(100);
        $integrity = verifyLogChainIntegrity();
        
        if (!$integrity['valid']) {
            throw new Exception("Chaîne de logs compromise");
        }
        
        return true;
    }
    
    public function runAllTests() {
        $tests = [
            'Database Schema' => 'testDatabaseSchema',
            'Signature Functions' => 'testSignatureFunctions',
            'Log Chaining' => 'testLogChaining'
        ];
        
        $results = [];
        
        foreach ($tests as $name => $method) {
            try {
                $this->$method();
                $results[$name] = 'PASS';
            } catch (Exception $e) {
                $results[$name] = 'FAIL: ' . $e->getMessage();
            }
        }
        
        return $results;
    }
}

11. Performance et optimisation

11.1. Optimisation base de données

11.1.1. Configuration MariaDB

# /etc/mysql/mariadb.conf.d/99-arpelin.cnf

[mysqld]
# Optimisations mémoire
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2

# Optimisations requêtes
query_cache_type = 1
query_cache_size = 128M
tmp_table_size = 64M
max_heap_table_size = 64M

# Index et performances
innodb_file_per_table = 1
innodb_flush_method = O_DIRECT

11.1.2. Index critiques NF525

-- Index pour performances requêtes audit
CREATE INDEX idx_logs_date_user ON logs(log_date, user_id);
CREATE INDEX idx_transactions_date ON transactions(transaction_date);
CREATE INDEX idx_closures_period ON closures(period_start, period_end);

-- Index pour chaînage
CREATE INDEX idx_logs_hash_chain ON logs(current_hash, previous_hash);
CREATE INDEX idx_closures_hash_chain ON closures(hash_current, hash_previous);

-- Index fonctionnels
CREATE INDEX idx_articles_active_barcode ON articles(is_active, barcode);
CREATE INDEX idx_users_active_role ON users(is_active, role);

11.2. Cache et optimisation PHP

11.2.1. Configuration OPcache

# /etc/php/8.3/fpm/conf.d/10-opcache.ini

opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.save_comments=1

11.2.2. Cache applicatif

class CacheManager {
    private static $cache = [];
    
    public static function get($key) {
        return self::$cache[$key] ?? null;
    }
    
    public static function set($key, $value, $ttl = 3600) {
        self::$cache[$key] = [
            'value' => $value,
            'expires' => time() + $ttl
        ];
    }
    
    public static function getCachedArticles() {
        $cacheKey = 'articles_active';
        $cached = self::get($cacheKey);
        
        if ($cached && $cached['expires'] > time()) {
            return $cached['value'];
        }
        
        $articles = getActiveArticles();
        self::set($cacheKey, $articles, 1800); // 30 minutes
        
        return $articles;
    }
}

12. Documentation technique et maintenance

12.1. Procédures de maintenance

12.1.1. Maintenance préventive mensuelle

// Script maintenance mensuelle
function monthlyMaintenance() {
    $maintenanceLog = [];
    
    // 1. Optimisation bases de données
    $databases = getAllClientDatabases();
    foreach ($databases as $db) {
        optimizeDatabase($db);
        $maintenanceLog[] = "Base $db optimisée";
    }
    
    // 2. Nettoyage logs anciens (si configuré)
    $retentionDays = getLogRetentionDays();
    if ($retentionDays > 0) {
        cleanOldLogs($retentionDays);
        $maintenanceLog[] = "Logs > $retentionDays jours nettoyés";
    }
    
    // 3. Vérification intégrité globale
    $integrityCheck = verifyGlobalIntegrity();
    $maintenanceLog[] = "Intégrité: " . 
        ($integrityCheck['valid'] ? 'OK' : 'ERREURS DÉTECTÉES');
    
    // 4. Rapport maintenance
    $report = generateMaintenanceReport($maintenanceLog);
    sendMaintenanceReport($report);
    
    return $maintenanceLog;
}

12.1.2. Surveillance continue

// Script surveillance (cron toutes les 5 minutes)
function continuousMonitoring() {
    $alerts = [];
    
    // Vérification espace disque
    $diskUsage = getDiskUsage();
    if ($diskUsage > 85) {
        $alerts[] = "Espace disque critique: {$diskUsage}%";
    }
    
    // Vérification connexions BDD
    $dbStatus = checkDatabaseConnections();
    if (!$dbStatus['all_connected']) {
        $alerts[] = "Connexions BDD en erreur: " . 
                   implode(', ', $dbStatus['errors']);
    }
    
    // Vérification certificats SSL
    $sslCheck = checkSSLCertificates();
    if ($sslCheck['expires_soon']) {
        $alerts[] = "Certificat SSL expire dans " . 
                   $sslCheck['days_remaining'] . " jours";
    }
    
    // Envoi alertes si nécessaire
    if (!empty($alerts)) {
        sendAlerts($alerts);
    }
}

12.2. Documentation API interne

12.2.1. API fonctions NF525

/**
 * API NF525 - Fonctions principales conformité
 */
class NF525API {
    
    /**
     * Valide une transaction et génère ticket
     * @param array $cartData Données panier
     * @param array $paymentData Données paiement
     * @param string $userId Identifiant caissier
     * @return array Données transaction et ticket
     */
    public function validateTransaction($cartData, $paymentData, $userId) {
        // Implémentation voir section 6.1.1
    }
    
    /**
     * Génère clôture manuelle
     * @param string $startDate Date début période
     * @param string $endDate Date fin période
     * @param string $userId Utilisateur demandeur
     * @return array Données clôture générée
     */
    public function generateManualClosure($startDate, $endDate, $userId) {
        // Implémentation voir section 6.3.1
    }
    
    /**
     * Exporte données pour audit
     * @param string $startDate Date début
     * @param string $endDate Date fin
     * @param string $format Format export (CSV/JSON/PDF)
     * @return string Chemin fichier généré
     */
    public function exportAuditData($startDate, $endDate, $format = 'CSV') {
        // Implémentation voir section 9.2.2
    }
    
    /**
     * Vérifie intégrité chaîne de logs
     * @param string|null $startDate Date début (optionnelle)
     * @param string|null $endDate Date fin (optionnelle)
     * @return array Résultat vérification
     */
    public function verifyLogIntegrity($startDate = null, $endDate = null) {
        // Implémentation voir section 9.2.1
    }
}

13. Conformité et audit

13.1. Points de contrôle NF525 ⭐

13.1.1. Checklist conformité technique

  • Traçabilité : Table logs avec chaînage cryptographique

  • Inaltérabilité : Données figées en table transactions

  • Horodatage : Précision à la seconde pour toutes opérations

  • Signature électronique : SHA-256 + extrait 4 caractères ticket

  • Clôtures automatiques : Cron quotidien/mensuel/annuel

  • Clôtures manuelles : Interface dédiée avec droits

  • Archivage : Conservation données période selon réglementation

  • Numérotation : Tickets séquentiels uniques par client

  • TVA : Calcul automatique par taux article

  • Moyens paiement : Traçabilité complète tous moyens

13.1.2. Procédure audit technique

function performTechnicalAudit($auditPeriod) {
    $auditResults = [
        'audit_date' => date('Y-m-d H:i:s'),
        'period' => $auditPeriod,
        'checks' => []
    ];
    
    // 1. Vérification intégrité données
    $integrityCheck = verifyLogChainIntegrity(
        $auditPeriod['start'], 
        $auditPeriod['end']
    );
    $auditResults['checks']['data_integrity'] = $integrityCheck;
    
    // 2. Cohérence transactions/clôtures
    $coherenceCheck = verifyTransactionClosureCoherence($auditPeriod);
    $auditResults['checks']['coherence'] = $coherenceCheck;
    
    // 3. Complétude numérotation
    $numberingCheck = verifyTicketNumbering($auditPeriod);
    $auditResults['checks']['numbering'] = $numberingCheck;
    
    // 4. Validation signatures
    $signatureCheck = verifyAllSignatures($auditPeriod);
    $auditResults['checks']['signatures'] = $signatureCheck;
    
    // 5. Conformité tickets
    $ticketCheck = verifyTicketCompliance($auditPeriod);
    $auditResults['checks']['tickets'] = $ticketCheck;
    
    // Génération rapport audit
    return generateAuditReport($auditResults);
}

13.2. Mise à disposition administration

13.2.1. Interface audit dédiée

// Interface pour contrôles administratifs
class AdminAuditInterface {
    
    public function getAuditAccess($adminCredentials) {
        // Validation credentials administrateur
        if (!$this->validateAdminAccess($adminCredentials)) {
            throw new Exception("Accès non autorisé");
        }
        
        return [
            'data_access' => $this->getDataAccessMethods(),
            'export_tools' => $this->getExportTools(),
            'verification_tools' => $this->getVerificationTools()
        ];
    }
    
    public function getDataAccessMethods() {
        return [
            'transactions' => '/admin/audit/transactions',
            'logs' => '/admin/audit/logs',
            'closures' => '/admin/audit/closures',
            'archives' => '/admin/audit/archives'
        ];
    }
    
    public function generateComplianceReport($clientId, $period) {
        // Génération rapport conformité complet
        $client = getClientInfo($clientId);
        $transactions = getTransactionsByPeriod(
            $period['start'], $period['end']
        );
        $logs = getLogsByPeriod(
            $period['start'], $period['end']
        );
        
        return [
            'client_info' => $client,
            'period' => $period,
            'transactions_count' => count($transactions),
            'total_amount' => array_sum(array_column($transactions, 'total_ttc')),
            'integrity_status' => verifyLogChainIntegrity(),
            'export_file' => exportAuditData(
                $period['start'], $period['end'], 'PDF'
            )
        ];
    }
}

14. Conclusion

14.1. Synthèse technique

Le Dossier d'Architecture Technique (DAT) d'Arpelin présente une implémentation robuste et conforme aux exigences NF525, structurée autour de :

  • Architecture sécurisée : HTTPS/TLS, isolation données par client

  • Modules NF525 certifiés : Caisse, bornes, clôtures, archivage

  • Traçabilité complète : Chaînage cryptographique, JET, immutabilité

  • Performance optimisée : Cache, index, configuration adaptée

  • Maintenance facilitée : Scripts automatisés, monitoring continu

14.2. Points techniques clés ⭐

  1. Sécurité cryptographique : SHA-256 pour toutes signatures et hash

  2. Isolation données : Base MySQL dédiée par client

  3. Traçabilité inviolable : Chaînage blockchain dans table logs

  4. Archivage conformé : Conservation automatique avec empreintes

  5. API modulaires : Intégrations paiement extensibles

14.3. Évolutivité

L'architecture technique permet :

  • Montée en charge horizontale (ajout VPS)

  • Intégration nouvelles APIs paiement

  • Extension modules fonctionnels

  • Maintien conformité lors évolutions


Document établi dans le cadre de la certification NF525 Version : 1.0 Date : Janvier 2024 Responsable : Emre KOSE

Last updated