Communitygithub.com

timerise-ai/digital-signage

Compétence Agent : construire un module d'affichage dynamique — bibliothèque multimédia, listes de lecture par écran, registre des écrans, appairage par code PIN et URL de provisionnement, lecteur TV plein écran avec récupération de blocage, surveillance de l'état des écrans et contrôle à distance — dans Next.js App Router sur Firestore ou Supabase

Qu'est-ce que digital-signage ?

Cette compétence fournit un module complet d'affichage dynamique (digital signage) conçu pour fonctionner de manière fiable sur des appareils TV peu coûteux fonctionnant sans surveillance pendant des mois. Elle gère la gestion des médias (CRUD) et des playlists, l'enregistrement des écrans, l'appairage sécurisé par code PIN ou URL de provisionnement, ainsi qu'un lecteur plein écran capable de récupérer des blocages. L'architecture repose sur un mécanisme de sondage (polling) toutes les 30 à 60 secondes, garantissant une faible consommation de bande passante et une résilience face aux interruptions réseau. La compétence s'oppose fermement à son utilisation pour la diffusion de publicités web, les bornes interactives ou les vidéos intégrées simples. Les règles strictes incluent : ne jamais dériver l'intervalle de sondage de l'état du rendu, ne pas confondre 'pause' et 'suppression', ne pas faire confiance aux scopes fournis par le client, et ne jamais émettre un jeton partagé entre plusieurs écrans. Le module est conçu pour Next.js App Router avec Firestore ou Supabase/Postgres, et son implémentation suit un guide de démarrage rapide structuré pour garantir une intégration robuste et opérationnelle.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add timerise-ai/digital-signage

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Affichage Numérique — Écrans + Publicités

Un écran dans un lieu n'est pas une page web. Il fonctionne sans surveillance pendant des mois sur une clé TV bon marché, personne ne regarde la console, et le mode de défaillance est une image figée que personne ne remarque pendant une semaine. Chaque décision ci-dessous existe pour survivre à cela.

Cette compétence intègre un module complet : CRUD administrateur pour les médias et les playlists, un registre des écrans, un appairage par code PIN et URL de provisionnement, un lecteur plein écran, et la couche opérationnelle (santé, aperçu, contrôle à distance) qui la rend gérable.

Quand l'utiliser

Construire ou étendre des écrans qui diffusent en boucle des médias dans un espace physique, sur Next.js App Router avec Firestore ou Supabase/Postgres.

Quand NE PAS l'utiliser

  • Diffusion de publicités web (impressions, enchères, pixels de suivi, tags tiers) — un problème différent avec une infrastructure différente.
  • Bornes interactives où l'utilisateur appuie pour effectuer une transaction. L'affichage numérique est unidirectionnel.
  • Une seule vidéo intégrée sur une page marketing. Utilisez une balise <video>.
  • La configuration générique Next.js, CMS ou authentification — considérée comme existante.

Architecture

 ADMIN (navigateur)                SERVEUR                      APPAREIL (TV)
 ─────────────────                 ──────                      ───────────
 téléchargement média ──────────► stockage objet ◄──── URL publique/signée ─┐
 CRUD publicité ─────────┐                                                  │
 édition playlist ───────┼──► /api/admin/*  ──► publicités + écrans ─┐      │
 émettre commande ───────┘      (auth personnel)      (restreint)    │      │
                                                                      ▼      │
 appairer écran ◄──── code PIN ───────────► /api/display/pair        │      │
                                           frappe jeton              │      │
                                           par écran                 ▼      │
                                          /api/display/playlist ────interroger──┤
                                          ▲ résout adIds → publicités          │
                                          └── remonte télémétrie,              │
                                              commandes descendantes     boucle lecteur

Un seul type de requête soutient l'ensemble du runtime : l'appareil interroge /api/display/playlist, remonte la télémétrie et reçoit le contenu et les commandes. Tout ce qui est opérationnel passe par ce canal.

Faits critiques — à lire avant de concevoir quoi que ce soit

  1. La playlist est un tableau ordonné sur l'écran, pas une entité distincte. display.adIds: string[] est la playlist — l'ordre est libre, pas de jointures, une seule lecture. N'introduisez une entité playlist autonome que lorsque le même contenu doit être diffusé sur plusieurs écrans ; voir data-model.md pour le compromis et extensions.md pour la migration.
  2. Interrogez ; ne diffusez pas en continu. Une interrogation toutes les 30 à 60 s est moins coûteuse, survit aux piles réseau en veille et se reconnecte gratuitement. Le temps réel est une mise à niveau facultative, pas la base. Mettez en cache la réponse avec un ETag, sinon vous paierez pour une lecture complète par écran et par interrogation.
  3. Les téléchargements de médias vont du navigateur au stockage directement, jamais via une route API. Les gestionnaires de route ont des limites de taille de corps et brûlent du calcul en proxyant les octets.
  4. L'appareil n'est pas fiable et n'est pas surveillé. Il détient un identifiant de longue durée dans le localStorage sur un matériel auquel n'importe qui peut accéder. Cet identifiant doit être propre à chaque écran et révocable.
  5. Le lecteur ne doit jamais pouvoir s'arrêter. Chaque élément multimédia reçoit un délai d'attente, un gestionnaire d'erreur et un moyen de passer. Un élément défectueux avance ; il ne bloque pas.

Règles strictes

Ne déduisez jamais l'intervalle d'interrogation de l'état de rendu. Interrogez à un intervalle stable et lisez l'état de la diapositive à partir d'une référence. Un minuteur dont l'effet dépend de l'index de la diapositive est détruit et recréé à chaque diapositive, donc un rafraîchissement plus long qu'une diapositive ne se déclencherait jamais ; le contrat de comportement fixe la synchronisation de l'interrogation à l'heure de l'horloge murale.

Ne surchargez jamais un seul booléen pour signifier à la fois « en pause » et « supprimé ». Utilisez active pour l'intention de l'opérateur et un deletedAt séparé pour le cycle de vie, sinon un élément supprimé réapparaît dès que quelqu'un le réactive.

Ne faites jamais confiance à un champ d'application tenant/lieu fourni par le client. Déduisez-le côté serveur à partir de la session du personnel authentifié ou de la ligne d'écran à laquelle le jeton se résout, et imposez-le sur chaque route [id] — en renvoyant 404, pas 403, afin que les identifiants ne puissent pas être sondés.

N'émettez jamais un seul jeton partagé pour tous les écrans. Générez un jeton par écran lors de l'appairage, stockez uniquement son hash, et faites de la révocation une simple mise à jour d'une ligne.

Ne démarrez jamais le minuteur de durée d'une image avant onLoad. Sur une TV lente, la diapositive expirera autrement avant d'être visible.

Ne portez jamais un état d'écran durable dans une commande unique. Le mode vide et la prise de contrôle doivent survivre au rechargement quotidien de l'appareil et à une coupure de courant — transmettez-les comme état à chaque interrogation (mode), et réservez le canal de commande avec accusé de réception effacé pour les commandes véritablement uniques comme le rechargement. Et toute commande dont l'effet est un rechargement doit persister son accusé de réception avant le rechargement, sinon le serveur la redistribue indéfiniment.

Démarrage rapide

  1. Remplissez le contrat d'interface pour votre application et confirmez le changement de nom de domaine — adaptation.md.
  2. Modélisez les entités et choisissez entre tableau et table de jonction — data-model.md.
  3. Créez les tables/collections, les index, les règles de sécurité et le compartiment de médias — firestore-backend.md ou supabase-backend.md.
  4. Construisez les points d'accès de l'appareil et de l'administrateur, y compris l'appairage et la vérification des jetons — api-routes.md.
  5. Appairez un écran — pairing.md — puis intégrez la boucle du lecteur — player-runtime.md.
  6. Construisez le back-office : médiathèque, liste des écrans, éditeur de playlist — admin-ui.md.
  7. Ajoutez la santé, l'aperçu et le contrôle à distance avant la mise en production — operations.md.
  8. Vérifiez par rapport au tableau des contrats de comportement dans player-runtime.md — débranchez le câble réseau, supprimez la publicité en cours en milieu de boucle, émettez un rechargement — et publiez les tests de la machine du lecteur comme couverture de régression.

Répertoire des références

Chargez la référence correspondant aux mots-clés déclencheurs. Pour une conception de novo, lisez data-model.md en premier.

Le code dans api-routes.md et operations.md est écrit avec Firestore comme backend canonique ; supabase-backend.md définit chaque substitution — la table de jonction remplaçant adIds, et les équivalents SQL des fonctions de service.

ScénarioMots-clés déclencheursRéférence
Intégration dans une application existanteadapter, renommer, jointure, intégrer, tenant, application hôteadaptation.md
Entités, champs, forme de la playlistschéma, modèle, Publicité, Écran, playlist, jonction, suppression doucedata-model.md
Backend Firestore/FirebaseFirestore, firebase-admin, règles de sécurité, index composite, Firebase Storagefirestore-backend.md
Backend Supabase/PostgresSupabase, Postgres, RLS, migration, bucket de stockage, Realtimesupabase-backend.md
Points d'accès, appairage, jetons, mise en cacheRoute API, appairage, code PIN, jeton, ETag, vérification de portée, zodapi-routes.md
Appairer un écranappairage, code PIN, URL de provisionnement, concentrateur, identifiant, désappairerpairing.md
Boucle du lecteur TVlecteur, boucle, fondu enchaîné, blocage vidéo, rotation, portrait, verrouillage de veille, hors ligneplayer-runtime.md
Interface back-officeadmin, téléchargement, médiathèque, éditeur de playlist, URL de provisionnementadmin-ui.md
Santé, aperçu, contrôle à distancebattement de cœur, dernière apparition, hors ligne, aperçu, rechargement, mode vide, prise de contrôle d'urgence, journal d'auditoperations.md
Planification, réutilisation, rapportsdiffusion par plages horaires, date de début, campagne, playlist partagée, preuve de diffusion, pré-mise en cache, multi-zoneextensions.md
Pourquoi les modèles diffèrent d'un portage naïfprovenance, registre, justification, conservé, ajoutéprovenance.md

Skills associés