telaria-app â architecture de l'application assemblĂ©e
Ce que c'est
telaria-app est une application web Symfony 8 / PHP ℠8.4 conçue comme un assembleur mince. Elle ne porte pas l'essentiel de la logique métier : celle-ci vit dans quatre bundles maison qu'elle wire et surcharge. L'application apporte, en propre : la couche utilisateur/authentification, la surface web (contrÎleurs, routes, templates), l'API, et quelques extensions applicatives (SEO, config chatbot, validation IA de la veille, anti-spam IA du contact).
Elle sert une vitrine web multi-sites, deux viewers de documentation, des assistants conversationnels RAG, un espace lecteur connecté, un formulaire de contact protégé et un back-office /admin de production doc-IA.
FrontiĂšres de composition
L'application se compose de quatre bundles maison plus son propre cĆur applicatif. Chaque bundle est une dĂ©pendance Composer (VCS) enregistrĂ©e pour tous les environnements.
| Domaine | Fourni par | RĂŽle de telaria-app |
|---|---|---|
| CMS, multisite, contact, i18n, markdown, settings, hub de config | bundle CMS/socle | ContrĂŽleurs de surface, companion SEO, choix des routes vitrine |
| Produit doc-IA : veille, chat, docs, metrics | bundle produit doc-IA | ContrĂŽleurs back-office, validation IA, config chatbot |
| CĆur RAG : indexation, embeddings, chunking, retrieval, vector store | bundle RAG | Configuration + section back-office |
| Serveur MCP : tenants, clients, outils, audit, rate limit | bundle MCP | Configuration + back-office clients/audit + seed CLI |
| User, auth, 2FA, reset, token API | telaria-app | CĆur applicatif du repo |
Principe : les bundles rĂ©fĂ©rencent l'utilisateur par interface ; l'application fournit l'implĂ©mentation concrĂšte via la rĂ©solution d'entitĂ©s cibles Doctrine (CmsUserInterface et VeilleReaderInterface â App\Entity\User). L'application Ă©tend les donnĂ©es des bundles sans modifier leurs tables, via des entitĂ©s companion en relation OneToOne (SEO sur le contenu CMS, verdict de validation sur l'item de veille, rĂ©glages de prompt sur le chat).
Contrats de wiring (config des bundles)
- Vitrine multisite : une liste blanche
vitrine_allowed_routesdĂ©finit les routes servies sur un site non primaire ; tout le reste renvoie 404 (via un subscriber du bundle). Les noms de routes appartiennent Ă l'application, d'oĂč un couplage explicite app â bundle dĂ©clarĂ© cĂŽtĂ© config. - RAG : la racine indexĂ©e est le dossier
docs/(prévu comme sous-module Git). Politique observée default-allow (indexe tout sauf une liste d'exclusions) ; embeddings délégués à un microservice externe (URL via variable d'environnement) ; paramÚtres de chunking et de retrieval fixés en config ; store = base + extension vectorielle (chemins via variables d'environnement). - MCP : version de protocole et quota par
(tenant, outil)fixés en config ; le quota est branché sur un rate limiter Symfony dédié injecté dans la passerelle du bundle. - Routes importées : les bundles MCP et CMS/socle exposent leurs routes via import. Les contrÎleurs de l'application sont chargés en double : une variante localisée préfixée
/{_locale}(préfixe de nomlocalized_) et une variante par défaut ; l'API est exclue du préfixe de locale.
Architecture de sécurité
Entité utilisateur
App\Entity\User est l'entité applicative centrale. Champs de contrat : email (identifiant unique de connexion), password (hashé), roles (ROLE_USER toujours garanti), isVerified, apiToken (nullable, stocké hashé SHA-512), et les champs 2FA (is2faEnabled opt-in, authCode, totpSecret, trustedVersion).
Elle implémente les contrats Symfony (UserInterface, PasswordAuthenticatedUserInterface, TwoFactorInterface, TrustedDeviceInterface) et les contrats des bundles (CmsUserInterface, VeilleReaderInterface).
Firewalls et contrĂŽle d'accĂšs
api(^/api/) : stateless, provider parapiToken, authenticator custom déclenché par le headerX-Auth-Token.main: reste du site, provider paremail,form_loginavec CSRF + 2FA + logout.- ContrÎle d'accÚs :
^/adminâROLE_ADMIN;^/apiâROLE_USER. HiĂ©rarchie :ROLE_ADMINâROLE_USER. - Redirection post-login selon le rĂŽle (admin â dashboard, lecteur â espace lecteur).
Mécanismes transverses
- Auth API : token prĂ©sentĂ© hashĂ© en SHA-512 puis comparĂ© au token stockĂ© ; rate-limitĂ© par IP ; Ă©chec â 401 JSON.
- 2FA email (
scheb/2fa) : provider email actif globalement mais opt-in par utilisateur ; code à 6 chiffres ; appareils de confiance via cookie dédié. - Basic Auth global (« public dans le privé ») : un listener sur
kernel.requestprotĂšge tout le site derriĂšre un Basic Auth HTTP quand un drapeau d'environnement est actif, sinon reste inerte â ce qui rend les pages publiques rĂ©ellement privĂ©es en environnement de prĂ©production. - Reset password / vĂ©rification email : via bundles SymfonyCasts dĂ©diĂ©s.
Surface web et endpoints (contrats de route)
Chaque route non-API possÚde une variante localisée localized_<nom> préfixée /{_locale}.
Public
| Path | Nom | Méthodes |
|---|---|---|
/ |
front.index |
GET |
/veille |
front.veille |
GET |
/legal, /accessibility |
front.legal, front.accessibility |
GET |
/contact |
front.contact |
GET, POST |
/captcha/challenge |
front.captcha_challenge |
GET |
/{slug} |
cms.page |
GET (priorité -10) |
/docs, /docs/{slug} |
docs.index, docs.show |
GET |
/docs/chat/ask, /docs/chat/reset |
docs.chat.* |
POST |
/docs-files, /docs-files/{path} |
docs-files.* |
GET |
/assistant + /ask /settings /reset |
assistant.* |
GET / POST |
/robots.txt, /sitemap.xml |
seo.robots, seo.sitemap |
GET |
/login, /logout |
security.* |
GET, POST |
Lecteur (ROLE_USER)
| Path | Nom | Méthodes |
|---|---|---|
/lecteur |
reader.index |
GET |
/lecteur/billet/{id} |
reader.show |
GET |
/lecteur/billet/{id}/lu |
reader.toggle_read |
POST |
/lecteur/tout-lu |
reader.mark_all_read |
POST |
Admin (ROLE_ADMIN, préfixe /admin)
Familles de noms de routes : admin.dashboard.*, admin.cms.* (pages, sites, images, media), admin.veille.*, admin.corpus.*, admin.rag.*, admin.mcp.*, admin.metrics*, admin.chatbot.config, admin.chat.params, admin.users.*, admin.profile.*.
API (firewall api, stateless, préfixe /api)
| Path | Nom | Méthodes | Auth |
|---|---|---|---|
/api/me |
api.user.me |
GET | ROLE_USER (X-Auth-Token) |
/api/webhook/github/docs |
api.webhook.github.docs |
POST | HMAC-SHA256 (X-Hub-Signature-256) |
Contrat du webhook de rĂ©-indexation : la signature sha256=hmac_sha256(body, secret) est vĂ©rifiĂ©e en temps constant. L'endpoint ne rĂ©agit qu'Ă un Ă©vĂ©nement de crĂ©ation de tag avec ref non vide (sinon 200 IgnorĂ©) ; si aucun checkout n'est dĂ©jĂ en cours, il lance checkout + rĂ©-indexation en fond â 202. Signature invalide â 401 ; payload non-JSON â 400. L'exĂ©cution effective (git + reindex) est dĂ©lĂ©guĂ©e Ă un contrat fourni par le bundle produit doc-IA ; l'application ne fait que valider la signature et dĂ©lĂ©guer.
Fonctions IA applicatives
Deux fonctions IA sont propres à l'application (au-dessus des bundles). Les deux appellent un modÚle Claude rapide de la famille Haiku via l'API Anthropic Messages, sur clé API fournie par variable d'environnement, avec parsing tolérant (jamais d'échec silencieux du pipeline).
Validation automatique de la veille
AprĂšs chaque cycle de veille (message traitĂ© par le worker Messenger), un subscriber Ă©coute l'Ă©vĂ©nement de message traitĂ© et valide les items nouvellement proposed, dans le mĂȘme process worker. Garde-fous observĂ©s :
- Désactivé si le prompt de validation n'est pas configuré (clé de réglage éditée en back-office).
- Limite de 20 items par cycle (garde anti-runaway), triés par date de traitement, uniquement ceux sans validation déjà persistée.
- Le prompt systÚme = le prompt configuré par l'utilisateur ; le message utilisateur porte titre, résumé tronqué, source et thÚme.
- Verdict attendu
ACCEPT|raison,REJECT|raisonouUNCERTAIN|raison. RĂ©ponse malformĂ©e âUNCERTAIN. - Application :
ACCEPTâ item acceptĂ© (visible en vitrine et espace lecteur) ;REJECTâ rejetĂ© ;UNCERTAINâ resteproposedpour revue humaine. La raison est persistĂ©e dans une entitĂ© companion. Les erreurs d'appel sont loggĂ©es mais ne font pas Ă©chouer le cycle.
FrontiÚre : le pipeline de collecte/résumé/proposition et l'entité VeilleItem (statuts proposed/accepted/rejected) viennent du bundle ; l'application ajoute le subscriber, le service d'appel, l'entité de validation et la section de config du prompt.
Anti-spam du contact
Le formulaire de contact combine plusieurs couches : rate limit, honeypot, CAPTCHA (Altcha, challenge/HMAC via variables d'environnement) et une analyse IA (ContactSpamAnalyzer) qui implémente le contrat de détection de spam du bundle.
Contrats de configuration
Toute la configuration sensible passe par variables d'environnement ; les fichiers versionnés ne contiennent que des placeholders. Contrats observés (usages, pas de valeurs) : framework (APP_ENV, APP_SECRET), base (DATABASE_URL), transport Messenger, mail (DSN, expéditeur, DKIM), CAPTCHA (secret + complexité), clé API Anthropic, secret HMAC du webhook, microservice d'embeddings et chemins du store vectoriel, drapeau + identifiants du Basic Auth global, throttle de reset, réglages du viewer docs, paramÚtres du pipeline de veille.
Rate limiters (politiques observĂ©es) : formulaire de contact (token bucket, quelques requĂȘtes par fenĂȘtre de minutes), API (token bucket, par IP), 2FA (token bucket serrĂ©), outil MCP (sliding window, par (tenant, outil), actif dans tous les environnements).
Points de contrat pour un intégrateur
- Identité : implémenter/mapper l'utilisateur derriÚre les interfaces des bundles ; ne jamais dupliquer, résoudre via
resolve_target_entities. - Extension de données de bundle : passer par une entité companion
OneToOne, jamais par modification des tables du bundle. - API : header
X-Auth-Token(token hashĂ© SHA-512 cĂŽtĂ© stockage), firewall stateless, rĂ©ponses JSON. - Webhook : signature HMAC-SHA256 en en-tĂȘte, vĂ©rification en temps constant, traitement asynchrone bornĂ© par un flag anti-concurrence.
- Multisite : toute nouvelle route destinĂ©e Ă la vitrine doit ĂȘtre ajoutĂ©e Ă la liste blanche, sinon 404 sur site non primaire.
- IA : les fonctions IA sont pilotées par des prompts configurables en back-office et bornées par des garde-fous (désactivation si non configuré, plafond par cycle, dégradation en
UNCERTAIN).
Fiche de référence descriptive, généralisée depuis une rétro-doc code-first. Certains éléments marqués « à confirmer par le Dev » dans la source (politique default-allow du RAG, découpage des migrations par bundle, ouverture de l'inscription publique, choix d'appels IA non centralisés) restent à valider.