Files
backend/documentation/CDC_API_Backend_v2.md
2026-07-04 22:47:55 +02:00

28 KiB

Cahier des Charges — API & Base de Données

Projet : Laverie Connectée — Backend

Version : 2.0
Stack principale : Laravel 11, MySQL 8, Redis, Docker
Positionnement : V1 démontrable, extensible vers V2 sans refonte majeure


1. Contexte & Objectifs

1.1 Contexte

Développement d'une API centrale servant :

  • une application utilisateur multi-plateforme,
  • un back-office exploitant,
  • une couche d'intégration avec les systèmes machines fournis par le client ou ses partenaires techniques.

L'API est le point d'entrée unique de la logique métier. Les clients applicatifs ne communiquent jamais directement avec la base de données.

1.2 Objectifs V1

  • authentifier les utilisateurs finaux et les exploitants,
  • gérer plusieurs laveries et plusieurs exploitants dans une même plateforme,
  • exposer les données établissements / machines / disponibilités,
  • gérer un porte-monnaie électronique avec traçabilité,
  • permettre la réservation d'un créneau,
  • permettre le démarrage d'un lavage via intégration machine,
  • historiser les événements machines,
  • fournir un socle d'audit, de sécurité et de statistiques simples.

1.3 Principes de conception

  • MVP strict : seules les fonctionnalités nécessaires à la démonstration et à la première mise en service sont incluses en V1.
  • Extensibilité : fidélité, abonnements, parrainage, campagnes marketing et analytics avancées sont prévues mais non implémentées en V1.
  • Traçabilité : tout flux critique doit être rejouable et auditable.
  • Isolation métier : chaque exploitant ne voit que ses établissements, ses machines et ses chiffres.
  • Intégration externe souple : la couche machine doit supporter aussi bien un modèle où notre système appelle une API partenaire qu'un modèle où le partenaire pousse des événements vers notre API.

2. Périmètre fonctionnel

2.1 MVP V1

Utilisateur final

  • inscription / connexion,
  • consultation des laveries,
  • consultation des machines et de leur statut,
  • consultation du solde wallet,
  • historique simple des transactions,
  • rechargement du wallet,
  • réservation d'un créneau,
  • démarrage d'un lavage,
  • historique des lavages,
  • notifications transactionnelles.

Exploitant

  • connexion superviseur,
  • consultation du parc machines,
  • consultation d'un tableau de bord simple,
  • consultation des réservations et lavages,
  • gestion simple de la tarification,
  • visualisation des alertes techniques de base.

Plateforme

  • multi-exploitants,
  • audit logs,
  • agrégats journaliers simples,
  • intégration machine simulable pour démonstration.

2.2 V2 prévue

  • fidélité,
  • parrainage,
  • abonnements,
  • campagnes marketing,
  • promotions avancées,
  • exports RGPD complets,
  • analytics détaillées,
  • règles tarifaires complexes,
  • exports métier avancés.

2.3 Hors périmètre V1

  • chat,
  • avis,
  • FAQ dynamique,
  • recommandation de cycle par photo,
  • moteur prédictif / deep learning,
  • orchestration matérielle bas niveau.

3. Stack Technique

Composant Technologie Version Commentaire
Framework API Laravel 11.x Coeur métier principal
Base de données MySQL 8.0 Référentiel transactionnel
Cache / queues Redis 7.x Queues, verrous applicatifs, cache court
Workers Laravel Horizon 5.x Supervision des jobs
Scheduler Laravel Scheduler natif Cron applicatif
Documentation API Scramble ou L5-Swagger OpenAPI
Conteneurisation Docker Environnements reproductibles
CI/CD GitHub Actions Tests + build
Monitoring erreurs Sentry Backend
Logs JSON structurés Corrélation et exploitation

3.1 Authentification recommandée

  • App mobile / web utilisateur : access token court + refresh token.
  • Back-office exploitant : session cookie Laravel.
  • Intégrations machines / partenaires : API key technique ou signature HMAC.

Cette séparation évite de mélanger les contraintes des apps utilisateurs, du back-office et des systèmes techniques.


4. Architecture logique

4.1 Domaines métier principaux

  • Authentification
  • Organisations / exploitants
  • Établissements
  • Machines
  • Tarification
  • Wallet & paiements
  • Réservations
  • Lavages
  • Notifications
  • Intégrations machines
  • Audit & statistiques

4.2 Multi-tenant logique

Le système n'est pas multi-base ni multi-schémas. L'isolation est assurée au niveau applicatif par :

  • organization_id,
  • policies Laravel,
  • query scopes explicites,
  • ressources d'API filtrées selon l'utilisateur connecté.

4.3 Structure recommandée Laravel

app/
├── Domain/
│   ├── Auth/
│   ├── Organization/
│   ├── Machine/
│   ├── Wallet/
│   ├── Booking/
│   ├── Wash/
│   ├── Pricing/
│   ├── Notification/
│   └── Integration/
├── Http/
│   ├── Controllers/
│   ├── Middleware/
│   └── Requests/
├── Jobs/
├── Events/
├── Listeners/
├── Policies/
├── Models/
└── Support/

5. Base de Données — Schéma révisé

5.0 Connexion bdd de test

hostname: localhost port: 3306 user: root password: shema: laverie

5.1 Exploitants et périmètre

Table organizations

CREATE TABLE organizations (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    name VARCHAR(200) NOT NULL,
    code VARCHAR(50) UNIQUE NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL
);

Table establishments

CREATE TABLE establishments (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    organization_id BIGINT UNSIGNED NOT NULL,
    uuid CHAR(36) UNIQUE NOT NULL,
    name VARCHAR(200) NOT NULL,
    address TEXT NOT NULL,
    city VARCHAR(100) NULL,
    zip_code VARCHAR(10) NULL,
    latitude DECIMAL(10,8) NULL,
    longitude DECIMAL(11,8) NULL,
    timezone VARCHAR(50) NOT NULL DEFAULT 'Europe/Paris',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_establishments_organization FOREIGN KEY (organization_id) REFERENCES organizations(id)
);

Table supervisors

CREATE TABLE supervisors (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    organization_id BIGINT UNSIGNED NOT NULL,
    establishment_id BIGINT UNSIGNED NULL,
    uuid CHAR(36) UNIQUE NOT NULL,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    role ENUM('platform_admin','owner','manager','viewer') NOT NULL DEFAULT 'manager',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    last_login_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_supervisors_organization FOREIGN KEY (organization_id) REFERENCES organizations(id),
    CONSTRAINT fk_supervisors_establishment FOREIGN KEY (establishment_id) REFERENCES establishments(id)
);

5.2 Utilisateurs finaux

Table users

CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    phone VARCHAR(20) UNIQUE NULL,
    birthdate DATE NULL,
    email_verified_at TIMESTAMP NULL,
    password VARCHAR(255) NOT NULL,
    locale VARCHAR(10) NOT NULL DEFAULT 'fr',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    anonymized_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    deleted_at TIMESTAMP NULL
);

Table gdpr_consents

CREATE TABLE gdpr_consents (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    type ENUM('data_processing','marketing','analytics') NOT NULL,
    accepted BOOLEAN NOT NULL,
    policy_version VARCHAR(50) NOT NULL,
    policy_text_hash VARCHAR(255) NOT NULL,
    source ENUM('mobile','web','backoffice') NOT NULL,
    consent_language VARCHAR(10) NOT NULL DEFAULT 'fr',
    ip_address VARCHAR(45) NULL,
    user_agent TEXT NULL,
    accepted_at TIMESTAMP NOT NULL,
    revoked_at TIMESTAMP NULL,
    CONSTRAINT fk_gdpr_consents_user FOREIGN KEY (user_id) REFERENCES users(id)
);

Table user_devices

CREATE TABLE user_devices (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    platform ENUM('android','ios','web') NOT NULL,
    push_token VARCHAR(255) NOT NULL,
    app_version VARCHAR(50) NULL,
    device_name VARCHAR(100) NULL,
    last_seen_at TIMESTAMP NULL,
    revoked_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_user_device_token (push_token),
    CONSTRAINT fk_user_devices_user FOREIGN KEY (user_id) REFERENCES users(id)
);

Table notification_preferences

CREATE TABLE notification_preferences (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    transaction_enabled BOOLEAN NOT NULL DEFAULT TRUE,
    reminder_enabled BOOLEAN NOT NULL DEFAULT TRUE,
    marketing_enabled BOOLEAN NOT NULL DEFAULT FALSE,
    system_enabled BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_notification_preferences_user (user_id),
    CONSTRAINT fk_notification_preferences_user FOREIGN KEY (user_id) REFERENCES users(id)
);

5.3 Machines et intégrations

Table machines

CREATE TABLE machines (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    establishment_id BIGINT UNSIGNED NOT NULL,
    uuid CHAR(36) UNIQUE NOT NULL,
    name VARCHAR(100) NOT NULL,
    type ENUM('washer_small','washer_large','dryer_small','dryer_large') NOT NULL,
    qr_code VARCHAR(255) UNIQUE NOT NULL,
    status ENUM('available','reserved','running','maintenance','offline','error') NOT NULL DEFAULT 'available',
    current_user_id BIGINT UNSIGNED NULL,
    cycle_started_at TIMESTAMP NULL,
    cycle_ends_at TIMESTAMP NULL,
    last_heartbeat_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_machines_establishment FOREIGN KEY (establishment_id) REFERENCES establishments(id),
    CONSTRAINT fk_machines_current_user FOREIGN KEY (current_user_id) REFERENCES users(id)
);

Table machine_integrations

CREATE TABLE machine_integrations (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    machine_id BIGINT UNSIGNED NOT NULL,
    provider VARCHAR(100) NOT NULL,
    external_machine_id VARCHAR(100) NOT NULL,
    external_site_id VARCHAR(100) NULL,
    mode ENUM('pull','push','hybrid','simulated') NOT NULL DEFAULT 'simulated',
    config JSON NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_machine_provider_external (provider, external_machine_id),
    CONSTRAINT fk_machine_integrations_machine FOREIGN KEY (machine_id) REFERENCES machines(id)
);

Table machine_commands

CREATE TABLE machine_commands (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    machine_id BIGINT UNSIGNED NOT NULL,
    provider VARCHAR(100) NOT NULL,
    command_type ENUM('start_cycle','stop_cycle','refresh_status') NOT NULL,
    payload JSON NULL,
    status ENUM('pending','sent','acknowledged','failed','timeout','cancelled') NOT NULL DEFAULT 'pending',
    external_reference VARCHAR(255) NULL,
    correlation_id VARCHAR(255) NULL,
    requested_by_user_id BIGINT UNSIGNED NULL,
    requested_by_supervisor_id BIGINT UNSIGNED NULL,
    sent_at TIMESTAMP NULL,
    responded_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_machine_commands_machine FOREIGN KEY (machine_id) REFERENCES machines(id),
    CONSTRAINT fk_machine_commands_user FOREIGN KEY (requested_by_user_id) REFERENCES users(id),
    CONSTRAINT fk_machine_commands_supervisor FOREIGN KEY (requested_by_supervisor_id) REFERENCES supervisors(id)
);

Table machine_events

CREATE TABLE machine_events (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    machine_id BIGINT UNSIGNED NOT NULL,
    provider VARCHAR(100) NOT NULL,
    external_event_id VARCHAR(255) NULL,
    event_type ENUM('heartbeat','machine_online','machine_offline','cycle_started','cycle_completed','cycle_failed','error_reported','status_changed') NOT NULL,
    payload JSON NULL,
    occurred_at TIMESTAMP NOT NULL,
    received_at TIMESTAMP NOT NULL,
    processed_at TIMESTAMP NULL,
    processing_status ENUM('pending','processed','failed','ignored') NOT NULL DEFAULT 'pending',
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_machine_events_machine FOREIGN KEY (machine_id) REFERENCES machines(id)
);

Table machine_status_history

CREATE TABLE machine_status_history (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    machine_id BIGINT UNSIGNED NOT NULL,
    previous_status VARCHAR(50) NULL,
    new_status VARCHAR(50) NOT NULL,
    source VARCHAR(100) NOT NULL,
    reason VARCHAR(255) NULL,
    created_at TIMESTAMP NULL,
    CONSTRAINT fk_machine_status_history_machine FOREIGN KEY (machine_id) REFERENCES machines(id)
);

5.4 Tarification

Table pricing_rules

CREATE TABLE pricing_rules (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    establishment_id BIGINT UNSIGNED NOT NULL,
    machine_id BIGINT UNSIGNED NULL,
    machine_type ENUM('washer_small','washer_large','dryer_small','dryer_large') NULL,
    day_type ENUM('weekday','weekend','holiday','all') NOT NULL DEFAULT 'all',
    slot_start TIME NOT NULL,
    slot_end TIME NOT NULL,
    price DECIMAL(8,2) NOT NULL,
    label VARCHAR(100) NULL,
    requires_app BOOLEAN NOT NULL DEFAULT FALSE,
    priority SMALLINT NOT NULL DEFAULT 100,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_pricing_rules_establishment FOREIGN KEY (establishment_id) REFERENCES establishments(id),
    CONSTRAINT fk_pricing_rules_machine FOREIGN KEY (machine_id) REFERENCES machines(id)
);

Table promotions

CREATE TABLE promotions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    establishment_id BIGINT UNSIGNED NOT NULL,
    machine_type ENUM('washer_small','washer_large','dryer_small','dryer_large','all') NOT NULL DEFAULT 'all',
    discount_type ENUM('percent','fixed') NOT NULL,
    discount_value DECIMAL(8,2) NOT NULL,
    starts_at TIMESTAMP NOT NULL,
    ends_at TIMESTAMP NOT NULL,
    description TEXT NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_promotions_establishment FOREIGN KEY (establishment_id) REFERENCES establishments(id)
);

5.5 Wallet et paiements

Table wallets

CREATE TABLE wallets (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    currency CHAR(3) NOT NULL DEFAULT 'EUR',
    current_balance DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    status ENUM('active','blocked','closed') NOT NULL DEFAULT 'active',
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_wallets_user (user_id),
    CONSTRAINT fk_wallets_user FOREIGN KEY (user_id) REFERENCES users(id)
);

Table payment_transactions

CREATE TABLE payment_transactions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    provider VARCHAR(50) NOT NULL,
    provider_payment_id VARCHAR(255) NULL,
    amount DECIMAL(10,2) NOT NULL,
    currency CHAR(3) NOT NULL DEFAULT 'EUR',
    status ENUM('initiated','pending','succeeded','failed','cancelled','refunded') NOT NULL DEFAULT 'initiated',
    idempotency_key VARCHAR(100) NOT NULL,
    return_url VARCHAR(255) NULL,
    raw_payload JSON NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_payment_idempotency (idempotency_key),
    CONSTRAINT fk_payment_transactions_user FOREIGN KEY (user_id) REFERENCES users(id)
);

Table wallet_transactions

CREATE TABLE wallet_transactions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    wallet_id BIGINT UNSIGNED NOT NULL,
    type ENUM('credit','debit','hold','release','refund','adjustment') NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    balance_before DECIMAL(10,2) NOT NULL,
    balance_after DECIMAL(10,2) NOT NULL,
    source_type VARCHAR(100) NOT NULL,
    source_id BIGINT UNSIGNED NULL,
    idempotency_key VARCHAR(100) NULL,
    metadata JSON NULL,
    created_at TIMESTAMP NULL,
    CONSTRAINT fk_wallet_transactions_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id)
);

5.6 Réservations et lavages

Table bookings

CREATE TABLE bookings (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    machine_id BIGINT UNSIGNED NOT NULL,
    slot_start TIMESTAMP NOT NULL,
    slot_end TIMESTAMP NOT NULL,
    booking_fee DECIMAL(8,2) NOT NULL DEFAULT 0.00,
    reserved_amount DECIMAL(8,2) NOT NULL DEFAULT 0.00,
    penalty_amount DECIMAL(8,2) NOT NULL DEFAULT 0.00,
    status ENUM('pending','confirmed','cancelled','expired','active','completed','no_show') NOT NULL DEFAULT 'pending',
    cancelled_at TIMESTAMP NULL,
    penalty_applied_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_bookings_user FOREIGN KEY (user_id) REFERENCES users(id),
    CONSTRAINT fk_bookings_machine FOREIGN KEY (machine_id) REFERENCES machines(id)
);

Table washes

CREATE TABLE washes (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    machine_id BIGINT UNSIGNED NOT NULL,
    booking_id BIGINT UNSIGNED NULL,
    machine_command_id BIGINT UNSIGNED NULL,
    trigger_method ENUM('qr_code','booking','supervisor','system') NOT NULL,
    status ENUM('pending_start','running','completed','failed','cancelled') NOT NULL DEFAULT 'pending_start',
    program VARCHAR(100) NULL,
    started_at TIMESTAMP NULL,
    ended_at TIMESTAMP NULL,
    duration_minutes INT UNSIGNED NULL,
    cost DECIMAL(8,2) NOT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_washes_user FOREIGN KEY (user_id) REFERENCES users(id),
    CONSTRAINT fk_washes_machine FOREIGN KEY (machine_id) REFERENCES machines(id),
    CONSTRAINT fk_washes_booking FOREIGN KEY (booking_id) REFERENCES bookings(id),
    CONSTRAINT fk_washes_command FOREIGN KEY (machine_command_id) REFERENCES machine_commands(id)
);

5.7 Notifications, audit et statistiques

Table push_notifications

CREATE TABLE push_notifications (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NULL,
    type VARCHAR(100) NOT NULL,
    title VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,
    data JSON NULL,
    status ENUM('pending','sent','failed') NOT NULL DEFAULT 'pending',
    sent_at TIMESTAMP NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    CONSTRAINT fk_push_notifications_user FOREIGN KEY (user_id) REFERENCES users(id)
);

Table audit_logs

CREATE TABLE audit_logs (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    actor_type VARCHAR(50) NOT NULL,
    actor_id BIGINT UNSIGNED NOT NULL,
    organization_id BIGINT UNSIGNED NULL,
    establishment_id BIGINT UNSIGNED NULL,
    action VARCHAR(100) NOT NULL,
    target_type VARCHAR(100) NOT NULL,
    target_id BIGINT UNSIGNED NULL,
    before_data JSON NULL,
    after_data JSON NULL,
    ip_address VARCHAR(45) NULL,
    created_at TIMESTAMP NULL
);

Table daily_establishment_stats

CREATE TABLE daily_establishment_stats (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    establishment_id BIGINT UNSIGNED NOT NULL,
    stat_date DATE NOT NULL,
    total_washes INT UNSIGNED NOT NULL DEFAULT 0,
    total_revenue DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    bookings_count INT UNSIGNED NOT NULL DEFAULT 0,
    no_show_count INT UNSIGNED NOT NULL DEFAULT 0,
    top_up_amount DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    occupancy_rate DECIMAL(5,2) NOT NULL DEFAULT 0.00,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    UNIQUE KEY uniq_daily_establishment_stats (establishment_id, stat_date),
    CONSTRAINT fk_daily_establishment_stats_establishment FOREIGN KEY (establishment_id) REFERENCES establishments(id)
);

6. Contrat d'intégration machine

6.1 Principe

Le backend doit supporter deux scénarios :

  • pull : notre système appelle une API partenaire pour envoyer une commande ou lire un statut,
  • push : le partenaire pousse des événements vers notre système,
  • hybrid : combinaison des deux,
  • simulated : mode démonstration / sandbox.

6.2 Abstraction applicative

interface MachineProviderInterface {
    public function startCycle(Machine $machine, array $payload): MachineCommandResult;
    public function stopCycle(Machine $machine, array $payload = []): MachineCommandResult;
    public function refreshStatus(Machine $machine): MachineStatusSnapshot;
    public function handleInboundEvent(array $payload): void;
}

6.3 Événements entrants attendus

  • heartbeat
  • machine_online
  • machine_offline
  • cycle_started
  • cycle_completed
  • cycle_failed
  • error_reported
  • status_changed

6.4 Endpoints d'intégration proposés

Méthode Endpoint Usage
POST /api/v1/integrations/machines/events Réception d'événements machine
POST /api/v1/integrations/machines/heartbeat Heartbeat passerelle / machine
POST /api/v1/integrations/machines/commands/{uuid}/ack Accusé de réception optionnel

6.5 Payload minimal d'événement

{
  "provider": "client_gateway",
  "event_type": "cycle_completed",
  "occurred_at": "2026-06-27T10:15:00Z",
  "machine_external_id": "MACH-001",
  "correlation_id": "cmd_12345",
  "data": {
    "status": "available",
    "duration_minutes": 42,
    "error_code": null
  }
}

6.6 Exigences minimales côté partenaire

  • identifiant machine externe stable,
  • horodatage fiable,
  • type d'événement,
  • état courant de la machine,
  • identifiant de corrélation si une commande a été envoyée par notre système,
  • stratégie d'authentification technique,
  • documentation des erreurs métiers.

6.7 Mode démonstration

Un provider simulé doit permettre :

  • démarrage immédiat d'un cycle,
  • passage en statut running,
  • émission d'un faux événement cycle_completed après un délai configurable,
  • retour en statut available.

Ce mode permet une démo sans matériel réel.


7. Endpoints API — V1

7.1 Auth utilisateur

Méthode Endpoint Description
POST /api/v1/auth/register Inscription
POST /api/v1/auth/login Connexion utilisateur
POST /api/v1/auth/refresh Renouvellement token
POST /api/v1/auth/logout Déconnexion
GET /api/v1/auth/me Profil courant

7.2 Wallet

Méthode Endpoint Description
GET /api/v1/wallet Solde
GET /api/v1/wallet/transactions Historique
POST /api/v1/wallet/top-up/initiate Démarrer un rechargement
POST /api/v1/wallet/top-up/confirm Confirmation de rechargement
POST /api/v1/wallet/top-up/webhook/{provider} Webhook PSP

7.3 Établissements & machines

Méthode Endpoint Description
GET /api/v1/establishments Liste établissements
GET /api/v1/establishments/{uuid} Détail établissement
GET /api/v1/machines/{uuid} Détail machine
GET /api/v1/machines/{uuid}/availability Créneaux disponibles
GET /api/v1/machines/{uuid}/pricing Tarif actif

7.4 Réservations

Méthode Endpoint Description
POST /api/v1/bookings Créer une réservation
GET /api/v1/bookings Mes réservations
GET /api/v1/bookings/{uuid} Détail réservation
PATCH /api/v1/bookings/{uuid}/cancel Annuler
PATCH /api/v1/bookings/{uuid}/move Déplacer

7.5 Lavages

Méthode Endpoint Description
POST /api/v1/washes/start Démarrer un lavage
GET /api/v1/washes Historique
GET /api/v1/washes/{uuid} Détail

7.6 Superviseur

Méthode Endpoint Description
POST /api/v1/supervisor/auth/login Connexion superviseur
POST /api/v1/supervisor/auth/logout Déconnexion
GET /api/v1/supervisor/dashboard Dashboard
GET /api/v1/supervisor/machines Parc machines
GET /api/v1/supervisor/bookings Réservations
GET /api/v1/supervisor/washes Lavages
GET /api/v1/supervisor/pricing Tarifs
POST /api/v1/supervisor/pricing Création tarif
PUT /api/v1/supervisor/pricing/{id} Modification tarif
GET /api/v1/supervisor/promotions Promotions

8. Règles métier critiques

8.1 Wallet

  • aucune écriture directe de solde hors WalletService,
  • toute opération critique porte une clé d'idempotence,
  • séparation stricte entre transaction de paiement externe et mouvement de wallet interne.

8.2 Réservations

  • un créneau machine ne peut jamais être réservé deux fois,
  • création de réservation sous transaction avec verrou logique,
  • pénalité et remboursement centralisés dans BookingService.

8.3 Lavages

  • un lavage ne peut démarrer que si la machine est éligible,
  • toute commande machine doit être historisée,
  • toute fin de cycle doit être confirmée par événement ou simulation contrôlée.

8.4 Scoping exploitant

  • toute requête superviseur doit être filtrée par organization_id,
  • si establishment_id est renseigné sur le superviseur, la visibilité est limitée à cet établissement.

9. Tâches planifiées

Fréquence Job Description
Toutes les 5 min CheckNoShowBookings Détection des no-shows
Toutes les 5 min RefreshOfflineMachines Contrôle heartbeat / statuts
Toutes les heures SendScheduledNotifications Notifications en attente
Chaque nuit GenerateDailyStats Agrégats journaliers
Chaque nuit PurgeRevokedTokens Nettoyage technique
Chaque semaine AnonymizeInactiveUsers Politique RGPD

10. Sécurité

10.1 Général

  • HTTPS obligatoire,
  • validation stricte des entrées,
  • rate limiting sur auth, paiements et endpoints techniques,
  • headers de sécurité côté web,
  • UUID publics dans l'API.

10.2 Paiements

  • vérification systématique des webhooks,
  • aucune confiance dans le retour client seul,
  • conservation du payload brut du PSP.

10.3 Intégrations machines

  • API key dédiée ou signature HMAC,
  • journalisation des appels,
  • horodatage et contrôle anti-rejeu si possible.

11. Observabilité

  • Sentry backend,
  • logs structurés JSON,
  • suivi des jobs Laravel Horizon,
  • métriques minimales :
    • taux d'échec commandes machines,
    • taux d'échec paiements,
    • machines offline,
    • jobs en échec,
    • no-shows.

12. Tests

Type Outil Portée
Unitaires Pest Wallet, Booking, Pricing, Machine provider
Intégration Pest + MySQL réel Endpoints critiques
Contrat Payloads partenaires Intégration machine / paiement
Charge k6 Wallet, booking, start wash

Cas critiques obligatoires

  • double webhook paiement,
  • double réservation même créneau,
  • timeout commande machine,
  • événement machine reçu en doublon,
  • annulation et no-show simultanés,
  • scoping superviseur inter-organisation.

13. Livrables attendus

  • code source Laravel,
  • migrations et seeders,
  • documentation OpenAPI,
  • .env.example,
  • Docker pour dev,
  • suite de tests critique,
  • mode simulation machine,
  • données de démonstration multi-laveries.