Démarrer
Démarrer
État du système
La forme actuelle d'ItsBagelBot : services, plan de données, bus de messages et transformation d'un message de chat en réponse.
Sur cette page
Cette page documente le système tel qu’il fonctionne aujourd’hui : microservices de données par schéma, bus NATS, ingress Elixir et consoles SvelteKit. Lorsqu’une ancienne page diverge, cette page et le code font foi.
En bref
- Microservices, une responsabilité chacun, déployables indépendamment pour des mises à jour sans interruption.
- Go pour les services de données et de traitement, Elixir/OTP pour l’ingress Twitch, SvelteKit (SSR) pour les consoles des diffuseurs et de l’équipe.
- NATS est le seul transport interservices : pub/sub par sujets et JetStream pour les événements, request-reply pour les RPC. Aucun service ne lit la base d’un autre.
- MySQL HeatWave, un schéma par service de données, accessible via
ent. - Valkey contient la projection des réglages et des niveaux, ainsi que des caches de courte durée.
- Fonctionne sur k3s avec Cilium, derrière un tunnel cloudflared, avec Tailscale pour l’accès des opérateurs.
Services
| Service | Chemin | Langage | Responsabilité |
|---|---|---|---|
| ingress | app/twitch/ingress/ |
Elixir | Conduit EventSub et shards WebSocket Twitch ; supervision par shard ; normalise et publie les événements sur twitch.ingress.event.* ; expose le RPC d’instantané des shards |
| sesame | app/twitch/sesame/ |
Go | Consomme les voies de l’ingress ; exécute modules, commandes personnalisées, minuteurs et AutoMod entrant ; publie des requêtes outgress typées |
| outgress | app/twitch/outgress/ |
Go | Exécute les actions Twitch (chat, gestion EventSub) ; limite de débit par diffuseur via Valkey ; registre des chaînes ; cycle de vie des jetons ; interrupteur d’arrêt |
| projector | app/projector/ |
Go | Construit les projections Valkey à partir des événements des propriétaires ; sert les lectures de niveau, d’état en direct et de tableau de bord ; compteurs et classements en direct |
| users | app/db/users/ |
Go | Comptes, statut (free/paid/vip), rôles du personnel, jetons OAuth Twitch ; émet data.users.* |
| commands | app/db/commands/ |
Go | Commandes de chat personnalisées et définitions de fetch ; émet data.commands.* |
| modules | app/db/modules/ |
Go | Configuration des modules par diffuseur ; émet data.modules.changed |
| loyalty | app/db/loyalty/ |
Go | Soldes des spectateurs, temps de visionnage et compteurs de chaîne |
| transactions | app/db/transactions/ |
Go | Facturation Tebex, concours et remise des récompenses |
| notifications | app/db/notifications/ |
Go | Enregistrements de notifications destinées aux comptes |
| discord-data | app/db/discord/ |
Go | Configuration des serveurs Discord, tickets et XP |
| discord | app/discord/{ingress,engine,outgress}/ |
Go | Session de la passerelle Discord, décisions des modules et effets REST |
| gossip | app/gossip/ |
Go | Passerelle vers les API externes, avec cache et budgets amont |
| release | app/release/ |
Go | CLI du train de publication exécutée par le workflow GitHub Release, une étape par job |
| clusterops | app/clusterops/ |
Go | Redémarre les consoles au renouvellement TLS et garde les claims de comptes NATS à jour |
| console | web/dashboard/, web/admin/ |
SvelteKit SSR | dashboard (libre-service des diffuseurs et pages publiques) et admin (équipe) ; ne parle aux services que par RPC NATS |
CONTEXT-MAP.md à la racine du dépôt liste des emplacements réservés comme app/plain/ et
app/yt-ingress/ ; ce ne sont pas des services en fonctionnement.
Plan de données
- Base de données : MySQL HeatWave. Chaque service de données possède son propre schéma et en est le seul écrivain. Les lectures entre services passent par RPC NATS, jamais par SQL.
- ORM :
ent, code généré par service sousapp/db/<svc>/ent/. - Projection : Valkey stocke la projection des réglages par diffuseur (
settings:<user_id>) lue par le chemin critique. Les écritures de commandes et de modules sont en write-behind (~2 s) : le tableau de bord renvoie une vue optimiste, la base est mise à jour de façon asynchrone, et un événement d’invalidation de cache réaligne les lecteurs. - Cache : des caches en processus de courte durée devant Valkey (par exemple le cache de niveau du projector, TTL de 30 s) absorbent les recherches répétées.
Bus de messages
NATS transporte deux classes de trafic :
- Événements (pub/sub et JetStream). Événements de changement de domaine
data.*, événements d’ingresstwitch.ingress.event.*, état des shardstwitch.ingress.status.*, voies d’envoi outgresstwitch.outgress.*et diffusions d’invalidation de cachebagel.cache.invalidate.<scope>. Le catalogue des flux se trouve danspkg/bus/streams.go. - RPC (request-reply). Tout ce qui est sous
bagel.rpc.*, plus les sujets d’administration de l’ingresstwitch.ingress.admin.*. Voir contrats RPC →.
Les brokers fonctionnent en mode opérateur JWT, avec des comptes et des rôles par service
(deploy/messaging/accounts.yaml) : un service ne peut publier et s’abonner qu’aux sujets que son rôle accorde.
Voies premium / standard
L’ingress oriente chaque événement vers une voie. Le chat des diffuseurs Premium (statut paid ou vip),
ainsi que d’un ensemble configuré d’identifiants spéciaux toujours premium, passe par
twitch.ingress.event.premium ; tous les autres par .standard. Les événements de début et de fin
de stream vont aussi sur .stream. Sesame propage la priorité entrante jusqu’à sa sortie : les réponses
partent donc sur twitch.outgress.premium ou twitch.outgress.standard. Les tâches de contrôle,
comme l’enrôlement EventSub, utilisent twitch.outgress.system. Les diffuseurs inconnus et les
échecs de recherche sont routés en standard.
Flux d’une requête (commande de chat)
- Twitch livre un événement de chat à un shard ingress via le WebSocket du Conduit EventSub.
- L’ingress le normalise et le publie sur
twitch.ingress.event.{premium|standard}. - Sesame consomme la voie, charge les modules et commandes de la chaîne depuis la projection (Valkey, avec repli par RPC auprès du propriétaire), applique les contrôles et construit une réponse.
- La réponse est publiée sur
twitch.outgress.{premium|standard}. - outgress applique la limite de débit par diffuseur et envoie via Helix. Twitch associe
sender_idà l’autorisationuser:botdu bot et à l’autorisationchannel:botdu diffuseur, ce qui affiche le badge Chat Bot sur les réponses éligibles.
Infrastructure
- Cluster : k3s avec un nœud de plan de contrôle ARM portant une taint (
cp1) et trois nœuds de travail étiquetésrole=node. Les images sont compilées nativement pour ARM et Intel et tirées depuis GHCR. Voir Matériel et cluster →. - Réseau : le trafic public entre par le tunnel sortant cloudflared vers Traefik. Les opérateurs atteignent la console admin, la supervision NATS et l’API Kubernetes via Tailscale. Cilium fournit le CNI, et chaque namespace part de politiques de refus par défaut. Voir Réseau →.
- Livraison : GitHub Actions compile les images et le workflow Release les épingle par empreinte dans
deploy/k8s(un test CI impose les empreintes), puis déplace la branchedeploy. Flux synchronise le cluster depuis cette seule branche (deploy/flux). - NATS : trois membres de hub conservent chaque flux JetStream en R3, plus un DaemonSet leaf auquel
les services se connectent (
deploy/messaging/README.md).
Objectifs
- Les mises à jour se font sans interruption. Comme l’anti-affinité d’un pod par nœud ne laisse aucun
nœud libre pour un pod supplémentaire, la plupart des Deployments fixent
maxSurge: 0etmaxUnavailable: 1(deploy/k8s/*.yaml).