diff --git a/20 Work/Ideas/Mogador/Proposition d'architecture - Content Publication Engine.md b/20 Work/Ideas/Mogador/Proposition d'architecture - Content Publication Engine.md new file mode 100644 index 0000000..a78f74e --- /dev/null +++ b/20 Work/Ideas/Mogador/Proposition d'architecture - Content Publication Engine.md @@ -0,0 +1,1375 @@ + +## TL;DR + +Le systeme actuel de synchro Louise/Mogador fonctionne, mais il est devenu trop fragile: trois serveurs avec le meme code, dependance forte a Directus, peu d'observabilite, corrections d'urgence difficiles a tracer, et trop de logique implicite dans une synchro construite rapidement. + +La recommandation est de ne pas tout recommencer en big bang, mais de construire un **Content Publication Engine** interne qui publie des JSON statiques versionnes vers un bucket/CDN. Les sites consommeraient ces JSON au lieu de consommer Directus directement. + +Le projet doit etre separe en deux chantiers: + +1. **Chantier interne, sous notre controle** + + - produire les JSON publics; + - gerer les runs atomiques et rollback; + - integrer JWP via un `Media Pipeline`; + - offrir une `Publication Console` interne pour corrections d'urgence; + - produire rapports et alertes. +2. **Chantier PCI, separe** + + - discuter avec PCI d'une API Louise/Mogador v2; + - demander du bulk, SSL fonctionnel, pagination, limites documentees; + - a long terme, demander des events/webhooks comme signal de changement. + +Point important: le chantier interne ne doit pas attendre PCI. Il doit fonctionner avec le Mogador Toolkit actuel, puis remplacer son lecteur source par Louise API v2 si elle arrive. + +Position recommandee: + +```text +Louise Export / Mogador Toolkit actuel + -> Content Publication Engine interne + -> Media Pipeline JWP + -> Publication Console + -> Published Content Feed JSON + -> Bucket/CDN + -> Sites web +``` + +Directus peut rester temporairement pendant la transition, mais ne devrait plus etre le moteur principal de publication web. + +## Objectif + +Ce document propose une refonte progressive de la synchronisation Louise/Mogador afin de rendre la publication vers TFO, IDELLO, ONFR et lineaire plus fiable, plus rapide a diagnostiquer et plus simple a consommer par les sites. + +Le but n'est pas de jeter toute la connaissance metier existante. Le code actuel contient plusieurs regles importantes qui doivent etre conservees. Par contre, l'architecture actuelle melange trop de responsabilites: + +- extraction des donnees officielles; +- synchronisation; +- Directus; +- permissions; +- edition d'urgence; +- publication web; +- videos JWP; +- rapports; +- alertes. + +La refonte doit separer ces responsabilites sans creer une usine a gaz. + +## Contexte actuel + +Louise est la vraie source de verite. + +Toutes les 3 heures, Louise produit un fichier SQL complet, `export_mogador.sql`. Ce fichier n'est jamais incremental. Il commence par des `TRUNCATE`, puis reinsere toutes les donnees. + +Flux actuel: + +```text +Louise + -> export_mogador.sql complet + -> rsync vers serveur Linux + -> import dans une base MySQL structuree avec mogador.sql + -> API Mogador officielle qui parle a cette base + -> application Laravel interne + -> synchronisation vers Directus + -> sites web / fournisseurs consomment Directus ou redistribuent dans leurs propres bases +``` + +Aujourd'hui, il y a trois serveurs avec une copie du meme code: + +```text +P1: TFO + lineaire +P2: IDELLO +P3: ONFR +``` + +Cette separation existe parce qu'un seul serveur prendrait trop de temps a synchroniser toutes les plateformes. L'export, le transfert, l'import SQL et la synchronisation prennent environ 1 heure par cycle sur l'architecture actuelle. + +## Contraintes importantes + +- La source officielle reste Louise. +- L'export Louise est un full export SQL, pas un incrementiel. +- L'equipe dev peut regarder la base, mais la consommation officielle devrait passer par l'API Mogador pour rester conforme aux attentes contractuelles. +- L'app interne ne doit pas etre exposee a Internet selon les contraintes Infra actuelles. +- Les fournisseurs ont besoin d'un acces read-only. +- Les edimestres et l'equipe interne doivent pouvoir faire des corrections d'urgence. +- Les sites veulent un modele oriente utilisateur: collection -> saisons -> episodes -> programmations. +- Louise/Mogador expose souvent les donnees dans le sens inverse: episode -> programmation -> serie -> collection. +- Directus est utile pour les permissions et l'edition, mais difficile comme moteur relationnel/publication. +- Les programmations futures sont demandees, avec une limite v1 proposee a J+10. +- Les videos JWP sont gerees dans une app AdonisJS existante et doivent etre integrees sans coupler toute la publication a JWP. + +## Problemes actuels + +### Architecture lourde + +Le meme code est deploye sur plusieurs serveurs. Cela complique: + +- les mises a jour; +- les migrations; +- les alertes; +- le debugging; +- les reprises apres incident; +- la comprehension globale du systeme. + +### Directus porte trop de responsabilites + +Directus sert aujourd'hui a: + +- donner un acces read-only aux fournisseurs; +- permettre des corrections d'urgence; +- exposer les donnees aux sites; +- representer des relations complexes entre produits, programmations, series et collections. + +Le probleme principal est le dernier point. Les relations entre produits, programmations, series et collections sont difficiles a maintenir dans Directus. Certaines relations ne peuvent pas etre creees proprement a cause de contraintes FK ou du modele de donnees. + +### Le modele Louise ne correspond pas au modele des sites + +Terminologie metier: + +```text +Collection = serie pour le public +Serie = saison +Episode = episode +``` + +Les sites veulent souvent: + +```json +{ + "collection": { + "programmation": { + "start": "2026-08-08T06:00:00-04:00", + "end": "2026-08-08T06:24:00-04:00" + } + }, + "seasons": [ + { + "serie": {}, + "episodes": [ + { + "product": {}, + "programmations": [], + "media": {}, + "images": [] + } + ] + } + ] +} +``` + +Mais les donnees Louise/Mogador partent souvent de l'episode, puis il faut remonter vers la serie/saison et la collection. + +Exemple: `is_original` peut etre disponible sur les episodes, mais pas directement sur la collection. Si le site veut cette information au niveau collection, il faut definir une regle explicite de remontee. + +### Peu d'observabilite proactive + +Aujourd'hui, l'equipe est souvent reactive. Les problemes sont decouverts quand la production ou les sites signalent une erreur. + +Exemples deja rencontres: + +- supervisor down; +- worker queue down; +- migration oubliee lors d'un changement de serveur; +- programmation attendue absente du site; +- synchro incomplete; +- donnees manquantes dans Directus. + +## Decision recommandee + +La recommandation principale est de ne plus utiliser Directus comme moteur principal de publication web. + +L'application interne devrait produire des JSON statiques prets a consommer par les sites. + +Architecture cible: + +```text +Louise SQL full export + -> import MySQL Mogador + -> Mogador Toolkit actuel + -> Content Publication Engine interne + -> snapshots / diffs / rapports + -> generation de JSON statiques + -> publication vers bucket/CDN par plateforme + -> sites web consomment les JSON +``` + +L'app interne ne serait pas exposee a Internet. Les sites ne parlent pas a Laravel ou AdonisJS directement. Ils lisent des fichiers JSON publics publies dans un bucket/CDN. + +## Deux chantiers a ne pas melanger + +### Chantier A: amelioration interne de la synchro + +Ce chantier est sous notre controle. + +Il contient: + +- `Content Publication Engine`; +- `Media Pipeline` AdonisJS/JWP; +- contrat interne `media_assets`; +- contrat interne `publication_jobs`; +- `Publication Console` pour corrections d'urgence; +- `Published Content Feed`, les JSON publies vers bucket/CDN. + +Ce chantier peut commencer sans attendre une refonte par PCI. Au debut, il peut continuer a lire les donnees officielles via l'export SQL et le Mogador Toolkit actuel. + +### Chantier B: discussion PCI / evolution Louise-Mogador + +Ce chantier est un projet separe. + +Objectif: discuter avec PCI pour moderniser l'acces aux donnees officielles Louise/Mogador. + +Il peut inclure: + +- une API Louise/Mogador v2; +- des endpoints bulk plus efficaces; +- une meilleure compatibilite SSL; +- des limites de concurrence documentees; +- des exports plus faciles a consommer; +- a long terme, des events/webhooks comme signal de changement pour aller vers une publication presque instantanee. + +Ce chantier a une relation directe avec la synchro interne, mais il ne doit pas bloquer le chantier A. La synchro interne doit etre concue pour fonctionner avec le Mogador Toolkit actuel, puis remplacer son lecteur source par Louise API v2 si elle arrive. + +## Flow d'information cible + +### Chantier A: publication interne + +```mermaid +flowchart TD + Louise["LouiseSysteme source editorial"] + LouiseExport["Louise ExportSQL complet toutes les 3h"] + Importer["Import SQL interneBase source locale"] + Toolkit["Mogador ToolkitAPI legacy actuelle"] + + Snapshot["Snapshot Collectorlit les donnees officielles"] + SnapshotStore["Snapshot Storeruns source + checksums"] + Diff["Diff Builderfabrique l'incrementiel interne"] + + MediaPipeline["Media PipelineAdonisJS/JWP"] + JWP["JWPplateforme video"] + MediaAssets["media_assetsetat media interne"] + + Console["Publication Consolemini CMS interne"] + Overrides["overridescorrections d'urgence"] + + Jobs["publication_jobsfile de republication"] + Engine["Content Publication EngineLaravel ou autre"] + Validator["Validation + rapportsattendu vs publie"] + Runs["Published Content Feedruns JSON immuables"] + Manifest["manifest.jsonpointe vers le run actif"] + Bucket["Bucket/CDNexposition publique controlee"] + Sites["Sites webTFO / IDELLO / ONFR / lineaire"] + Alerts["Slack / Better Stackalertes anomalies"] + + Louise --> LouiseExport + LouiseExport --> Importer + Importer --> Toolkit + Toolkit --> Snapshot + + Snapshot --> SnapshotStore + SnapshotStore --> Diff + Diff --> Engine + + Snapshot --> MediaPipeline + MediaPipeline --> JWP + JWP --> MediaPipeline + MediaPipeline --> MediaAssets + MediaPipeline --> Jobs + + Console --> Overrides + Console --> Jobs + + MediaAssets --> Engine + Overrides --> Engine + Jobs --> Engine + + Engine --> Validator + Validator --> Alerts + Validator --> Runs + Runs --> Manifest + Manifest --> Bucket + Runs --> Bucket + Bucket --> Sites +``` + +Ce schema represente ce qu'on controle nous-memes. Il ne depend pas d'une API Louise/Mogador v2. + +### Chantier B: evolution PCI + +```mermaid +flowchart TD + Louise["Louisesysteme source"] + CurrentExport["Export SQL actuelfull truncate + insert"] + CurrentToolkit["Mogador Toolkit actuelAPI legacy"] + Discussion["Discussion PCIupgrade Louise/Mogador"] + ApiV2["Louise API v2bulk + SSL + pagination"] + Events["Events/Webhooks futurssignal de changement"] + InternalReader["Source Reader internedans le Content Publication Engine"] + + Louise --> CurrentExport --> CurrentToolkit --> InternalReader + Louise --> Discussion + Discussion --> ApiV2 + Discussion --> Events + ApiV2 -.remplace progressivement.-> InternalReader + Events -.declenche une relecture officielle.-> InternalReader +``` + +Ce deuxieme schema est un projet avec PCI. Il peut ameliorer fortement la vitesse et la fiabilite, mais il doit rester interchangeable. + +Le `Content Publication Engine` devrait avoir un `Source Reader` abstrait: + +```text +Version 1: +Source Reader -> Mogador Toolkit actuel -> DB importee depuis Louise Export + +Version future: +Source Reader -> Louise API v2 +``` + +Le reste du systeme interne ne devrait pas changer: + +- diff interne; +- `media_assets`; +- `publication_jobs`; +- overrides; +- rapports; +- JSON publics; +- manifest; +- rollback. + +## Comment ca marche + +1. Louise produit un export complet toutes les 3 heures. +2. Le SQL est importe dans une base interne. +3. Le Mogador Toolkit expose les donnees officielles. +4. Le Snapshot Collector lit les donnees officielles. +5. Le Diff Builder compare le snapshot courant au snapshot precedent. +6. Le Media Pipeline gere JWP et ecrit l'etat media dans `media_assets`. +7. La Publication Console gere les corrections d'urgence et ecrit les overrides. +8. Les changements creent des `publication_jobs`. +9. Le Content Publication Engine combine donnees officielles, media, overrides et regles metier. +10. Il genere un run JSON complet. +11. Il valide le run et produit un rapport. +12. Il publie les fichiers JSON immuables. +13. Il met a jour `manifest.json` seulement si le run est valide. +14. Les sites lisent le manifest, puis les fichiers du run actif. + +## Fabrication d'un incremental a partir d'un full export + +Louise ne fournit pas d'incrementiel. Chaque export est complet. + +La solution est de sauvegarder des snapshots internes et de comparer les snapshots entre eux. + +Exemple: + +```text +09h00: export Louise complet + -> import MySQL + -> extraction via Mogador Toolkit + -> snapshot_09h00 + +12h00: export Louise complet + -> import MySQL + -> extraction via Mogador Toolkit + -> snapshot_12h00 + +Diff snapshot_09h00 -> snapshot_12h00: + -> programmes ajoutes + -> programmes retires + -> produits modifies + -> images modifiees + -> dates de programmation modifiees + -> erreurs ou anomalies +``` + +Cela permet: + +- de savoir ce qui a change; +- de generer un `latest.json`; +- de limiter certaines republications; +- de produire un rapport clair; +- de conserver un historique. + +## Donnees internes proposees + +Tables possibles: + +```text +sync_runs +sync_run_items +sync_anomalies +source_snapshots +products +programs +collections +series +episodes +media_assets +publication_jobs +publication_snapshots +manual_overrides +deleted_programs +``` + +Avec une colonne `platform`: + +```text +tfo +idello +onfr +linear +``` + +Cela evite de dupliquer toute la logique dans des tables separees comme `tfo_products`, `idello_products`, `onfr_products`, sauf si une contrainte technique oblige a garder cette separation. + +## Published Content Feed: JSON statiques proposes + +Au lieu d'un seul gros JSON, il faut publier plusieurs fichiers specialises. + +Exemple pour TFO: + +```text +/tfo/v1/manifest.json +/tfo/v1/runs/20260730-0900/today.json +/tfo/v1/runs/20260730-0900/latest.json +/tfo/v1/runs/20260730-0900/schedule/index.json +/tfo/v1/runs/20260730-0900/schedule/2026-07-30.json +/tfo/v1/runs/20260730-0900/schedule/2026-07-31.json +/tfo/v1/runs/20260730-0900/collections/index.json +/tfo/v1/runs/20260730-0900/collections/0123456/full.json +/tfo/v1/runs/20260730-0900/products/GP123456.json +/tfo/v1/runs/20260730-0900/search/index.json +``` + +Pour 8 000 produits TFO et 22 000 produits IDELLO, ce volume de fichiers JSON n'est pas un probleme pour un bucket/CDN. C'est preferable a un gros fichier unique. + +Le site ne code pas un chemin de run en dur. Il lit toujours: + +```text +/tfo/v1/manifest.json +``` + +Puis utilise le `base_path` retourne: + +```text +/tfo/v1/runs/20260730-0900 +``` + +### manifest.json + +Le manifest indique quelle version est publiee. + +```json +{ + "schema_version": "1.0", + "platform": "tfo", + "published_at": "2026-07-30T09:50:00-04:00", + "run_id": "20260730-0900", + "base_path": "/tfo/v1/runs/20260730-0900" +} +``` + +Le manifest est le seul fichier qui doit avoir un cache court: + +```text +/tfo/v1/manifest.json +Cache-Control: public, max-age=60, stale-while-revalidate=120 + +/tfo/v1/runs/20260730-0900/* +Cache-Control: public, max-age=31536000, immutable +``` + +Compromis acceptable si Infra veut reduire les appels: + +```text +manifest.json: max-age=300 +``` + +Donc 5 minutes. Trois heures serait trop long pour les corrections d'urgence, les rollbacks et les republications apres media JWP. + +Important: les runs sont des copies completes et immuables. Donc oui, garder plusieurs runs multiplie le nombre de fichiers stockes. + +Exemple simplifie avec TFO: + +```text +8 000 produits TFO +5 runs conserves += environ 40 000 fichiers produits +``` + +Et il faut ajouter les collections, schedules, indexes, `today.json`, `latest.json`, etc. + +Estimation plus complete pour TFO avec 5 runs: + +```text +Produits: +8 000 x 5 runs = 40 000 fichiers + +Collections: +environ 300 x 5 runs = 1 500 fichiers + +Schedules: +environ 11 jours x 5 runs = 55 fichiers + +Indexes / today / latest / divers: +environ 50 a 150 fichiers + +Total estime: +environ 41 500 a 42 000 fichiers +``` + +Le `manifest.json` n'est pas multiplie de la meme facon: il pointe seulement vers le run actif. + +Ce volume reste raisonnable pour un bucket/CDN, mais il doit etre assume dans la strategie de retention. C'est pour cela qu'on garde: + +- les runs recents utiles au rollback; +- un minimum de 3 runs valides; +- une limite de retention, par exemple 10 jours; +- des policies de nettoyage automatique. + +Le compromis est volontaire: on accepte plus de fichiers stockes pour obtenir une publication atomique, un rollback simple, un cache agressif sur les runs, et aucun risque qu'un site lise une publication a moitie generee. + +### today.json + +Contient ce qui doit etre en ligne aujourd'hui. + +```json +{ + "date": "2026-07-30", + "programs": [] +} +``` + +### latest.json + +Contient les nouveautes et changements depuis la derniere publication. + +```json +{ + "run_id": "20260730-0900", + "added": [], + "updated": [], + "removed": [] +} +``` + +### schedule/YYYY-MM-DD.json + +Contient la programmation d'une date precise. + +```json +{ + "date": "2026-08-08", + "programs": [ + { + "program_key": 123, + "product_key": 456, + "begin": "2026-08-08T06:00:00-04:00", + "end": "2026-08-08T06:24:00-04:00", + "title": "..." + } + ] +} +``` + +### products/{id}.json + +Contient le detail d'un produit. + +```json +{ + "product": {}, + "programmations": { + "current": [], + "upcoming": [], + "next": { + "date": "2026-08-08", + "begin": "2026-08-08T06:00:00-04:00" + } + }, + "media": {}, + "images": [] +} +``` + +### collections/{biznumber}/full.json + +Contient le modele attendu par les sites. + +```json +{ + "collection": { + "biznumber": "0123456", + "title": "...", + "is_original": true, + "programmation": { + "start": "2026-08-08T06:00:00-04:00", + "end": "2026-08-08T06:24:00-04:00" + }, + "next_programmation": { + "date": "2026-08-08", + "begin": "2026-08-08T06:00:00-04:00" + } + }, + "seasons": [ + { + "serie": {}, + "episodes": [ + { + "product": {}, + "programmations": [], + "media": {}, + "images": [] + } + ] + } + ] +} +``` + +## Programmations futures + +Pour afficher des messages comme "prochain episode le 8 aout", il faut extraire une fenetre future de programmation. + +Limite v1 recommandee: J+10. + +Configuration proposee: + +```env +TFO_SCHEDULE_DAYS_AHEAD=10 +IDELLO_SCHEDULE_DAYS_AHEAD=10 +ONFR_SCHEDULE_DAYS_AHEAD=10 +LINEAR_SCHEDULE_DAYS_BEHIND=7 +LINEAR_SCHEDULE_DAYS_AHEAD=10 +``` + +Les programmations futures sont publiees dans: + +```text +/tfo/v1/runs/{run_id}/schedule/2026-08-08.json +``` + +Et resumees dans les JSON produit/collection: + +```json +{ + "next_programmation": { + "date": "2026-08-08", + "begin": "2026-08-08T06:00:00-04:00" + } +} +``` + +Le site peut ensuite appliquer sa logique d'affichage selon l'heure. + +## Search et Algolia + +Un fichier comme: + +```text +/tfo/v1/runs/{run_id}/search/index.json +``` + +peut servir a alimenter Algolia, Meilisearch, Typesense ou un autre moteur de recherche. + +Il peut contenir seulement les champs utiles: + +```json +[ + { + "objectID": "GP123456", + "type": "product", + "title": "...", + "slug": "...", + "image": "...", + "collection_biznumber": "0123456" + } +] +``` + +Si les sites ont besoin d'une vraie recherche rapide sur 8 000 a 22 000 items, un moteur dedie reste preferable a un gros fichier recherche charge cote client. + +## Publication atomique et retention + +Principe: + +```text +/tfo/v1/runs/20260730-0900/... +/tfo/v1/runs/20260730-1200/... +/tfo/v1/manifest.json +``` + +Si la generation du run `20260730-1200` echoue, `manifest.json` continue de pointer vers `20260730-0900`. Une sync ratee ne casse pas le site. + +Retention proposee: + +```text +JSON publies: +- garder les runs des 10 derniers jours +- garder au minimum les 3 derniers runs valides +- supprimer les runs incomplets jamais publies + +Rapports: +- garder 90 jours + +Anomalies importantes / audit: +- garder 1 an ou selon politique interne +``` + +## Versioning, documentation et validation + +Les JSON deviennent un contrat avec les sites. Il faut donc versionner le format. + +Version dans le chemin: + +```text +/tfo/v1/manifest.json +/tfo/v1/runs/20260730-0900/products/GP123456.json +/tfo/v1/runs/20260730-0900/collections/0123456/full.json +``` + +Version dans chaque fichier: + +```json +{ + "schema_version": "1.0", + "platform": "tfo", + "run_id": "20260730-0900" +} +``` + +Documentation recommandee: + +```text +docs/ + publication-contract.md + files.md + cache-strategy.md + versioning.md + examples/ + manifest.json + product.json + collection-full.json + schedule-day.json + schemas/ + manifest.schema.json + product.schema.json + collection-full.schema.json + schedule-day.schema.json +``` + +Avant de publier un run: + +```text +1. generer tous les JSON +2. valider chaque type de fichier contre son JSON Schema +3. produire le rapport +4. publier seulement si les erreurs critiques sont absentes +5. mettre a jour manifest.json +``` + +Swagger/OpenAPI est utile pour les endpoints internes de la Publication Console. Pour les JSON statiques, JSON Schema et exemples versionnes sont plus importants. + +## Role futur de Directus + +Deux options sont possibles. + +### Option 1: retirer Directus progressivement + +Si les sites consomment les JSON statiques et si les permissions fournisseurs sont gerees par bucket ou prefixe, Directus n'est plus necessaire dans la chaine de publication. + +Permissions possibles: + +```text +bucket-tfo +bucket-idello +bucket-onfr +``` + +Ou un seul bucket avec prefixes: + +```text +publication/tfo/ +publication/idello/ +publication/onfr/ +``` + +### Option 2: garder Directus temporairement + +Directus peut rester pendant une periode de transition pour: + +- consultation interne; +- edition d'urgence existante; +- acces read-only fournisseur existant; +- comparaison avec les nouveaux JSON. + +Mais il ne devrait plus composer le JSON relationnel final utilise par les sites. + +## Publication Console: edition d'urgence + +Si Directus est retire ou reduit, il faut remplacer son role d'edition d'urgence. + +La proposition est de creer une `Publication Console` interne, non exposee a Internet. + +Acces proposes: + +```text +Admin sync: +- peut configurer et publier +- peut gerer les utilisateurs +- peut faire rollback + +Edimestre: +- peut rechercher et consulter +- peut creer une correction d'urgence +- peut voir les overrides actifs +- ne peut pas changer la configuration systeme + +Read-only interne: +- peut consulter les donnees, rapports et JSON publies +- ne peut pas modifier +``` + +Fonctions minimales: + +- rechercher un produit, programme, collection ou serie; +- voir les donnees venant de Louise/Mogador; +- voir le JSON actuellement publie; +- ajouter une correction temporaire; +- mettre une raison; +- mettre une date d'expiration; +- republier les JSON concernes; +- garder un historique complet. + +Exemple de table: + +```text +manual_overrides +- id +- platform +- entity_type: product | program | collection | serie +- entity_key: product_key | program_key | biznumber +- field_path +- value_json +- reason +- active_from +- active_until +- created_by +- approved_by +- created_at +- updated_at +``` + +Important: il ne faut pas modifier les JSON publies directement a la main. Les overrides doivent etre appliques dans le pipeline de generation, sinon ils seront perdus ou impossibles a auditer. + +Chaque override devrait inclure: + +- l'utilisateur; +- le role; +- la raison; +- la date d'expiration; +- l'entite touchee; +- l'ancien contenu; +- le nouveau contenu; +- le run dans lequel la correction a ete publiee. + +## Media Pipeline: role de l'app AdonisJS/JWP + +L'app AdonisJS qui synchronise les videos vers JWP ne devrait pas devenir le moteur de publication JSON complet. Son role naturel est: + +> verifier les videos, envoyer ou mettre a jour les medias dans JWP, suivre leur statut, et declarer qu'un produit doit etre republie quand le media est pret. + +Le point important n'est pas la technologie de cette app, mais le contrat entre le Media Pipeline et le Content Publication Engine. + +Elle devrait faire: + +- lire les infos video source depuis Louise/Mogador ou depuis le snapshot interne; +- verifier la presence du fichier video source; +- creer ou mettre a jour le media dans JWP; +- gerer poster, sous-titres, metadata et statut d'encodage; +- maintenir une table interne `media_assets`; +- creer un job de republication quand un media change. + +Elle ne devrait pas faire: + +- publier les JSON finaux des sites; +- connaitre toute la logique collection/saison/episode; +- ecrire directement dans les fichiers publics; +- remplacer le Content Publication Engine. + +## Contrat entre Media Pipeline et Content Publication Engine + +### Table `media_assets` + +Cette table represente l'etat media interne d'un produit. + +Champs proposes: + +```text +id +platform +product_key +biznumber +provider +provider_media_id +status +source_video_name +source_file_delivery +m3u8_url +poster_url +captions_status +error_code +error_message +metadata_json +created_at +updated_at +ready_at +``` + +Valeurs possibles pour `status`: + +```text +missing +uploading +processing +ready +failed +disabled +``` + +Exemple: + +```json +{ + "platform": "tfo", + "product_key": "GP123456", + "biznumber": "0123456", + "provider": "jwp", + "provider_media_id": "abc123", + "status": "ready", + "m3u8_url": "https://cdn.jwplayer.com/manifests/abc123.m3u8", + "poster_url": "https://cdn.jwplayer.com/v2/media/abc123/poster.jpg", + "captions_status": "ready", + "updated_at": "2026-07-31T09:15:00-04:00" +} +``` + +### Table `publication_jobs` + +Cette table sert a dire au Content Publication Engine: "quelque chose a change, republie ce qui est touche". + +Champs proposes: + +```text +id +platform +entity_type +entity_key +reason +priority +status +attempts +payload_json +available_at +locked_at +processed_at +created_at +updated_at +``` + +Valeurs possibles pour `entity_type`: + +```text +product +collection +schedule +all +``` + +Valeurs possibles pour `reason`: + +```text +mogador_snapshot_changed +media_ready +media_failed +override_changed +manual_republish +rollback +``` + +Exemple: + +```json +{ + "platform": "tfo", + "entity_type": "product", + "entity_key": "GP123456", + "reason": "media_ready", + "priority": 50, + "status": "pending" +} +``` + +Pourquoi cette table est le meilleur compromis: + +- plus fiable qu'un appel direct entre apps; +- rejouable si le Content Publication Engine est temporairement down; +- observable dans un dashboard ou rapport; +- compatible avec plusieurs workers; +- idempotent si on utilise une cle unique par entite/reason/run; +- rapide, car le job peut etre traite presque tout de suite; +- plus simple a auditer; +- ne force pas le Media Pipeline et le Content Publication Engine a etre deployes ensemble. + +On peut garder un scan periodique comme filet de securite, par exemple toutes les 15 ou 30 minutes, pour detecter un media modifie qui n'aurait pas cree de job. + +## Rapport et alertes + +Le rapport est une piece centrale de la v2. + +Il doit comparer: + +```text +ce que Louise/Mogador contient +vs +ce que le Content Publication Engine a traite +vs +ce qui a ete publie en JSON +vs +eventuellement ce qui reste dans Directus pendant la transition +``` + +Exemple de rapport: + +```text +Plateforme: TFO +Run: 20260730-0900 + +Export SQL recu: oui +Import MySQL: succes +Mogador Toolkit: OK + +Programmes attendus aujourd'hui: 1230 +Programmes publies: 1229 +Produits attendus: 8142 +Produits publies: 8139 + +Ecarts: +- 1 programme absent du JSON final +- 2 produits sans video JWP +- 5 images manquantes +- 1 produit ignore car type extrait + +Publication: +- statut: publie avec avertissements +- manifest pointe vers: /tfo/v1/runs/20260730-0900 +``` + +Alertes a mettre en place: + +- export SQL non recu; +- fichier SQL trop petit ou checksum identique de facon suspecte; +- import MySQL echoue; +- Mogador Toolkit ne repond pas; +- workers down; +- queue bloquee; +- sync trop longue; +- ecart entre attendu et publie; +- programme prevu a 6h absent de la publication avant 6h; +- video JWP manquante; +- image ou transcription manquante; +- override actif proche expiration. + +## Fichier SQL hors application + +Le fait que `export_mogador.sql` soit hors du repertoire de l'application n'est pas un probleme. + +Le script d'import peut ecrire un fichier de statut dans un chemin connu: + +```json +{ + "export_received_at": "2026-07-30T09:01:00-04:00", + "import_started_at": "2026-07-30T09:35:00-04:00", + "import_finished_at": "2026-07-30T09:48:00-04:00", + "sql_file_size": 306184192, + "checksum": "abc123", + "status": "success" +} +``` + +Chemins configurables: + +```env +MOGADOR_EXPORT_PATH=/data/mogador/export_mogador.sql +MOGADOR_IMPORT_STATUS_PATH=/data/mogador/import-status.json +MOGADOR_IMPORT_LOG_PATH=/var/log/mogador-import.log +``` + +Le Content Publication Engine lit ce statut pour produire son rapport. + +## Timeline du chantier A: synchro interne + +Important: les durees ci-dessous representent des estimations d'effort si l'equipe travaille presque a temps plein sur le projet. Si l'equipe a 35-40% d'operations courantes, il faut convertir ces estimations en duree calendrier. + +Exemple: + +```text +2 semaines d'effort projet / 60% de disponibilite projet += environ 3.3 semaines calendrier +``` + +En pratique, une estimation doit souvent etre multipliee par environ 1.5 a 1.7 si l'equipe n'est disponible qu'a 60-65% pour le projet. + +### Phase 0: contrat technique + +Duree estimee: 1 semaine. + +Livrables: + +- schema `media_assets`; +- schema `publication_jobs`; +- structure JSON v1; +- regles de statut media; +- regles de republication; +- convention de logs et rapports. + +### Phase 1: observabilite + +Objectif: savoir ce qui se passe avant de tout remplacer. + +- Ajouter `sync_runs`. +- Ajouter `sync_run_items`. +- Ajouter `sync_anomalies`. +- Generer un rapport par plateforme. +- Alerter sur les ecarts critiques. +- Garder Directus tel quel. + +### Phase 2: Media Pipeline minimal + +Duree estimee: 1 a 2 semaines. + +- L'app AdonisJS ecrit dans `media_assets`. +- Elle cree des jobs `publication_jobs`. +- Elle detecte les medias `missing`, `processing`, `ready`, `failed`. +- Elle produit un rapport simple sur les videos manquantes ou en erreur. + +### Phase 3: publication JSON en parallele + +Duree estimee: 2 a 3 semaines. + +- Generer `/manifest.json`. +- Generer `/today.json`. +- Generer `/schedule/YYYY-MM-DD.json`. +- Generer quelques `/products/{id}.json`. +- Generer quelques `/collections/{id}/full.json`. +- Lire `media_assets`. +- Traiter `publication_jobs`. +- Comparer JSON vs Directus. + +### Phase 4: premier site pilote + +Duree estimee: 2 semaines. + +- Choisir ONFR ou une portion TFO. +- Publier dans un bucket/prefix dedie. +- Valider performance, structure JSON, cache, rollback et medias JWP. +- Ajouter alertes Slack/Better Stack. + +### Phase 5: Publication Console + +Duree estimee: 2 semaines. + +- Ajouter `manual_overrides`. +- Ajouter interface interne. +- Ajouter auth et roles. +- Ajouter audit trail. +- Ajouter expiration automatique. +- Ajouter rapport des overrides actifs. + +### Phase 6: reduction ou retrait de Directus + +- Garder Directus seulement pendant transition. +- Migrer les usages fournisseurs vers buckets/CDN. +- Retirer progressivement les dependances Directus. + +## Timeline du chantier B: PCI / Louise-Mogador + +Ce chantier peut avancer en parallele, mais il ne devrait pas bloquer le chantier interne. + +### Etape B1: clarifier les problemes actuels + +Points a documenter pour PCI: + +- SSL non fonctionnel ou non compatible; +- lenteur des appels API; +- limite de concurrence actuelle; +- trop grand nombre d'appels necessaires pour reconstruire un produit complet; +- absence d'incrementiel; +- absence de signal de changement; +- besoin de bulk; +- besoin de pagination/cursor; +- besoin de checksums ou export id; +- besoin de documentation claire et versionnee. + +### Etape B2: demander une API v2 bulk + +Exemples de besoins: + +- recuperer tous les produits/programmes d'une plateforme pour une fenetre de dates; +- recuperer une collection complete; +- recuperer un produit complet; +- recuperer les horaires J+10; +- recuperer les droits et pays autorises; +- recuperer les informations video source, mais pas les champs JWP. + +### Etape B3: demander un mode evenementiel + +PCI pourrait envoyer un event quand une modification est sauvegardee dans Louise. Cet event ne publie rien directement. Il sert seulement a declencher une relecture officielle par notre systeme interne. + +Exemple: + +```json +{ + "event_id": "evt_123", + "sequence": 987654, + "event_type": "product.updated", + "platforms": ["tfo"], + "product_key": "GP123456", + "occurred_at": "2026-07-31T09:15:00-04:00" +} +``` + +Notre systeme recoit l'event, relit le detail via API officielle, applique les validations, enrichit avec JWP/overrides, puis republie les JSON touches. + +## Vision long terme: publication presque instantanee + +Aujourd'hui, Louise exporte un full SQL toutes les 3 heures. Tant que c'est le seul signal officiel, on ne peut pas garantir une publication instantanee d'une modification faite dans Louise. + +Par contre, on peut preparer l'architecture pour le futur. + +A court terme: + +- snapshot toutes les 3 heures; +- diff interne; +- publication atomique; +- overrides internes rapides; +- republication rapide quand un media JWP devient pret. + +A moyen terme: + +- demander a PCI une API Louise/Mogador v2 bulk fiable; +- reduire le temps de lecture; +- eviter les milliers d'appels API individuels; +- garder le snapshot complet comme filet de securite. + +A long terme: + +- demander a PCI des evenements/webhooks comme signal; +- chaque changement dans Louise envoie un evenement; +- notre systeme relit le detail officiel via API; +- le snapshot complet continue de tourner pour reconciler les ecarts. + +Important: le webhook ne devrait pas publier directement vers les sites. Il devrait seulement dire: "quelque chose a change". Notre systeme interne reste responsable de valider, enrichir, publier, alerter et rollback. + +## Choix technique recommande pour la nouvelle app v2 + +La nouvelle app v2 devrait etre faite en Laravel. + +Raisons principales: + +- le projet est surtout un systeme metier back-office, pas une API publique temps reel; +- Laravel gere tres bien les jobs, le scheduler, les commandes, les retries et les traitements planifies; +- Horizon donne une bonne visibilite sur les queues si Redis est utilise correctement; +- l'ecosysteme Laravel est tres solide pour construire une `Publication Console` interne avec auth, roles, policies et audit; +- les migrations, seeders, commands et jobs sont bien adaptes a ce type de pipeline; +- l'equipe connait deja le contexte Laravel de la synchro actuelle; +- la logique de publication doit etre fiable et observable plus que fashionable; +- le rollback, les rapports, les overrides et la validation JSON sont des cas naturels pour Laravel. + +Le Media Pipeline existant peut rester separe. Ce qui compte, c'est qu'il respecte le contrat: + +```text +Media Pipeline + -> ecrit media_assets + -> cree publication_jobs + +Content Publication Engine + -> lit media_assets + -> traite publication_jobs + -> genere les JSON publics +``` + +Avec cette separation, le Media Pipeline peut evoluer independamment. La nouvelle app v2, elle, devrait etre le systeme de publication fiable, auditable et operationnel; Laravel est le meilleur choix pour ce role. + +## Risques principaux + +|Risque|Probabilite|Impact|Reponse| +|---|---|---|---| +|Le projet devient trop large et tente de remplacer Directus, Mogador, JWP et les sites en meme temps|Elevee|Eleve|Decouper en pilote, garder PCI comme chantier separe, livrer par increments| +|Les regles metier actuelles sont implicites dans le vieux code|Elevee|Eleve|Extraire les regles, valider avec production, ajouter rapports de comparaison| +|Les corrections d'urgence entrent en conflit avec Louise au prochain export|Elevee|Eleve|Definir precedence, expiration d'override, audit et rapport d'ecart| +|Le manifest est cache trop longtemps|Moyenne|Eleve|TTL court sur manifest, runs immuables caches longtemps, procedure purge CDN| +|Media Pipeline et Publication Engine se couplent trop fortement|Moyenne|Eleve|Passer uniquement par `media_assets` et `publication_jobs`| +|Le systeme publie un JSON incomplet mais valide techniquement|Moyenne|Eleve|Ajouter validations metier, rapports attendu vs publie et seuils bloquants| +|L'absence d'API PCI v2 maintient certaines lenteurs|Elevee|Moyen|Concevoir le `Source Reader` remplacable et optimiser avec snapshots/diffs internes| +|PCI ne livre pas d'events/webhooks a court terme|Elevee|Moyen|Ne pas en faire une dependance du MVP; garder polling 3h et overrides internes| +|Infra refuse l'exposition de l'app interne|Moyenne|Moyen|Exposer seulement les JSON via bucket/CDN; garder la console sur reseau interne| +|Migration depuis Directus cause une interruption|Moyenne|Eleve|Double-run, comparaison, pilote, rollback, aucun big bang| + +## Noms recommandes + +```text +Louise + Systeme source editorial. + +Louise Export + Export SQL complet genere par Louise. + +Mogador Toolkit + API legacy actuelle autour de la base importee. + +Louise API v2 + Future API PCI demandee pour lecture bulk et events. + +Content Publication Engine + Notre moteur interne qui genere les JSON publics. + +Media Pipeline + Notre service interne qui gere JWP et l'etat media. + +Publication Console + Mini CMS interne pour edimestres/admins et overrides. + +Published Content Feed + Les fichiers JSON versionnes consommes par les sites. +``` + +Avec ces noms, on peut parler de l'architecture sans que "Mogador" veuille dire quatre choses differentes. + +## Position finale + +La proposition recommandee est: + +```text +Content Publication Engine interne + + snapshots + + diff maison + + Media Pipeline JWP + + Publication Console + + JSON statiques + + bucket/CDN + + rapports + + alertes +``` + +Directus peut etre garde temporairement, mais ne devrait plus etre le moteur principal de publication web. + +Cette approche respecte les contraintes: + +- Louise reste source de verite. +- Le Mogador Toolkit actuel peut rester utilise au depart. +- L'app interne n'est pas exposee a Internet. +- Les sites recoivent des donnees simples et rapides. +- Les fournisseurs peuvent etre isoles par bucket ou prefixe. +- L'equipe interne garde la capacite de corriger en urgence. +- Les erreurs deviennent visibles avant que la production les signale. +- L'architecture reste compatible avec une future API Louise/Mogador v2 de PCI. \ No newline at end of file diff --git a/20 Work/Ideas/Mogador/Suite de la proposition Sync v2 - publication, videos et responsabilites.md b/20 Work/Ideas/Mogador/Suite de la proposition Sync v2 - publication, videos et responsabilites.md deleted file mode 100644 index b53d997..0000000 --- a/20 Work/Ideas/Mogador/Suite de la proposition Sync v2 - publication, videos et responsabilites.md +++ /dev/null @@ -1,801 +0,0 @@ - - -Ce document est une suite a `README-sync-v2-proposal.md`. Le premier document propose de remplacer la synchro actuelle vers Directus par un moteur interne qui publie des fichiers JSON versionnes, atomiques et faciles a consommer par les sites. - -Ici, on precise un point important qui est apparu apres: la synchro video vers JWP existe deja dans une app AdonisJS, elle est aussi liee a Mogador/Louise, et il faut eviter de recreer une dependance fragile avec PCI a chaque changement de plateforme video. - -Clarification importante: la demande d'une API Louise/Mogador v2 est un projet separe de l'amelioration de la synchro interne. Les deux sujets sont relies, mais ils n'ont pas le meme proprietaire, pas le meme rythme et pas le meme niveau de controle. - -- Le chantier interne vise a rendre notre publication fiable avec les contraintes actuelles. -- Le chantier PCI vise a moderniser l'acces officiel aux donnees Louise/Mogador et, a long terme, permettre des signaux de changement plus rapides. - -## Resume executif - -La recommandation est de separer clairement deux chantiers qui sont lies, mais qui ne doivent pas etre melanges. - -### Chantier A: amelioration interne de la synchro - -Ce chantier est sous notre controle. - -Objectif: remplacer la synchro actuelle trop fragile par un systeme interne plus fiable, plus observable et plus simple a consommer par les sites. - -Il contient: - -- le `Content Publication Engine`; -- le `Media Pipeline` AdonisJS/JWP; -- le contrat interne `media_assets`; -- le contrat interne `publication_jobs`; -- la `Publication Console` pour les corrections d'urgence; -- le `Published Content Feed`, c'est-a-dire les JSON publies vers bucket/CDN. - -Ce chantier peut commencer sans attendre une refonte par PCI. Au debut, il peut continuer a lire les donnees officielles via l'export SQL et le Mogador Toolkit actuel. - -### Chantier B: discussion PCI / evolution Louise-Mogador - -Ce chantier est un projet separe. - -Objectif: discuter avec PCI pour moderniser l'acces aux donnees officielles Louise/Mogador. - -Il peut inclure: - -- une API Louise/Mogador v2; -- des endpoints bulk plus efficaces; -- une meilleure compatibilite SSL; -- des limites de concurrence documentees; -- des exports plus faciles a consommer; -- a long terme, des events/webhooks comme signal de changement pour aller vers une publication presque instantanee. - -Ce chantier a une relation directe avec la synchro interne, mais il ne doit pas bloquer le chantier A. La synchro interne doit etre concue pour fonctionner avec le Mogador Toolkit actuel, puis remplacer son lecteur source par Louise API v2 si elle arrive. - -## Responsabilites a separer - -Dans le chantier interne, il faut separer clairement trois responsabilites: - -1. Louise/Mogador reste la source officielle des metadonnees et des droits. -2. Notre systeme interne gere la publication JSON vers les sites. -3. Notre systeme interne gere aussi l'etat des medias JWP, sans demander a Louise de connaitre JWP. - -PCI ne devrait pas etre responsable de JWP, ni de publier directement vers les sites. Dans le chantier PCI, on peut lui demander une API v2 plus efficace pour lire les donnees officielles en bulk, avec une vision long terme d'evenements/webhooks comme signal de changement. Mais la publication finale reste notre responsabilite. - -La publication finale devrait etre produite par notre Sync Engine, qui combine: - -- les donnees officielles Louise/Mogador; -- l'etat media interne JWP; -- les corrections d'urgence faites dans un mini CMS interne; -- les regles de publication par plateforme. - -## Schema du chantier A: flow interne de publication - -```mermaid -flowchart TD - Louise["LouiseSysteme source editorial"] - LouiseExport["Louise ExportSQL complet toutes les 3h"] - Importer["Import SQL interneBase source locale"] - Toolkit["Mogador ToolkitAPI legacy actuelle"] - - Snapshot["Snapshot Collectorlit les donnees officielles"] - SnapshotStore["Snapshot Storeruns source + checksums"] - Diff["Diff Builderfabrique l'incrementiel interne"] - - MediaPipeline["Media PipelineAdonisJS/JWP"] - JWP["JWPplateforme video"] - MediaAssets["media_assetsetat media interne"] - - Console["Publication Consolemini CMS interne"] - Overrides["overridescorrections d'urgence"] - - Jobs["publication_jobsfile de republication"] - Engine["Content Publication EngineLaravel ou autre"] - Validator["Validation + rapportsattendu vs publie"] - Runs["Published Content Feedruns JSON immuables"] - Manifest["manifest.jsonpointe vers le run actif"] - Bucket["Bucket/CDNexposition publique controlee"] - Sites["Sites webTFO / IDELLO / ONFR / lineaire"] - Alerts["Slack / Better Stackalertes anomalies"] - - Louise --> LouiseExport - LouiseExport --> Importer - Importer --> Toolkit - Toolkit --> Snapshot - - Snapshot --> SnapshotStore - SnapshotStore --> Diff - Diff --> Engine - - Snapshot --> MediaPipeline - MediaPipeline --> JWP - JWP --> MediaPipeline - MediaPipeline --> MediaAssets - MediaPipeline --> Jobs - - Console --> Overrides - Console --> Jobs - - MediaAssets --> Engine - Overrides --> Engine - Jobs --> Engine - - Engine --> Validator - Validator --> Alerts - Validator --> Runs - Runs --> Manifest - Manifest --> Bucket - Runs --> Bucket - Bucket --> Sites -``` - -Ce schema represente ce qu'on controle nous-memes. Il ne depend pas d'une API Louise/Mogador v2. - -## Schema du chantier B: evolution PCI / Louise-Mogador - -```mermaid -flowchart TD - Louise["Louisesysteme source"] - CurrentExport["Export SQL actuelfull truncate + insert"] - CurrentToolkit["Mogador Toolkit actuelAPI legacy"] - Discussion["Discussion PCIupgrade Louise/Mogador"] - ApiV2["Louise API v2bulk + SSL + pagination"] - Events["Events/Webhooks futurssignal de changement"] - InternalReader["Source Reader internedans le Content Publication Engine"] - - Louise --> CurrentExport --> CurrentToolkit --> InternalReader - Louise --> Discussion - Discussion --> ApiV2 - Discussion --> Events - ApiV2 -.remplace progressivement.-> InternalReader - Events -.declenche une relecture officielle.-> InternalReader -``` - -Ce deuxieme schema est un projet avec PCI. Il peut ameliorer fortement la vitesse et la fiabilite, mais il doit rester interchangeable. Le `Content Publication Engine` ne devrait pas etre concu uniquement pour cette future API. Il devrait avoir un `Source Reader` abstrait qui peut lire aujourd'hui via Mogador Toolkit, puis demain via Louise API v2. - -## Comment ca marche, etape par etape - -1. Louise reste la source officielle. - - Louise continue de produire son export complet. Aujourd'hui, cet export est un SQL avec `TRUNCATE` puis `INSERT`. Ce n'est pas un incrementiel. - -2. L'export est importe dans une base interne. - - Comme aujourd'hui, le fichier SQL peut etre copie sur le serveur interne puis importe dans MySQL. Le Mogador Toolkit lit cette base et expose les donnees via API. - -3. Le Snapshot Collector lit les donnees officielles. - - Dans la premiere version du chantier interne, il lit via Mogador Toolkit. Si le chantier PCI aboutit, ce lecteur pourra etre remplace par une Louise API v2 plus efficace. Le but est de produire un snapshot interne coherent et versionne, peu importe la source technique. - -4. Le Diff Builder fabrique notre incrementiel. - - Louise ne donne pas d'incrementiel, donc on compare deux snapshots. On detecte ce qui est ajoute, modifie, supprime ou expire. C'est ce diff interne qui permet de republier seulement ce qui est touche. - -5. Le Media Pipeline gere JWP separement. - - L'app AdonisJS reste responsable de verifier les videos, envoyer les medias vers JWP, suivre l'encodage, les posters et les sous-titres. Elle n'ecrit pas les JSON publics. Elle maintient seulement `media_assets`. - -6. Quand un media change, un job est cree. - - Si une video devient prete dans JWP, le Media Pipeline cree un `publication_jobs` avec `reason = media_ready`. Le Sync Engine saura alors qu'il doit republier le produit, la collection ou l'horaire touche. - -7. Les corrections d'urgence passent par la Publication Console. - - Les edimestres/admins internes peuvent faire un override sans attendre le prochain export Louise. Chaque correction est auditee et cree aussi un job de republication. - -8. Le Content Publication Engine combine tout. - - Il lit les donnees officielles, les diffs, les medias JWP, les overrides et les jobs. Ensuite il genere les fichiers JSON attendus par les sites: produits, collections, schedule J+10, today, latest, search index, etc. - -9. Les JSON sont publies en runs immuables. - - Exemple: - - ```text - /tfo/v1/runs/20260731-090000/products/GP123456.json - /tfo/v1/runs/20260731-090000/collections/0123456/full.json - /tfo/v1/runs/20260731-090000/schedule/2026-08-08.json - /tfo/v1/manifest.json - ``` - - Les sites lisent le `manifest.json`, puis vont chercher les fichiers du run actif. Pour rollback, on repointe simplement le manifest vers un run precedent. - -10. Les rapports comparent attendu vs publie. - - Le systeme doit produire un rapport du genre: "voici ce que Louise dit qui devrait etre en ligne aujourd'hui et dans les 10 prochains jours; voici ce qui a ete publie; voici ce qui manque ou est en erreur". - -11. Les alertes deviennent proactives. - - Si un programme de 6h n'a pas de JSON, pas de video, pas de programmation ou une incoherence, l'equipe est avertie avant que la production ou les sites le decouvrent. - - -## Point de jonction entre les deux chantiers - -Les deux chantiers se rejoignent a un seul endroit principal: la lecture des donnees officielles. - -Dans le `Content Publication Engine`, cette partie devrait etre isolee derriere un composant qu'on peut appeler `Source Reader`. - -Version 1: - -```text -Source Reader -> Mogador Toolkit actuel -> DB importee depuis Louise Export -``` - -Version future: - -```text -Source Reader -> Louise API v2 -``` - -Le reste du systeme interne ne devrait pas changer: - -- diff interne; -- `media_assets`; -- `publication_jobs`; -- overrides; -- rapports; -- JSON publics; -- manifest; -- rollback. - -Autrement dit, l'API Louise/Mogador v2 est une amelioration du lecteur source. Ce n'est pas le coeur du systeme de publication. - -## Pourquoi ne pas mettre JWP dans l'API Louise/Mogador v2 - -Avant, la plateforme video etait Limelight. Limelight a disparu, et l'organisation est maintenant sur JWP. Si on demande a PCI de retourner des champs specifiques a JWP, on recree une dependance qui va couter cher a chaque changement de plateforme video. - -L'API Louise/Mogador v2 devrait donc retourner seulement les informations video source et metier: - -- produit/programme associe; -- nom ou identifiant du fichier source; -- type de media; -- duree; -- droits; -- dates de disponibilite; -- metadata officielle utile pour publication; -- eventuellement les informations necessaires pour retrouver le fichier dans notre stockage. - -Elle ne devrait pas retourner: - -- `jw_media_id`; -- URL JWP finale; -- URL HLS JWP; -- poster JWP; -- statut d'encodage JWP; -- captions JWP; -- champs specifiques a une plateforme video. - -Ces champs appartiennent a notre domaine interne de publication media. - -## Role de l'app AdonisJS actuelle - -L'app AdonisJS qui synchronise les videos vers JWP ne devrait pas devenir le moteur de publication JSON complet. Son role naturel est plus limite et plus clair: - -> Media Sync Service: verifier les videos, envoyer ou mettre a jour les medias dans JWP, suivre leur statut, et declarer qu'un produit doit etre republie quand le media est pret. - -Elle peut rester en AdonisJS si l'equipe est plus confortable avec JavaScript/TypeScript pour cette partie. Ce n'est pas un probleme tant que le contrat avec le Sync Engine est clair. - -Ce qu'elle devrait faire: - -- lire les infos video source depuis Louise/Mogador ou depuis le snapshot interne; -- verifier la presence du fichier video source; -- creer ou mettre a jour le media dans JWP; -- gerer poster, sous-titres, metadata et statut d'encodage; -- maintenir une table interne `media_assets`; -- creer un job de republication quand un media change. - -Ce qu'elle ne devrait pas faire: - -- publier les JSON finaux des sites; -- connaitre toute la logique collection/saison/episode; -- ecrire directement dans les fichiers publics; -- remplacer le Sync Engine. - -## Role du Sync Engine - -Le Sync Engine reste le coeur de la publication. - -Il prend les donnees officielles et les transforme dans le format attendu par les sites: - -```json -{ - "collection": {}, - "seasons": [ - { - "serie": {}, - "episodes": [ - { - "product": {}, - "programmations": [], - "media": {}, - "images": [] - } - ] - } - ] -} -``` - -Il doit etre responsable de: - -- charger le snapshot Louise/Mogador; -- fabriquer notre incrementiel interne a partir des snapshots; -- appliquer les overrides du mini CMS interne; -- enrichir les produits avec l'etat media JWP; -- generer les JSON par plateforme; -- publier les runs atomiques; -- mettre a jour le `manifest.json`; -- produire les rapports de validation; -- alerter en cas d'ecart. - -## Le contrat entre AdonisJS et le Sync Engine - -Pour que les deux apps restent decouplees, il faut un contrat simple en base de donnees. - -### Table `media_assets` - -Cette table represente l'etat media interne d'un produit. - -Champs proposes: - -```text -id -platform -product_key -biznumber -provider -provider_media_id -status -source_video_name -source_file_delivery -m3u8_url -poster_url -captions_status -error_code -error_message -metadata_json -created_at -updated_at -ready_at -``` - -Valeurs possibles pour `status`: - -```text -missing -uploading -processing -ready -failed -disabled -``` - -Exemple: - -```json -{ - "platform": "tfo", - "product_key": "GP123456", - "biznumber": "0123456", - "provider": "jwp", - "provider_media_id": "abc123", - "status": "ready", - "m3u8_url": "https://cdn.jwplayer.com/manifests/abc123.m3u8", - "poster_url": "https://cdn.jwplayer.com/v2/media/abc123/poster.jpg", - "captions_status": "ready", - "updated_at": "2026-07-31T09:15:00-04:00" -} -``` - -### Table `publication_jobs` - -Cette table sert a dire au Sync Engine: "quelque chose a change, republie ce qui est touche". - -Champs proposes: - -```text -id -platform -entity_type -entity_key -reason -priority -status -attempts -payload_json -available_at -locked_at -processed_at -created_at -updated_at -``` - -Valeurs possibles pour `entity_type`: - -```text -product -collection -schedule -all -``` - -Valeurs possibles pour `reason`: - -```text -mogador_snapshot_changed -media_ready -media_failed -override_changed -manual_republish -rollback -``` - -Exemple: - -```json -{ - "platform": "tfo", - "entity_type": "product", - "entity_key": "GP123456", - "reason": "media_ready", - "priority": 50, - "status": "pending" -} -``` - -## Pourquoi une table de jobs est la meilleure option - -On avait trois options: - -1. AdonisJS appelle directement une commande interne du Sync Engine. -2. AdonisJS ecrit dans une table/queue `publication_jobs`. -3. Le Sync Engine scanne regulierement les medias modifies. - -La meilleure option pour nous est la deuxieme: `publication_jobs`. - -Raisons: - -- plus fiable qu'un appel direct entre apps; -- rejouable si le Sync Engine est temporairement down; -- observable dans un dashboard ou rapport; -- compatible avec plusieurs workers; -- idempotent si on utilise une cle unique par entite/reason/run; -- rapide, car le job peut etre traite presque tout de suite; -- plus simple a auditer; -- ne force pas AdonisJS et Laravel a etre deployes ensemble. - -On peut garder un scan periodique comme filet de securite, par exemple toutes les 15 ou 30 minutes, pour detecter un media modifie qui n'aurait pas cree de job. - -## Timeline proposee pour le chantier A: synchro interne - -Il ne faut pas faire "AdonisJS d'abord" ou "Sync Engine d'abord" de facon isolee. La premiere chose a faire est de definir le contrat commun. - -### Phase 0: contrat technique - -Duree estimee: 1 semaine. - -Livrables: - -- schema `media_assets`; -- schema `publication_jobs`; -- structure JSON v1; -- regles de statut media; -- regles de republication; -- convention de logs et rapports. - -Cette phase permet a l'equipe media et a l'equipe publication de travailler en parallele sans se bloquer. - -### Phase 1: Media Sync minimal - -Duree estimee: 1 a 2 semaines. - -Livrables: - -- l'app AdonisJS ecrit dans `media_assets`; -- elle cree des jobs `publication_jobs`; -- elle detecte les medias `missing`, `processing`, `ready`, `failed`; -- elle produit un rapport simple sur les videos manquantes ou en erreur. - -Cette phase ne remplace pas encore Directus ou la synchro actuelle. - -### Phase 2: Sync Engine prototype - -Duree estimee: 2 a 3 semaines. - -Livrables: - -- lecture du snapshot Louise/Mogador; -- lecture de `media_assets`; -- generation locale des JSON; -- generation du `manifest.json`; -- support des produits, collections, today, latest et schedule J+10; -- traitement de `publication_jobs`; -- rapport de comparaison entre attendu et publie. - -### Phase 3: pilote - -Duree estimee: 2 semaines. - -Commencer avec ONFR ou un sous-ensemble TFO. - -Livrables: - -- publication vers un bucket de test; -- comparaison avec Directus; -- validation des caches; -- validation rollback; -- validation des medias JWP; -- alertes Slack/Better Stack. - -### Phase 4: mini CMS interne - -Duree estimee: 2 semaines. - -Livrables: - -- authentification interne; -- roles edimestres/admin; -- edition d'urgence; -- audit trail; -- preview avant publication; -- creation de jobs `override_changed`. - -### Phase 5: generalisation - -Duree estimee: 3 a 6 semaines selon disponibilite. - -Livrables: - -- TFO; -- IDELLO; -- ONFR; -- lineaire; -- documentation finale; -- JSON Schema; -- Swagger/OpenAPI pour les endpoints internes; -- runbook d'operation; -- retention des runs; -- monitoring complet. - -## Timeline separee pour le chantier B: PCI / Louise-Mogador - -Ce chantier peut avancer en parallele, mais il ne devrait pas bloquer le chantier interne. - -### Etape B1: clarifier les problemes actuels - -Objectif: arriver avec des demandes concretes pour PCI. - -Points a documenter: - -- SSL non fonctionnel ou non compatible; -- lenteur des appels API; -- limite de concurrence actuelle; -- trop grand nombre d'appels necessaires pour reconstruire un produit complet; -- absence d'incrementiel; -- absence de signal de changement; -- besoin de bulk; -- besoin de pagination/cursor; -- besoin de checksums ou export id; -- besoin de documentation claire et versionnee. - -### Etape B2: demander une API v2 bulk - -Objectif: remplacer les milliers d'appels individuels par quelques appels bulk previsibles. - -Exemples de besoins: - -- recuperer tous les produits/programmes d'une plateforme pour une fenetre de dates; -- recuperer une collection complete; -- recuperer un produit complet; -- recuperer les horaires J+10; -- recuperer les droits et pays autorises; -- recuperer les informations video source, mais pas les champs JWP. - -### Etape B3: demander un mode evenementiel - -Objectif: preparer la publication presque instantanee. - -PCI pourrait envoyer un event quand une modification est sauvegardee dans Louise. Cet event ne publie rien directement. Il sert seulement a declencher une relecture officielle par notre systeme interne. - -Exemple: - -```json -{ - "event_id": "evt_123", - "sequence": 987654, - "event_type": "product.updated", - "platforms": ["tfo"], - "product_key": "GP123456", - "occurred_at": "2026-07-31T09:15:00-04:00" -} -``` - -Notre systeme recoit l'event, relit le detail via API officielle, applique les validations, enrichit avec JWP/overrides, puis republie les JSON touches. - -## Vision long terme: publication presque instantanee - -Aujourd'hui, Louise exporte un full SQL toutes les 3 heures. Tant que c'est le seul signal officiel, on ne peut pas garantir une publication instantanee d'une modification faite dans Louise. - -Par contre, on peut preparer l'architecture pour le futur. - -A court terme: - -- snapshot toutes les 3 heures; -- diff interne; -- publication atomique; -- overrides internes rapides; -- republication rapide quand un media JWP devient pret. - -A moyen terme: - -- demander a Louise/Mogador une API v2 bulk fiable; -- reduire le temps de lecture; -- eviter les milliers d'appels API individuels; -- garder le snapshot complet comme filet de securite. - -A long terme: - -- demander a Louise/Mogador des evenements/webhooks comme signal; -- chaque changement dans Louise envoie un evenement; -- notre Sync Engine va ensuite relire le detail officiel via API; -- le snapshot complet continue de tourner pour reconciler les ecarts. - -Important: le webhook ne devrait pas publier directement vers les sites. Il devrait seulement dire: "quelque chose a change". Notre systeme interne reste responsable de valider, enrichir, publier, alerter et rollback. - -Cette vision long terme appartient au chantier B, mais elle beneficie au chantier A. Le systeme interne doit donc etre pret a recevoir des signaux plus rapides, sans dependre d'eux pour fonctionner au debut. - -## Position sur Laravel vs AdonisJS - -Pour le Sync Engine principal, Laravel reste un tres bon choix. - -Arguments en faveur de Laravel: - -- excellent scheduler; -- queues robustes; -- Horizon si Redis est bien configure; -- ecosysteme mature pour admin interne; -- migrations et jobs bien connus; -- bonne base pour audit trail, policies, auth interne; -- plus facile de construire un mini CMS operationnel rapidement; -- plus adapte a une application metier back-office avec beaucoup de traitements planifies. - -Arguments en faveur d'AdonisJS: - -- TypeScript; -- preference du tech lead; -- coherent avec l'app JWP actuelle; -- bon framework Node.js; -- peut etre tres efficace pour une equipe qui maintient surtout du JS. - -Recommandation pragmatique: - -- garder ou faire evoluer AdonisJS pour le Media Sync JWP; -- utiliser Laravel pour le Sync Engine et le mini CMS interne, si l'equipe accepte de le maintenir; -- sinon, faire tout en AdonisJS est possible, mais il faudra etre discipline sur les jobs, le scheduler, les migrations, les retries, l'idempotence et l'admin interne. - -Le choix final devrait surtout repondre a cette question: - -> Quelle stack l'equipe peut maintenir calmement quand une emission doit etre en ligne a 6h et qu'il y a une alerte a 5h45? - -## Noms proposes - -Il y a trop de choses appelees Mogador aujourd'hui. Il faut separer les noms par responsabilite. - -### Systeme source - -Nom actuel: - -- Louise; -- Export Mogador; -- API Mogador; -- Mogador Toolkit. - -Proposition: - -- `Louise`: le systeme editorial/source. -- `Louise Export`: le fichier SQL complet exporte par Louise. -- `Mogador Toolkit`: l'API legacy fournie avec la base importee. -- `Louise API v2`: la future API fournie par PCI, si elle remplace ou modernise le Toolkit. - -### Systeme interne de publication - -Noms possibles: - -- `Publication Engine`; -- `Content Publication Engine`; -- `Broadcast Sync Engine`; -- `Content Sync Engine`; -- `TFO Publication Engine`; -- `Oasis`; -- `Relay`; -- `Signal`; -- `Conductor`. - -Recommandation: `Content Publication Engine`. - -Pourquoi: - -- clair pour les non-devs; -- ne contient pas Mogador; -- explique que le systeme publie du contenu; -- peut couvrir TFO, IDELLO, ONFR et lineaire. - -### Systeme media - -Noms possibles: - -- `Media Sync`; -- `JWP Sync`; -- `Video Publishing Service`; -- `Media Pipeline`; -- `Media Bridge`. - -Recommandation: `Media Pipeline`. - -Pourquoi: - -- ne depend pas du nom JWP; -- survivra si JWP est remplace un jour; -- couvre upload, metadata, poster, sous-titres et statut. - -### Mini CMS interne - -Noms possibles: - -- `Publication Console`; -- `Editorial Console`; -- `Emergency Console`; -- `Ops Console`; -- `Content Console`. - -Recommandation: `Publication Console`. - -Pourquoi: - -- clair pour les edimestres; -- moins anxiogene que "Emergency"; -- peut servir aux corrections, previews, overrides et audits. - -### Stockage JSON public - -Noms possibles: - -- `Public JSON Feed`; -- `Content Feed`; -- `Site Feed`; -- `Published Feed`; -- `Delivery Feed`. - -Recommandation: `Published Content Feed`. - -Pourquoi: - -- explique que ce sont les donnees deja validees et publiees; -- evite de melanger avec Louise, Mogador ou Directus. - -## Naming recommande final - -La proposition la plus claire: - -```text -Louise - Systeme source editorial. - -Louise Export - Export SQL complet genere par Louise. - -Mogador Toolkit - API legacy actuelle autour de la base importee. - -Louise API v2 - Future API PCI demandee pour lecture bulk et events. - -Content Publication Engine - Notre moteur interne qui genere les JSON publics. - -Media Pipeline - Notre service interne qui gere JWP et l'etat media. - -Publication Console - Mini CMS interne pour edimestres/admins et overrides. - -Published Content Feed - Les fichiers JSON versionnes consommes par les sites. -``` - -Avec ces noms, on peut enfin parler de l'architecture sans que "Mogador" veuille dire quatre choses differentes. \ No newline at end of file