ADR-04: QR Code
Génération, personnalisation, token rotatif, format d'export
Contexte
Le QR code est le point d'entrée physique du système. Il doit être :
- Personnalisable (logo, couleurs) pour que l'établissement se l'approprie
- Sécurisé (token rotatif pour empêcher l'abus à distance)
- Imprimable en haute qualité
Décision
Génération côté serveur avec token rotatif dans l'URL.
Structure de l'URL
https://app.wcare.fr/report/{toiletId}/{token}toiletId: UUID du WC (stable, ne change jamais)token: Token rotatif (UUID v4, change périodiquement)
Personnalisation
Stockée en JSONB dans la table qr_code :
{
"logo": "https://cdn.wcare.fr/logos/hotel-xyz.png",
"foregroundColor": "#1a1a1a",
"backgroundColor": "#ffffff",
"style": "rounded",
"errorCorrection": "H"
}- Error correction "H" (30%) obligatoire quand un logo est présent
- Formats d'export : SVG (web), PNG (aperçu), PDF (impression)
Rotation de token
| Paramètre | Valeur |
|---|---|
| Durée de validité | 7 jours (configurable) |
| Ancien token | Redirige vers le nouveau pendant 24h |
| Après 24h | Ancien token → erreur "QR code expiré, scannez à nouveau" |
| Déclenchement | Cron job quotidien |
Le QR code physique ne change pas (il encode l'URL fixe avec toiletId). Seul le token dans l'URL est validé côté serveur.
Correction : En fait, le QR physique encode l'URL complète incluant le token.
Quand le token est roté, l'ancien QR continue de fonctionner grâce au redirect
via previousToken. L'établissement n'a pas besoin de réimprimer.
Alternatives écartées
| Alternative | Raison du rejet |
|---|---|
| QR statique sans token | Aucune protection anti-abus |
| QR dynamique (short URL) | Dépendance à un service tiers, latence |
| NFC tags | Coût unitaire plus élevé, pas universel |
| URL fixe avec CAPTCHA | Plus de friction pour l'utilisateur |
Conséquences
- Positif : Protection anti-photo (le token expire)
- Positif : Personnalisation full (logo, couleurs)
- Positif : Pas besoin de réimprimer (redirect graceful)
- Attention : Le cron de rotation doit être fiable
- Attention : Error correction H réduit la densité d'info — l'URL doit rester courte