Modules HACCP — fonctionnement interne
Comment fonctionnent techniquement les relevés de température, nettoyages, traçabilité, stocks, planifications, capteurs IoT et l'API publique
Cette page décrit le fonctionnement interne des modules métier pour les développeurs. Pour l'usage produit, voir les pages de la section Fonctionnalités.
Modèle de base : site → lieux → relevés
Une organisation possède des sites (établissements), chaque site des lieux (zones typées : froid, chaud, ambiant, nettoyage, stockage). Les lieux de type froid/chaud portent des consignes seuilMin/seuilMax : tout relevé hors bornes est marqué anomalie: true à l'insertion. L'accès aux données d'un site passe par requireSiteAccess (convex/sites/helpers.ts), qui vérifie l'appartenance à l'organisation.
Températures
convex/temperatures/:createRelevecalcule l'anomalie selon les seuils du lieu ;listBySite,recentAnomaliesBySiteetlastByLieuForSitealimentent la pagetemperatures/et le tableau de bord.- Deux modules frères sur la même page : mises en température (
misesEnTemperature/— refroidissement, remise, cuisson… avec température de début/fin et anomalie) et contrôles d'huile de friture (controlesHuile/— conforme ou non, action : changée/filtrée). - Les relevés issus des sondes IoT ont
userId: "iot:<deviceId>", ce qui permet de les distinguer des saisies manuelles.
Nettoyages
- Les zones de nettoyage (
nettoyageZones/) définissent les checklists d'un lieu (libellé, étapes ordonnées). - Un relevé (
nettoyages/) enregistre les tâches cochéestaches[{libelle, fait}], l'auteur et éventuellement les horodatagesdebutAt/finAt.createNettoyageBatchpermet la saisie groupée. - Les nettoyages planifiés (
nettoyagesPlanifies/) portent unefrequenceJourset uneprochaineEcheancequeadvancerPlanifiefait avancer à chaque réalisation.countDueByOrg/listDueBySitealimentent les rappels dans l'UI.
Traçabilité et stocks
- Deux types d'enregistrements (
tracabilite/) : réception (fournisseur, numéro de BL, lot, DLC, température de réception, conformité livraison, photos R2) et fabrication (ingrédients[{libelle, numLot, quantite}], quantité produite, recettes réutilisables viarecettes/). - Champs conditionnels selon les modules activés (
optionsCheckKit) : allergènes, décongélation, origine viande bovine (naissance/élevage/abattage), expéditions, non-conformités. - Le stock est une vue dérivée de la traçabilité :
stockBySiteliste les produits non sortis ;moveStock,setSortieetconsumeStocktracent chaque opération dansstockMouvements(entrée, mouvement, sortie, retour, modification) — l'historique complet d'un produit est reconstituable. - Étiquettes et registres PDF : générés côté client avec
@react-pdf/renderer(etiquette-pdf.tsx,stock-pdf.tsx,registre-pdf.tsxdans les routes correspondantes).
Alertes DLC
Le cron notify expiring DLC (07:00 UTC, convex/tracabilite/crons.ts) envoie chaque jour un email aux admins listant les produits dont la DLC approche. Le seuil est réglable par organisation (alerteParametres.joursAvant, 1 à 5 jours) et chaque produit n'est alerté qu'une fois (dlcAlerteEnvoyee).
Planification
Trois mécanismes complémentaires, tous rattachés à un site :
| Table | Usage | Avancement |
|---|---|---|
nettoyagesPlanifies | Nettoyages récurrents (fréquence en jours) | advancerPlanifie à la réalisation |
controlesPlanifies | Contrôles récurrents (température, mise en température, huile) | advancerProgramme |
tachesPlanifiees | Rappels ponctuels avec échéance | completeTache (statut non_commence → fait) |
Capteurs IoT
- Enrôlement :
createCapteur(rôles owner/admin uniquement) génère le token côté serveur (32 octets aléatoires hex) ; ledeviceIdest unique. Le token et l'URL du webhook s'affichent dans Paramètres → Capteurs. - Ingestion :
POST /sensors/readingsur le déploiement Convex (*.convex.site), corps JSON :
{ "deviceId": "sonde-chambre-froide-1", "token": "<token>", "temperature": 3.4 }- Sécurité : rate-limit par IP (60 requêtes/min, token bucket), comparaison de token en temps constant, température bornée (−100 à 200 °C), réponse d'erreur générique
401 unauthorized(pas d'énumération des devices). En cas de succès la réponse indique si le relevé est en anomalie :{ "ok": true, "anomalie": false }. - Le relevé est inséré dans
temperatureReadingscomme une saisie normale (anomalie calculée selon les seuils du lieu associé), et le capteur mémoriselastReadingAt/lastTemperature.
API publique v1
- Authentification par clé API d'organisation (Better Auth plugin
apiKey, préfixensk_, expiration 1–365 jours, rate-limit 1000 req/h), passée en headerx-api-keyouAuthorization: Bearer. - Endpoints (
convex/http.ts, accessibles aussi via le proxy web/api/v1/*) :GET /api/v1/me— l'organisation liée à la cléGET /api/v1/members— liste des membresGET /api/v1/members/:memberId— détail d'un membre
- Les clés se créent dans Réglages → Clés API (
settings/api-keys/).
Modules optionnels et démo
optionsCheckKitactive/désactive par organisation les blocs de formulaire avancés (allergènes, décongélation, origine viande, expéditions, non-conformités, documents) — l'UI des wizards de traçabilité s'adapte dynamiquement.demo/(seedDemoData/removeDemoData) installe un jeu de données de démonstration inventorié dansdemoRegistry, ce qui garantit une purge complète sans toucher aux données réelles.export/getFullExportDatafournit l'export intégral des données d'une organisation (page Réglages → Export).