Développement & connexion à la base¶
Dépôt¶
- GitHub :
mcmccservices-coder/Alarmes(privé) - Branche de travail :
main(mono-intervenant pour l'instant) - Continuité entre sessions : voir
CLAUDE.mdetSESSION_LOG.mdà la racine du repo (mécanisme Collaboration multi-session)
Se connecter à la base Supabase¶
Pas de psql installé sur le poste de dev actuel — connexion via Python (psycopg2).
Récupérer la chaîne de connexion¶
Piège IPv6
La chaîne "Direct Connection" du dashboard Supabase (db.<ref>.supabase.co) ne résout qu'en
IPv6 — elle échoue sur la plupart des réseaux locaux (getaddrinfo failed). Utiliser la chaîne
Transaction pooler à la place (IPv4, host aws-0-<région>.pooler.supabase.com:6543).
Lien direct pour l'ouvrir avec le bon mode pré-sélectionné (remplacer <ref> par la référence du projet,
voir architecture) :
https://supabase.com/dashboard/project/<ref>?showConnect=true&method=transaction
Copier la chaîne URI (commence par postgresql://postgres.<ref>:...).
Stocker la chaîne localement¶
Ne jamais coller la chaîne de connexion dans un fichier suivi par git ni dans le chat. Créer un fichier
.env à la racine du repo (déjà dans .gitignore) contenant une seule ligne :
postgresql://postgres.<ref>:<mot-de-passe>@aws-0-<région>.pooler.supabase.com:6543/postgres
Appliquer le schéma et les données de test¶
Le schéma (db/schema.sql) et les données de test (db/seed.sql) sont versionnés dans le repo — voir
modèle de données. Ils s'appliquent avec psycopg2 en lisant .env :
import psycopg2
with open('.env') as f:
url = f.read().strip()
with open('db/schema.sql', encoding='utf-8') as f:
sql = f.read()
conn = psycopg2.connect(url)
conn.cursor().execute(sql)
conn.commit()
Même principe pour db/seed.sql, à exécuter après schema.sql.
Interface (UI)¶
Premier jet d'écrans généré avec Claude Design (2026-08-29) : tableau de tâches tablette (mode kiosque),
écran d'appairage QR code, vue téléphone personnel, vue responsable. Export commité dans le repo sous
Alarmes — PWA horeca.zip (design_handoff_alarmes/).
Écran kiosque (app/src/screens/Kiosque.jsx) reconstruit fidèlement à ce handoff : thème nuit/jour
(bascule manuelle, préférence en localStorage), grille 3×3 de tâches, validation nominative. Champs du
handoff pas encore en base (urgent, photo_requise, type ponctuelle/checklist) volontairement omis de
cet écran — voir points ouverts.
Robustesse de la grille kiosque
La maquette du designer est calibrée pour une tablette 1280×800 précise. Sur une fenêtre de taille
différente, l'en-tête peut grignoter trop de place et couper le pied des cartes. Fix appliqué dans
App.css : grid-auto-rows: minmax(170px, 1fr) + overflow-y: auto sur .grille-taches — dégrade en
léger défilement plutôt que de couper le contenu si l'espace est serré.
Temps réel (Realtime)¶
La table alarmes est ajoutée à la publication supabase_realtime (bloc idempotent dans db/schema.sql).
Le kiosque et l'écran mobile s'abonnent via postgres_changes (INSERT/UPDATE/DELETE) et mettent à jour
l'état local sans refetch — voir Kiosque.jsx et Mobile.jsx. Le point vert de l'en-tête reflète l'état
réel du channel (SUBSCRIBED ou non), avec un bandeau d'alerte si la connexion tombe.
Appairage QR / devices¶
Table pairing_tokens (jeton éphémère, 5 min, lié à un poste — pas à une personne pour l'instant, voir
points ouverts). Flux : le kiosque génère un jeton + un QR
(qrcode), l'URL encodée contient ?appairage=<jeton> ; App.jsx route vers l'écran Appairage.jsx qui
valide le jeton et crée une ligne devices ; le token de ce device est mémorisé en localStorage sur le
téléphone pour les visites suivantes (App.jsx route alors vers Mobile.jsx).
crypto.randomUUID() et contexte sécurisé
crypto.randomUUID() exige un contexte sécurisé (HTTPS, ou localhost/127.0.0.1) — indisponible en
HTTP simple sur une IP réseau (utile pour tester depuis un vrai téléphone en dev). Remplacé par
crypto.getRandomValues() (app/src/lib/token.js), qui fonctionne dans tous les contextes.
Tester avec un vrai téléphone : localhost/127.0.0.1 n'est joignable que depuis le PC de dev. Deux
options :
- Exposer le serveur de dev sur le réseau local (
npm run dev -- --host 0.0.0.0) et ouvrir le kiosque via l'IP réseau du PC (ipconfig/Get-NetIPAddress) — nécessite le même Wi-Fi, peut buter sur une isolation AP du routeur (fréquente sur les réseaux "Invité"). - Plus simple : déployer sur Cloudflare Pages (
wrangler pages deploy, voir ci-dessous) — URLhttps://joignable de partout, et ça évite le problèmecrypto.randomUUID()par la même occasion (HTTPS = contexte sécurisé).
Déploiement du front¶
Projet Cloudflare Pages alarmes → https://alarmes.pages.dev (voir
architecture).
Intégration Git continue (depuis le 2026-08-30) : chaque git push sur main déclenche automatiquement
un build + déploiement côté Cloudflare — pas de commande à lancer à la main. Config du projet :
- Source : dépôt GitHub
mcmccservices-coder/Alarmes, branche de prodmain root_dir:app(monorepo — la doc MkDocs et le front cohabitent dans le même dépôt)build_command:npm install && npm run builddestination_dir:dist- Variables d'environnement (
VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY) configurées côté Cloudflare (Production et Preview) — plus besoin que le poste qui déploie aitapp/.env.local.
Pour changer cette config (ex. mettre à jour les clés Supabase si le projet change) : dashboard Cloudflare
→ projet alarmes → Settings, ou via l'API Cloudflare Pages (PATCH /accounts/{id}/pages/projects/alarmes
avec deployment_configs).
Avant le 2026-08-30 : déploiement manuel (direct upload)
Le projet a d'abord été créé en mode direct upload (wrangler pages deploy) pour tester rapidement
sans configurer l'intégration Git — pratique pour un test ponctuel, mais un projet Direct Upload ne
peut pas être converti en projet Git après coup côté API (You cannot update the source object in
a Direct Uploads project) : il a fallu supprimer le projet et le recréer directement en mode Git.
Compression d'images (prévue)¶
Pas encore implémentée. Approche prévue pour réduire la taille des photos avant upload vers Supabase Storage (les photos de téléphone en haute définition sont inutilement lourdes pour une simple preuve visuelle) :
import imageCompression from 'browser-image-compression'
async function compresserPhoto(fichier) {
return imageCompression(fichier, {
maxWidthOrHeight: 1600,
maxSizeMB: 0.5,
useWebWorker: true,
})
}
Réduit typiquement une photo de 3-8 Mo à 100-400 Ko. Voir architecture pour le choix de Supabase Storage comme cible.