28 KiB
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
heartbeatmachine_onlinemachine_offlinecycle_startedcycle_completedcycle_failederror_reportedstatus_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_completedaprè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_idest 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.