Documentation officielle du projet

Architecture du système

ZEvent Bot est une architecture serverless entièrement exécutée sur Cloudflare. Discord envoie les commandes par HTTP, trois collecteurs surveillent les sources de données et une file fiable distribue les notifications sans serveur Node.js permanent ni connexion au Gateway Discord.

Idée principale

D1 conserve l’état fiable du produit, Analytics Engine conserve les séries de mesures, les Durable Objects coordonnent les opérations qui doivent rester ordonnées et Queues absorbe les pics de notifications avec des retries automatiques.

Vue globale

Sources externes

DiscordInteractions HTTP, OAuth, Event Webhooks et API REST
API ZEventLives, calendrier officiel, cagnotte et audience
Team G-DocPlanning, participants et donation goals
Twitch HelixÉtat live complémentaire, désactivé par défaut

Cloudflare Workers

Runtime DiscordCommandes, installations, maintenance et livraisons
Collecteur ZEventDurable Object, alarme adaptative 60 s / 15 s
Collecteur G-DocGoals 60 s / 30 s, planning 2 min / 5 min
Collecteur TwitchDurable Object, alarme toutes les 60 secondes

État, transport et mesures

D1 · zevent-botConfiguration, données normalisées, outbox et journaux
Queues + DLQNotifications asynchrones, retries et échecs définitifs
Analytics EngineActivité, snapshots, collecteurs et livraisons

Accès aux données

API publiqueStats, événement, audience, historique et statut assaini
API d’administrationOAuth Discord, guildes, diagnostics, audit et Test Lab

Cloudflare Pages

Site publicPrésentation, installation, statistiques et statut
Panneau adminInterface sécurisée connectée directement à l’API admin
DocumentationPages statiques sans accès aux secrets ni à D1

Inventaire des applications

Application Déclencheurs Responsabilité
zevent-discord-bot HTTP, Queue et Cron chaque minute Interactions Discord, installations, événements planifiés, maintenance et livraisons.
zevent-source-zevent Cron chaque minute, alarme 60 s hors événement et 15 s pendant Lives, calendrier officiel, cagnotte, audience et snapshots publics.
zevent-source-gdoc Goals 60 s / 30 s ; planning 2 min / 5 min Donation goals, participants et planning Team G-Doc.
zevent-source-twitch Cron chaque minute, alarme toutes les 60 s État live Helix et alertes optionnelles.
zevent-public-api HTTP GET et Cron chaque minute Agrégation et exposition en lecture seule des statistiques et du statut.
zevent-admin-api HTTP et Cron toutes les 10 minutes OAuth, droits, inventaire Discord, audit, diagnostics et messages de test.
zevent-bot-site Cloudflare Pages Site public statique appelant directement l’API publique.
zevent-bot-admin Cloudflare Pages Panneau statique appelant directement l’API admin avec les cookies OAuth.
zevent-bot-docs Cloudflare Pages Cette documentation statique, sans connexion à une API ou une base.

Comment une donnée devient une notification

  1. 1Le Cron réveille le collecteur.Toutes les minutes, le Cron vérifie l’alarme du Durable Object. L’alarme déclenche ensuite la collecte à la fréquence propre de la source.
  2. 2La source externe est interrogée.Le Worker valide et normalise la réponse ZEvent, G-Doc ou Twitch, puis compare le snapshot à l’état précédent du Durable Object.
  3. 3D1 reçoit l’état durable.Les streamers, événements, goals, métriques publiques et états de santé sont enregistrés. La première collecte initialise l’état sans rejouer d’anciennes alertes.
  4. 4Les abonnements sont résolus.Pour chaque changement pertinent, le collecteur lit les guildes et utilisateurs abonnés puis crée une ligne dédupliquée dans l’outbox notification_deliveries. La destination indique explicitement s’il s’agit d’un salon ou d’un DM.
  5. 5Queues absorbe la charge.L’identifiant de livraison rejoint zevent-notifications. Le collecteur n’attend donc jamais que Discord ait accepté tous les messages.
  6. 6Le Dispatcher ordonne les appels Discord.Le consumer transmet le travail au Durable Object DISCORD_DISPATCHER, qui sérialise les appels REST, respecte les délais de rate limit et utilise un nonce idempotent.
  7. 7Les erreurs sont rejouées ou isolées.Les réponses 429 et 5xx sont retentées jusqu’à cinq fois. Une livraison épuisée rejoint zevent-notifications-dlq et est marquée en échec dans D1.
  8. 8La télémétrie est enregistrée.Analytics Engine reçoit le volume, le résultat et les latences. D1 garde 48 heures de journal détaillé pour alimenter /v1/status.

Rôle de chaque technologie Cloudflare

Service Utilisation dans le projet Pourquoi
Workers Runtime Discord, trois collecteurs, API publique et API admin. Exécuter du TypeScript à la demande, sans machine ni processus permanent.
Pages Site public, panneau admin et documentation. Servir des fichiers statiques mondiaux ; les navigateurs appellent les APIs en HTTPS.
D1 Une base SQLite serverless partagée nommée zevent-bot. Conserver l’état métier transactionnel et requêtable entre les exécutions.
Queues File principale zevent-notifications et dead-letter queue. Découpler la collecte de Discord, lisser les pics et rejouer les erreurs temporaires.
Durable Objects Un poller par source et un DISCORD_DISPATCHER global. Obtenir un état cohérent, des alarmes précises et une exécution ordonnée.
Analytics Engine Quatre datasets de séries temporelles opérationnelles et produit. Agréger de gros volumes de compteurs sans transformer D1 en base analytique.
Service Bindings Le runtime appelle directement les trois collecteurs privés. Communication Worker-to-Worker sans URL publique ni secret réseau supplémentaire.
Cron Triggers Amorçage des pollers, maintenance, stats publiques et inventaire admin. Déclencher les travaux périodiques sans scheduler externe.
Observability Logs Journaux séparés pour chacun des Workers. Diagnostiquer une source ou une livraison sans mélanger les services.
Web Analytics Mesure optionnelle du trafic du site Pages public. Analyser les visites du site ; ce service est distinct d’Analytics Engine.

Ce que contient D1

D1 est la source de vérité durable. Les tables sont regroupées en cinq usages :

Les migrations sont versionnées dans le dépôt et appliquées par GitHub Actions avant les Workers qui dépendent du nouveau schéma. La production et le staging utilisent des bases distinctes.

Durable Objects et cohérence

Objet État coordonné Fonction
ZEventPoller Dernier snapshot officiel Compare les lives et événements toutes les 60 secondes, puis 15 pendant l’édition.
GDocPoller Dernier snapshot communautaire Compare les goals toutes les 60 s / 30 s et le planning toutes les 2 min / 5 min.
TwitchPoller Streams et jeton Helix temporaire Suit Twitch toutes les 60 secondes lorsqu’il est activé.
DISCORD_DISPATCHER Ordre des requêtes et prochain délai Sérialise les messages et événements Discord pour gérer les rate limits.

Les Durable Objects ne remplacent pas D1 : leur stockage représente l’état de coordination d’une instance, tandis que D1 reste la source de vérité partagée par toutes les applications.

Analytics et page de statut

Dataset Données enregistrées Consommateur
zevent_activity Commandes et notifications réussies ou échouées, type et durée. API publique et dashboard admin.
zevent_snapshots Cagnotte, audience, streamers en ligne, guildes et utilisateurs. Graphiques publics et statistiques avancées.
zevent_collectors Passages, durée, volumes, changements, backoff et erreurs par source. Suivi de fraîcheur et diagnostic des crawlers.
zevent_deliveries Succès, retries, échecs, codes HTTP et latences de livraison. Page de statut et analyse de la qualité des notifications.

L’API publique expose un snapshot assaini sur /v1/status. Elle ne publie jamais les identifiants Discord ni les messages d’erreur bruts. Aucun Tail Worker n’est requis : les métriques sont enregistrées directement au moment où le résultat est connu.

Commandes, installation et administration

Discord appelle https://bot.zevent.app/discord/interactions pour les commandes et https://bot.zevent.app/discord/events pour les événements d’installation. Le runtime vérifie la signature Discord avant tout traitement. Après une autorisation utilisateur, le Dispatcher tente d’ouvrir un DM pour envoyer le guide d’accueil. Les réglages de serveur et abonnements personnels sont stockés séparément dans D1 ; les réponses immédiates repartent par HTTP et toutes les alertes futures utilisent la même Queue.

Le panneau Pages appelle directement https://admin-api.zevent.app/. L’API admin réalise l’OAuth avec Discord, vérifie l’appartenance au serveur officiel et les rôles autorisés, crée une session sécurisée, protège les mutations par CSRF et journalise les actions sensibles. Les messages de l’espace Aperçu & test suivent exactement la même Queue et le même Dispatcher que la production. L’explorateur de données admin est lui strictement en lecture seule sur D1.

Déploiement et isolation

Le monorepo PNPM utilise TypeScript, Node.js pour les outils de build et Wrangler pour Cloudflare. Node.js n’est pas un serveur de production : GitHub Actions installe, teste, construit, applique les migrations D1 et déploie uniquement les workspaces modifiés. Les trois collecteurs restent trois scripts Cloudflare distincts, avec des logs et des déploiements séparés.

Ce qui n’est pas utilisé

Il n’y a ni PostgreSQL, ni Redis, ni Discord.js, ni shard Gateway. Les interactions HTTP et les services Cloudflare remplacent ces composants pour cette architecture Cloudflare-only.