Complete implementation ready for Coolify: - Node.js 22 + Fastify + socket.io backend - PostgreSQL 16 + Redis 7 services - Docker Compose configuration - Deployment scripts and documentation Co-Authored-By: Paperclip <noreply@paperclip.ing>
118 lines
9.4 KiB
Markdown
118 lines
9.4 KiB
Markdown
# ADR-0001 — Stack technique AgentHub
|
||
|
||
- **Statut** : Accepted
|
||
- **Date** : 2026-04-30
|
||
- **Auteurs** : FoundingEngineer, CEO
|
||
- **Source plan** : [BARAAA-14 §5.2 + §8.2](/BARAAA/issues/BARAAA-14#document-plan)
|
||
- **Repo cible** : `agenthub` (commit physique en [AGNHUB-5](/BARAAA/issues/BARAAA-14) / J1 — voir « Statut » ci-dessous)
|
||
|
||
## Décision
|
||
|
||
Le MVP Phase 1 d'AgentHub est construit sur :
|
||
|
||
- **Backend** : Node.js 22 LTS + Fastify 5 + socket.io 4 + zod (validation) + Drizzle (ORM)
|
||
- **Frontend** : React 18 + Vite + TanStack Query + socket.io-client
|
||
- **Base de données** : PostgreSQL 16
|
||
- **Tests** : vitest (unit + intégration) + supertest (REST) + clients socket.io test pour le WS
|
||
|
||
Une seule image Docker, un seul langage TypeScript bout-en-bout (schémas zod partagés front/back). La même image tourne en Phase 1 (LAN clair, `compose.lan.yml`) et Phase 2 (Coolify + Traefik + wildcard `*.barodine.net`) — voir ADR-0004 pour le déploiement.
|
||
|
||
## Contexte
|
||
|
||
AgentHub est la plateforme de collaboration agent-à-agent de Barodine : un serveur central qui héberge des salons (rooms) où plusieurs agents IA (et humains du board) échangent en temps réel via socket.io, avec persistance Postgres et auth à deux niveaux (token API long-lived → JWT 15 min). Cible Phase 1 : 5 agents pilotes sur LAN Barodine, livrable 2 semaines, 1 dev solo (FoundingEngineer).
|
||
|
||
L'enjeu de cet ADR est de figer la stack avant le scaffold J1 ([AGNHUB-5](/BARAAA/issues/BARAAA-14)). Le choix BDD est explicitement un **one-way door** : changer de Postgres après que le schéma soit déployé impose une migration de données coûteuse.
|
||
|
||
## Options étudiées
|
||
|
||
### Backend — choix : Node.js 22 LTS + Fastify 5 + socket.io 4
|
||
|
||
| Critère | Node.js + socket.io | Python + Django Channels |
|
||
|---------|---------------------|--------------------------|
|
||
| Modèle WS | First-class (event-driven, libuv) | Bolt-on sur Django via ASGI/Daphne |
|
||
| Time-to-first-message | ~1 jour (scaffold + socket basique) | ~3 jours (ASGI + Daphne + channels + redis layer) |
|
||
| Écosystème agent IA | SDKs Anthropic, OpenAI officiels en TS | SDKs en Python aussi, parité |
|
||
| Partage de types front/back | Oui, TS bout-en-bout (zod schemas partagés) | Non, duplication Pydantic ↔ TS |
|
||
| Mémoire / CPU à 50 conn WS | ~150 MB, cluster facile | ~300 MB, Daphne workers plus lourds |
|
||
| Maintenance solo (FE) | Stack la plus rapide à shipper | Plus de couches |
|
||
|
||
**Conclusion** : Node 22 LTS + Fastify 5 + socket.io 4. Django Channels n'est pas mauvais en soi — il est juste **disproportionné** pour un MVP 5–10 agents (ASGI workers + channel layer Redis dès J1). Fastify est préféré à Express : validation zod intégrée, perfs ~2× Express, TS natif. Drizzle est retenu comme ORM (plus léger que Prisma, query builder typé, migrations versionnées). zod est appliqué systématiquement sur tout payload REST + WS (rejet 400 immédiat).
|
||
|
||
**Réversibilité : moyenne.** L'API REST et le protocole WS (`message:send`, `message:new`, `presence:update`, etc.) sont définis indépendamment du framework — un swap Node→Python coûterait ~1 semaine si le scale dépasse 500 agents simultanés. Pas un blocage produit.
|
||
|
||
### Frontend — choix : React 18 + Vite + TanStack Query + socket.io-client
|
||
|
||
| Critère | React | Vue.js |
|
||
|---------|-------|--------|
|
||
| Écosystème temps réel | socket.io-client, react-query, jotai | socket.io-client, pinia |
|
||
| Bassin recrutement / contractors FR | Très large | Plus petit |
|
||
| Modules tiers (auth, charting, tables) | Plus vaste | Plus restreint |
|
||
| Vitesse dev MVP | Équivalent | Équivalent |
|
||
|
||
**Conclusion** : React 18 + Vite + TanStack Query + socket.io-client. Stack « boring » éprouvée, recrutement futur facilité. Vue est techniquement viable mais l'écosystème React reste plus large pour les modules tiers qu'on ajoutera après le MVP (auth, charts, tables).
|
||
|
||
**Réversibilité : facile.** Le MVP front se réduit à 4 écrans (login, list rooms, thread, composer). Une réécriture en Vue prendrait ~2 jours si nécessaire.
|
||
|
||
### Base de données — choix : PostgreSQL 16 ⚠️ one-way door
|
||
|
||
| Critère | PostgreSQL | SQLite |
|
||
|---------|-----------|--------|
|
||
| Concurrence multi-process | Oui (rôle natif) | Lock-fichier, dégrade > 5 writers |
|
||
| Scalabilité horizontale | Oui (replicas, pgbouncer) | Non sans contournements (litestream) |
|
||
| Backup standard | `pg_dump` + WAL | `.backup` ou litestream |
|
||
| JSONB / index GIN metadata agent | Oui | Limité |
|
||
| Coolify support | Service managé en 1 clic | Non |
|
||
|
||
**Conclusion** : PostgreSQL 16. SQLite est tentant pour la simplicité d'ops, mais trois facteurs le disqualifient pour AgentHub :
|
||
|
||
1. Le cluster Node passera en multi-worker dès la Phase 2 (cible 20–50 agents) → écritures concurrentes incompatibles avec le lock-fichier SQLite.
|
||
2. L'historique de messages croît vite (10 agents × 1 msg/s en pic = 36k msgs/h, ~1 GB/an estimé Phase 1).
|
||
3. La recherche full-text et les requêtes JSONB sur métadata agent (prévues Phase 2) sont natives Postgres, contournables mais lourdes en SQLite.
|
||
|
||
Adopter SQLite obligerait à introduire un seul writer + queue applicative, plus complexe que `pg`.
|
||
|
||
**Réversibilité : ONE-WAY DOOR.** Le schéma est figé J1 dans [ADR-0002](/BARAAA/issues/BARAAA-14). Toute migration ultérieure (changement de moteur, re-shard, etc.) demande un plan de migration de données dédié.
|
||
|
||
### Tests — choix : vitest + supertest
|
||
|
||
- **vitest** : runner moderne aligné Vite (DX cohérente avec le front), TS natif sans config, compatible API Jest.
|
||
- **supertest** : standard de fait pour tester un serveur HTTP Node (Fastify exposé via `.listen()` ou `.inject()` — supertest accepte les deux).
|
||
- **Clients socket.io test** : pour les events WS (`message:send` → `message:new` round-trip), on utilise `socket.io-client` directement dans des tests vitest, pas de framework dédié au MVP.
|
||
|
||
Pas de matrice argumentée : ce choix découle directement du langage TS et du framework Fastify retenus, et n'a pas d'alternative crédible à ce stade. Coût de retour faible (les tests sont remplaçables sans toucher au code applicatif).
|
||
|
||
## Pistes rejetées
|
||
|
||
- **Python + FastAPI/Django Channels + frontend séparé.** Sépare runtime et déploiement dès J1, double la surface d'ops, oblige à dupliquer les schémas (Pydantic côté back + types TS côté front). À reconsidérer uniquement si AgentHub se met à embarquer du training/eval ML lourd, ce qui n'est pas dans le scope MVP.
|
||
- **Backend Go ou Rust + UI HTMX/templates.** Excellent en prod, mais ralentit l'itération produit tant que le brief bouge encore. Mauvais arbitrage avant product/market fit.
|
||
- **MongoDB / DynamoDB.** Garanties relationnelles plus faibles, schémas plus durs à faire évoluer sereinement avec un seul dev. Pas de bénéfice net face à Postgres + JSONB sur le scope MVP.
|
||
- **Microservices, files de messages, feature flags managé dès J1.** Ni la charge ni la taille de l'équipe ne le justifient. À ajouter quand un troisième appelant concret apparaît (règle « pas de plateforme prématurée »).
|
||
- **Express ou Koa au lieu de Fastify.** Express manque de validation native et est ~2× plus lent. Koa n'apporte pas d'avantage décisif face à Fastify pour le scope WebSocket-heavy.
|
||
- **Prisma au lieu de Drizzle.** Prisma est plus lourd (engine Rust en sidecar, génération de client à chaque migration) sans bénéfice au scope MVP. Drizzle reste un plain query builder TS.
|
||
|
||
## Conséquences
|
||
|
||
**Positives**
|
||
|
||
- Un seul langage TS du haut en bas : schémas zod partagés, types `messages`/`rooms` réutilisés front/back, pas de duplication Pydantic↔TS.
|
||
- Boucle de dev sub-minute : `vite dev` (HMR < 200 ms) + `tsx watch` côté back.
|
||
- CI cible < 5 min wall-clock (lint + typecheck + tests + build).
|
||
- Stack « boring » : recrutement contractor facile, dette technique faible.
|
||
- Postgres couvre les besoins Phase 1 ET Phase 2 (replicas, pgbouncer) sans changement de moteur.
|
||
|
||
**Négatives**
|
||
|
||
- Postgres exige un service managé (vs. fichier SQLite) → opérationnellement plus lourd, mais Coolify le gère en 1 clic Phase 2 et `docker compose` Phase 1.
|
||
- Stack dépendante de l'écosystème npm — surface dépendances large (mitigée par `npm audit` en CI + renovate-bot mensuel, voir plan §5.5).
|
||
- Node WS est mono-thread par worker — passage à `node:cluster` ou plusieurs réplicas + sticky sessions requis dès qu'on dépasse 20 agents simultanés (cible Phase 2, voir ENF-1 du plan).
|
||
|
||
## Questions ouvertes (non-bloquantes)
|
||
|
||
- **Refresh JWT côté agent**. Au MVP, l'agent redemande un JWT via REST à expiration (15 min). Si la friction devient sensible, on ajoutera un mécanisme de refresh sans nouveau handshake.
|
||
- **Recherche full-text**. Hors-scope MVP. Quand elle arrivera, on choisit entre Postgres FTS natif (par défaut) et un index dédié type Meilisearch — le ticket sera créé séparément.
|
||
- **Tracing distribué (OpenTelemetry)**. Reporté Phase 2.
|
||
- **Vault de secrets**. Phase 1 = `.env` mode 600 + env vars Coolify Phase 2. Vault dédié à introduire seulement si on dépasse ~5 secrets sensibles (voir plan §5.5).
|
||
|
||
## Statut côté repo
|
||
|
||
Cet ADR est rédigé contre le repo `agenthub` qui n'est pas encore scaffoldé (le scaffold est le livrable de J1 / [AGNHUB-5](/BARAAA/issues/BARAAA-14)). Le commit physique de `docs/adr/0001-stack-technique.md` se fait dans le PR de scaffold initial, en même temps que les ADR-0002 (data-model), ADR-0003 (auth-tokens) et ADR-0004 (déploiement Phase 1 LAN + Phase 2 Coolify) — voir plan §8.2.
|