Files
SecondBrain/20 Work/Ideas/Mogador/Demande d'evolution API Mogador v2 pour la synchronisation web.md

24 KiB

Resume executif

Nous utilisons actuellement l'export SQL complet produit par Louise comme source de verite. Cet export est importe dans une base MySQL locale, puis notre application interne consomme les donnees via l'API Mogador.

Le probleme n'est pas uniquement l'existence de Mogador. Le probleme principal est que l'API actuelle est trop granulaire pour un besoin de synchronisation et de publication web moderne.

Aujourd'hui, pour publier TFO, IDELLO, ONFR et Linear, notre application doit:

  • recuperer les programmations par plateforme;
  • boucler sur chaque programme;
  • recuperer le produit;
  • recuperer les collections;
  • recuperer les videos;
  • recuperer les presses;
  • recuperer les images;
  • recuperer la serie;
  • recuperer les URLs;
  • recuperer les versions;
  • recuperer les mots-cles;
  • recuperer les categories pedagogiques;
  • recuperer les sous-titres;
  • recuperer les territoires;
  • recuperer les pays autorises;
  • reconstruire elle-meme les relations collection -> saisons -> episodes.

Cette logique genere beaucoup d'appels API, rallonge la synchronisation, complique les retries, augmente les risques de timeout et rend la publication difficile a auditer.

Notre demande est donc de faire evoluer Mogador vers une API v2 orientee "sync/publication", capable de retourner des snapshots complets, des deltas, un statut d'import et des payloads relationnels prets a consommer.

Objectif de l'API v2

L'API v2 doit permettre de produire rapidement des donnees de publication pour les sites web sans devoir faire des milliers de petits appels.

Objectifs:

  • reduire fortement le nombre d'appels API;
  • permettre une synchronisation fiable sur une fenetre J a J+10;
  • permettre la comparaison entre deux exports;
  • fournir des donnees relationnelles completes;
  • exposer le statut du dernier export/import;
  • supporter une concurrence documentee;
  • supporter HTTPS avec validation SSL;
  • fournir des schemas de reponse stables et versionnes.

Endpoints Mogador actuellement consommes

Cette liste provient de l'application Laravel actuelle.

Programmations

GET /programs/search.json?extended=true&channel_key={channel_key}&program_date={date}
GET /programs/search.json?extended=true&channel_key={channel_key}&begin_date={from}&end_date={to}
GET /programs/search.json?channel_key={channel_key}&id={collection_biznumber}
GET /program/{program_key}.json
GET /program/{program_key}.json?extended=true
GET /program/{program_key}/product.json
GET /program/{program_key}/versions.json
GET /program/{program_key}/pedagogicalcategories.json
GET /program/{program_key}/nonlinearcategories.json
GET /program/{program_key}/authorizedcountries.json
GET /program/{program_key}/subtitles.json
GET /program/{program_key}/territories.json
GET /program/{program_key}/othermaterials.json
GET /program/{program_key}/videos.json

Produits

GET /product/{product_key}.json
GET /product/{product_key}/programs.json
GET /product/{product_key}/directcollections.json
GET /product/{product_key}/reverselinkedproducts.json
GET /product/{product_key}/videos.json
GET /product/{product_key}/presses.json
GET /product/{product_key}/images.json
GET /product/{product_key}/serie.json
GET /product/{product_key}/urls.json
GET /product/{product_key}/versions.json
GET /product/{product_key}/keywords.json
GET /product/{product_key}/casting.json

Recherche produit / metaproduit

GET /products/search.json?id={biznumber}
GET /metaproducts/search.json?id_equal={biznumber}

Pedagogie IDELLO

GET /pedagogicalcategorytypes.json

Limites de l'API actuelle

Trop d'appels par produit

Pour un seul produit/programme, l'application peut devoir appeler plusieurs endpoints:

product
directcollections
videos
metaproducts
presses
images
serie
urls
versions
keywords
program versions
program subtitles
program territories
program countries
program materials

Sur 8 000 produits TFO ou 22 000 produits IDELLO, cela devient couteux.

Relations reconstruites cote client

Les sites veulent consommer:

collection -> saisons -> episodes -> programmations

Mais les donnees sont souvent accessibles dans l'autre sens:

episode -> programmation -> serie -> collection

Notre application doit donc reconstruire elle-meme une structure qui pourrait etre exposee directement par l'API.

Besoin de programmation future

Les sites veulent pouvoir afficher:

Prochain episode le 8 aout

Nous avons besoin d'une fenetre future maximale de J+10.

Besoin de statut d'import

L'export SQL Louise est importe dans MySQL avant que l'API soit utilisable. L'application doit savoir si l'import est termine et si les donnees sont pretes.

Besoin d'audit et de comparaison

Nous devons pouvoir comparer:

ce que Louise/Mogador expose
vs
ce que notre sync a publie

L'API v2 doit donc exposer un identifiant d'export stable et des compteurs.

API v2 demandee

1. Statut du dernier export/import

Endpoint

GET /sync/v2/status

Objectif

Permettre a notre systeme de savoir si les donnees sont pretes avant de commencer la synchronisation.

Reponse attendue

{
  "schema_version": "2.0",
  "status": "ready",
  "latest_export_id": "20260801-0900",
  "export_started_at": "2026-08-01T09:00:00Z",
  "export_finished_at": "2026-08-01T09:34:00Z",
  "import_started_at": "2026-08-01T09:35:00Z",
  "import_finished_at": "2026-08-01T09:48:00Z",
  "source": {
    "file_name": "export_mogador.sql",
    "file_size_bytes": 306184192,
    "checksum_sha256": "..."
  },
  "record_counts": {
    "programs": 1234,
    "products": 8142,
    "collections": 320,
    "series": 980,
    "videos": 7900,
    "images": 24000
  },
  "available_platforms": ["tfo", "idello", "onfr", "linear"]
}

Statuts possibles

receiving_export
importing
ready
failed
stale

2. Snapshot complet par plateforme

Endpoint

GET /sync/v2/platforms/{platform}/snapshot?from={date}&to={date}

Exemple:

GET /sync/v2/platforms/tfo/snapshot?from=2026-08-01&to=2026-08-11

Objectif

Retourner toutes les donnees necessaires pour publier une plateforme sur une fenetre donnee, sans devoir faire un appel par produit.

Parametres

platform: tfo | idello | onfr | linear
from: date ISO
to: date ISO, maximum J+10 pour les besoins web actuels
include: optionnel, liste de blocs a inclure

Exemple include:

programs,products,collections,series,presses,images,videos,subtitles,keywords,pedagogy,rights

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "platform": "tfo",
  "from": "2026-08-01",
  "to": "2026-08-11",
  "generated_at": "2026-08-01T09:50:00Z",
  "programs": [],
  "products": [],
  "series": [],
  "collections": [],
  "presses": [],
  "images": [],
  "videos": [],
  "subtitles": [],
  "keywords": [],
  "pedagogical_categories": [],
  "authorized_countries": [],
  "territories": [],
  "other_materials": []
}

Donnees attendues dans programs

{
  "program_key": 9001,
  "product_key": 1001,
  "product_biznumber": "GP1001",
  "channel_key": 6,
  "platform": "tfo",
  "begin": "2026-08-01T06:00:00Z",
  "end": "2026-08-01T06:24:00Z",
  "duration_seconds": 1440,
  "title": "Titre programme",
  "target": "Jeunesse",
  "live": false,
  "advertising": "0",
  "version": {},
  "territories": [],
  "authorized_countries": [],
  "subtitles": [],
  "other_materials": [],
  "nonlinear_categories": [],
  "pedagogical_categories": []
}

Donnees attendues dans products

{
  "product_key": 1001,
  "biznumber": "GP1001",
  "title": "Titre episode",
  "short_title": "Titre court",
  "production_year": "2024",
  "duration": "00:24:00",
  "distributor": "...",
  "origin_country": "CA",
  "type": "Episode",
  "kind": "...",
  "subkind": "...",
  "category": "...",
  "target": "...",
  "rating": "...",
  "serie_key": 2001,
  "serie_biznumber": "S123",
  "serie_title": "Saison 1",
  "collection_key": 3001,
  "collection_biznumber": "C123",
  "collection_title": "Collection publique",
  "episode_number": "1",
  "episode_count": "12",
  "season": "1",
  "is_audio": false,
  "is_original": true,
  "is_pedagogical_data_valid": true,
  "modification_date": "2026-08-01T08:44:00Z",
  "urls": [],
  "versions": [],
  "presses": [],
  "images": [],
  "videos": [],
  "keywords": [],
  "casting": [],
  "linked_products": [],
  "pedagogical_products": []
}

Donnees attendues dans series

Dans notre modele web, serie correspond souvent a une saison.

{
  "serie_key": 2001,
  "biznumber": "S123",
  "title": "Saison 1",
  "short_title": "S1",
  "production_year": "2024",
  "type": "Serie",
  "kind": "...",
  "subkind": "...",
  "category": "...",
  "target": "...",
  "season": "1",
  "episode_count": "12",
  "collection_key": 3001,
  "collection_biznumber": "C123",
  "collection_title": "Collection publique",
  "presses": [],
  "images": [],
  "casting": []
}

Donnees attendues dans collections

Dans notre modele web, collection correspond souvent a la serie publique.

{
  "collection_key": 3001,
  "biznumber": "C123",
  "title": "Collection publique",
  "short_title": "Collection",
  "type": "Collection",
  "kind": "...",
  "subkind": "...",
  "category": "...",
  "presses": [],
  "images": [],
  "date_begin": "2026-08-01T06:00:00Z",
  "date_end": "2026-08-11T23:59:59Z"
}

3. Changements entre deux exports

Endpoint

GET /sync/v2/platforms/{platform}/changes?since_export_id={export_id}

Exemple:

GET /sync/v2/platforms/tfo/changes?since_export_id=20260801-0600

Objectif

Permettre de savoir ce qui a change entre deux exports complets Louise.

Meme si Louise continue de fonctionner en full export SQL, Mogador peut exposer un diff entre deux imports.

Reponse attendue

{
  "schema_version": "2.0",
  "platform": "tfo",
  "from_export_id": "20260801-0600",
  "to_export_id": "20260801-0900",
  "added": {
    "programs": [],
    "products": [],
    "collections": [],
    "series": []
  },
  "updated": {
    "programs": [],
    "products": [],
    "collections": [],
    "series": []
  },
  "removed": {
    "programs": [],
    "products": [],
    "collections": [],
    "series": []
  }
}

Chaque element devrait contenir au minimum:

{
  "entity_type": "program",
  "entity_key": 9001,
  "biznumber": "GP1001",
  "change_reason": "modified",
  "previous_hash": "...",
  "current_hash": "..."
}

4. Collection complete prete pour publication web

Endpoint

GET /sync/v2/platforms/{platform}/collections/{biznumber}/full?from={date}&to={date}

Exemple:

GET /sync/v2/platforms/tfo/collections/C123/full?from=2026-08-01&to=2026-08-11

Objectif

Retourner directement la structure attendue par les sites:

collection -> saisons -> episodes -> programmations

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "platform": "tfo",
  "collection": {
    "collection_key": 3001,
    "biznumber": "C123",
    "title": "Collection publique",
    "presses": [],
    "images": [],
    "is_original_summary": "mixed",
    "next_programmation": {
      "program_key": 9001,
      "date": "2026-08-08",
      "begin": "2026-08-08T06:00:00Z",
      "end": "2026-08-08T06:24:00Z"
    }
  },
  "seasons": [
    {
      "serie": {
        "serie_key": 2001,
        "biznumber": "S123",
        "title": "Saison 1",
        "season": "1"
      },
      "episodes": [
        {
          "product": {},
          "programmations": [],
          "media": {},
          "images": []
        }
      ]
    }
  ]
}

Regles de remontee souhaitees

Certaines donnees existent seulement sur les episodes, mais les sites peuvent les vouloir au niveau collection.

Exemples:

collection.is_original_summary:
- original si tous les episodes sont originaux
- not_original si aucun episode n'est original
- mixed si certains episodes sont originaux

collection.next_programmation:
- premiere programmation future disponible dans la fenetre demandee

collection.all_targets:
- liste unique des targets des episodes/programmes

collection.all_audiences:
- liste unique des audiences/ratings des episodes

Ces regles doivent etre documentees dans l'API.

5. Produit complet pret pour publication web

Endpoint

GET /sync/v2/platforms/{platform}/products/{product_key}/full?from={date}&to={date}

Objectif

Retourner toutes les donnees utiles pour un produit/episode en un seul appel.

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "platform": "tfo",
  "product": {},
  "collection": {},
  "serie": {},
  "programmations": {
    "current": [],
    "upcoming": [],
    "next": {}
  },
  "presses": [],
  "images": [],
  "videos": [],
  "subtitles": [],
  "keywords": [],
  "casting": [],
  "linked_products": [],
  "pedagogical_products": []
}

6. Endpoint bulk par liste de cles

Endpoint

POST /sync/v2/platforms/{platform}/products/bulk
POST /sync/v2/platforms/{platform}/programs/bulk

Objectif

Permettre de recuperer plusieurs produits ou programmes complets sans multiplier les appels unitaires.

Exemple request

{
  "export_id": "20260801-0900",
  "product_keys": [1001, 1002, 1003],
  "include": ["presses", "images", "videos", "keywords", "programs"]
}

Exemple response

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "products": []
}

7. Endpoint pedagogie IDELLO

Endpoint

GET /sync/v2/platforms/idello/pedagogy

Objectif

Retourner toutes les categories pedagogiques IDELLO et leur hierarchie.

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "categories": [
    {
      "pedagogie_key": 1,
      "type": "...",
      "name_fr": "...",
      "name_en": "...",
      "description_fr": "...",
      "description_en": "...",
      "parent_key": null
    }
  ]
}

8. Endpoint media / videos

Endpoint

GET /sync/v2/platforms/{platform}/media/videos?from={date}&to={date}

Objectif

Retourner les informations video utiles pour la publication et la reconciliation avec JWP.

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "videos": [
    {
      "program_key": 9001,
      "product_key": 1001,
      "product_biznumber": "GP1001",
      "name": "my_file.mp4",
      "path": "/my_directory/",
      "format": "JWP",
      "file_delivery": "2026-08-01T08:00:00Z",
      "duration": "00:24:00",
      "tc_in": "00:00:00:00",
      "tc_out": "00:24:00:00",
      "subtitle_tc_ref": "..."
    }
  ]
}

Note: historiquement, les formats Limelight/Uplynk etaient presents. Aujourd'hui, le besoin est surtout lie a JWP.

9. Endpoint validation / diagnostics

Endpoint

GET /sync/v2/platforms/{platform}/diagnostics?from={date}&to={date}

Objectif

Retourner des anomalies connues cote Mogador/Louise avant que notre systeme ne publie.

Reponse attendue

{
  "schema_version": "2.0",
  "export_id": "20260801-0900",
  "platform": "tfo",
  "diagnostics": [
    {
      "severity": "warning",
      "entity_type": "program",
      "entity_key": 9001,
      "message": "No subtitles found"
    },
    {
      "severity": "error",
      "entity_type": "product",
      "entity_key": 1001,
      "message": "Missing video"
    }
  ]
}

Exigences techniques

HTTPS / SSL

L'API v2 doit fonctionner avec une validation SSL standard.

Notre application ne devrait pas avoir besoin de verify=false.

Concurrence documentee

L'API actuelle semble avoir une limite de concurrence par defaut autour de 5 requetes simultanees, configurable par variable d'environnement.

Pour l'API v2, il faudrait documenter officiellement:

concurrence recommandee
concurrence maximale
comportement en cas de rate limit
headers de rate limit
temps de reponse attendu
timeouts recommandes

Exemple de headers:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 8
Retry-After: 30

Pagination

Les endpoints volumineux doivent supporter une pagination stable.

Exemple:

GET /sync/v2/platforms/idello/snapshot?from=2026-08-01&to=2026-08-11&page_size=1000&cursor=...

Reponse:

{
  "data": [],
  "next_cursor": "abc123",
  "has_more": true
}

Compression

Support attendu:

gzip ou brotli

ETag / checksum

Les gros endpoints devraient retourner un ETag ou checksum pour detecter rapidement si le contenu a change.

ETag: "sha256-..."

Versioning

Toutes les reponses doivent inclure:

{
  "schema_version": "2.0",
  "export_id": "20260801-0900"
}

Les changements cassants doivent passer par une nouvelle version:

/sync/v3/...

Erreurs standardisees

Format attendu:

{
  "error": {
    "code": "IMPORT_NOT_READY",
    "message": "Latest export is still importing",
    "retry_after_seconds": 300,
    "export_id": "20260801-0900"
  }
}

Codes utiles:

IMPORT_NOT_READY
EXPORT_FAILED
INVALID_PLATFORM
INVALID_DATE_RANGE
RATE_LIMITED
NOT_FOUND
INTERNAL_ERROR

Vision long terme: publication quasi instantanee

La demande immediate est une API v2 orientee snapshot et synchronisation. Cependant, a long terme, les equipes de production voudront probablement une publication quasi instantanee apres une sauvegarde dans Louise.

Il faut donc prevoir une trajectoire en deux temps:

Court / moyen terme:
- API snapshot fiable
- API status
- API changes
- publication JSON controlee toutes les 3h ou sur demande

Long terme:
- evenements fiables lors des changements dans Louise
- replay des evenements
- republication ciblee des JSON touches
- reconciliation reguliere par snapshot complet

Le point important: Louise ne devrait pas publier directement vers les sites. Louise devrait notifier notre systeme qu'une donnee a change. Notre systeme reste responsable de la validation, de la transformation, des rapports, des overrides, du rollback et de la publication.

Flux cible long terme:

Louise save
  -> event / webhook signe
  -> Sync Engine interne
  -> recuperation du detail via API Mogador/Louise
  -> validation
  -> regeneration des JSON impactes
  -> publication bucket/CDN
  -> rapport / alerte

Et en parallele:

Snapshot complet regulier
  -> compare avec l'etat publie
  -> detecte les evenements perdus ou incoherents

Un systeme event-driven sans snapshot/reconciliation serait trop risque. Le snapshot complet doit rester le filet de securite.

API d'evenements demandee

Pour permettre une publication quasi instantanee, il faudrait ajouter une API d'evenements fiable.

Webhook de changement

Louise peut notifier notre systeme lorsqu'une entite change.

Exemples d'evenements:

program.created
program.updated
program.deleted
product.created
product.updated
product.deleted
collection.updated
serie.updated
media.updated
rights.updated

Payload minimal attendu

{
  "schema_version": "2.0",
  "event_id": "evt_20260801_000001",
  "sequence": 123456,
  "event_type": "program.updated",
  "entity_type": "program",
  "entity_key": 9001,
  "biznumber": "GP1001",
  "platforms": ["tfo"],
  "occurred_at": "2026-08-01T09:15:00Z",
  "export_id": "20260801-0900",
  "changed_fields": ["begin", "end", "product_key"]
}

Le payload peut rester leger. Il n'est pas obligatoire d'envoyer tout le produit dans le webhook. Par contre, l'evenement doit permettre a notre systeme de recuperer le detail complet ensuite.

Endpoint replay

Un endpoint de replay est obligatoire pour eviter les pertes d'evenements.

GET /sync/v2/events?since_sequence=123456

Reponse:

{
  "schema_version": "2.0",
  "from_sequence": 123456,
  "to_sequence": 123500,
  "events": [],
  "has_more": false,
  "next_sequence": 123501
}

Endpoint detail apres evenement

Apres reception d'un evenement, notre systeme doit pouvoir recuperer l'entite complete.

GET /sync/v2/platforms/{platform}/programs/{program_key}/full
GET /sync/v2/platforms/{platform}/products/{product_key}/full
GET /sync/v2/platforms/{platform}/collections/{biznumber}/full

Garanties attendues pour les events

Pour que les evenements soient utilisables en production, il faut:

  • event_id unique;
  • sequence monotone;
  • retry automatique des webhooks;
  • signature HMAC;
  • idempotence;
  • endpoint de replay;
  • conservation des evenements pendant une periode definie;
  • environnement staging;
  • documentation du format;
  • monitoring cote fournisseur;
  • garantie que les suppressions sont aussi envoyees;
  • garantie que les changements de droits sont envoyes.

Pourquoi le replay est non negociable

Un webhook peut echouer pour plusieurs raisons:

  • reseau indisponible;
  • maintenance;
  • timeout;
  • erreur applicative temporaire;
  • deploy en cours;
  • rate limit.

Sans replay, une notification perdue peut produire une publication incorrecte. Avec replay, notre systeme peut reprendre depuis la derniere sequence connue.

Position recommandee sur le temps reel

La recommandation est de ne pas aller directement vers:

Louise save -> site web

La cible devrait etre:

Louise save -> event fiable -> Sync Engine interne -> JSON statiques -> site web

Cela permet d'avoir une publication rapide tout en gardant:

  • validation;
  • audit;
  • rollback;
  • rapports;
  • controle des overrides internes;
  • cache/CDN maitrise;
  • reconciliation par snapshot.

Criteres d'acceptation

L'API v2 serait consideree utile si elle permet:

  • de recuperer TFO J a J+10 en beaucoup moins d'appels;
  • de recuperer IDELLO J a J+10 sans 22 000 appels produit unitaires;
  • de connaitre le statut exact du dernier export/import;
  • de recuperer un export_id stable dans chaque reponse;
  • de comparer deux exports;
  • de recuperer une collection complete dans le sens attendu par les sites;
  • de recuperer un produit complet en un seul appel;
  • de fonctionner avec SSL valide;
  • de supporter pagination et compression;
  • de documenter clairement les limites de concurrence;
  • de fournir un environnement staging.
  • de fournir une trajectoire vers des events fiables avec replay pour la publication quasi instantanee.

Priorites

Priorite 1

GET /sync/v2/status
GET /sync/v2/platforms/{platform}/snapshot

Ces deux endpoints reduiraient immediatement la complexite de la synchronisation.

Priorite 2

GET /sync/v2/platforms/{platform}/collections/{biznumber}/full
GET /sync/v2/platforms/{platform}/products/{product_key}/full

Ces endpoints reduiraient la complexite des relations collection/saison/episode.

Priorite 3

GET /sync/v2/platforms/{platform}/changes
POST /sync/v2/platforms/{platform}/products/bulk
GET /sync/v2/platforms/{platform}/diagnostics

Ces endpoints amelioreraient la performance, l'audit et la fiabilite.

Priorite 4

Webhook signed events
GET /sync/v2/events?since_sequence={sequence}
GET /sync/v2/platforms/{platform}/programs/{program_key}/full

Ces capacites prepareraient la publication quasi instantanee sans exposer les sites directement a Louise.

Conclusion

Nous ne cherchons pas necessairement a contourner Mogador. Nous cherchons surtout a eviter que notre application doive reconstruire une publication web complete a partir de milliers de petits appels API.

Une API Mogador v2 orientee synchronisation permettrait de:

  • garder Louise/Mogador comme source officielle;
  • reduire la charge sur l'API;
  • reduire la duree des syncs;
  • fiabiliser les publications;
  • faciliter les rapports d'ecarts;
  • mieux servir les sites web;
  • eviter une suppression complete de Mogador.
  • preparer une publication quasi instantanee avec des evenements fiables.

La demande principale est donc:

Passer d'une API granulaire par entite a une API de snapshot, diff et publication par plateforme.

La demande long terme est:

Ajouter des evenements fiables avec replay afin de permettre une republication ciblee quelques secondes/minutes apres une sauvegarde dans Louise.