Aller au contenu

Développement & connexion à la base

Dépôt

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 :

  1. 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é").
  2. Plus simple : déployer sur Cloudflare Pages (wrangler pages deploy, voir ci-dessous) — URL https:// joignable de partout, et ça évite le problème crypto.randomUUID() par la même occasion (HTTPS = contexte sécurisé).

Déploiement du front

Projet Cloudflare Pages alarmeshttps://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 prod main
  • root_dir : app (monorepo — la doc MkDocs et le front cohabitent dans le même dépôt)
  • build_command : npm install && npm run build
  • destination_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 ait app/.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.