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

1089 lines
24 KiB
Markdown

## 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
```http
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
```http
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
```http
GET /products/search.json?id={biznumber}
GET /metaproducts/search.json?id_equal={biznumber}
```
### Pedagogie IDELLO
```http
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:
```text
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:
```text
collection -> saisons -> episodes -> programmations
```
Mais les donnees sont souvent accessibles dans l'autre sens:
```text
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:
```text
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:
```text
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
```http
GET /sync/v2/status
```
### Objectif
Permettre a notre systeme de savoir si les donnees sont pretes avant de commencer la synchronisation.
### Reponse attendue
```json
{
"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
```text
receiving_export
importing
ready
failed
stale
```
## 2. Snapshot complet par plateforme
### Endpoint
```http
GET /sync/v2/platforms/{platform}/snapshot?from={date}&to={date}
```
Exemple:
```http
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
```text
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`:
```text
programs,products,collections,series,presses,images,videos,subtitles,keywords,pedagogy,rights
```
### Reponse attendue
```json
{
"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`
```json
{
"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`
```json
{
"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.
```json
{
"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.
```json
{
"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
```http
GET /sync/v2/platforms/{platform}/changes?since_export_id={export_id}
```
Exemple:
```http
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
```json
{
"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:
```json
{
"entity_type": "program",
"entity_key": 9001,
"biznumber": "GP1001",
"change_reason": "modified",
"previous_hash": "...",
"current_hash": "..."
}
```
## 4. Collection complete prete pour publication web
### Endpoint
```http
GET /sync/v2/platforms/{platform}/collections/{biznumber}/full?from={date}&to={date}
```
Exemple:
```http
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:
```text
collection -> saisons -> episodes -> programmations
```
### Reponse attendue
```json
{
"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:
```text
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
```http
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
```json
{
"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
```http
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
```json
{
"export_id": "20260801-0900",
"product_keys": [1001, 1002, 1003],
"include": ["presses", "images", "videos", "keywords", "programs"]
}
```
### Exemple response
```json
{
"schema_version": "2.0",
"export_id": "20260801-0900",
"products": []
}
```
## 7. Endpoint pedagogie IDELLO
### Endpoint
```http
GET /sync/v2/platforms/idello/pedagogy
```
### Objectif
Retourner toutes les categories pedagogiques IDELLO et leur hierarchie.
### Reponse attendue
```json
{
"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
```http
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
```json
{
"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
```http
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
```json
{
"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:
```text
concurrence recommandee
concurrence maximale
comportement en cas de rate limit
headers de rate limit
temps de reponse attendu
timeouts recommandes
```
Exemple de headers:
```http
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 8
Retry-After: 30
```
### Pagination
Les endpoints volumineux doivent supporter une pagination stable.
Exemple:
```http
GET /sync/v2/platforms/idello/snapshot?from=2026-08-01&to=2026-08-11&page_size=1000&cursor=...
```
Reponse:
```json
{
"data": [],
"next_cursor": "abc123",
"has_more": true
}
```
### Compression
Support attendu:
```text
gzip ou brotli
```
### ETag / checksum
Les gros endpoints devraient retourner un ETag ou checksum pour detecter rapidement si le contenu a change.
```http
ETag: "sha256-..."
```
### Versioning
Toutes les reponses doivent inclure:
```json
{
"schema_version": "2.0",
"export_id": "20260801-0900"
}
```
Les changements cassants doivent passer par une nouvelle version:
```text
/sync/v3/...
```
### Erreurs standardisees
Format attendu:
```json
{
"error": {
"code": "IMPORT_NOT_READY",
"message": "Latest export is still importing",
"retry_after_seconds": 300,
"export_id": "20260801-0900"
}
}
```
Codes utiles:
```text
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:
```text
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:
```text
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:
```text
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:
```text
program.created
program.updated
program.deleted
product.created
product.updated
product.deleted
collection.updated
serie.updated
media.updated
rights.updated
```
### Payload minimal attendu
```json
{
"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.
```http
GET /sync/v2/events?since_sequence=123456
```
Reponse:
```json
{
"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.
```http
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:
```text
Louise save -> site web
```
La cible devrait etre:
```text
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
```text
GET /sync/v2/status
GET /sync/v2/platforms/{platform}/snapshot
```
Ces deux endpoints reduiraient immediatement la complexite de la synchronisation.
### Priorite 2
```text
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
```text
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
```text
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:
```text
Passer d'une API granulaire par entite a une API de snapshot, diff et publication par plateforme.
```
La demande long terme est:
```text
Ajouter des evenements fiables avec replay afin de permettre une republication ciblee quelques secondes/minutes apres une sauvegarde dans Louise.
```