452 lines
13 KiB
Markdown
452 lines
13 KiB
Markdown
|
|
## Objectif
|
|
|
|
Nous évaluons une nouvelle façon de fournir les données de programmation et de contenus aux sites web TFO, IDELLO, ONFR et linéaire.
|
|
|
|
L'objectif est de savoir si une publication sous forme de fichiers JSON versionnés peut bien répondre à vos besoins techniques et opérationnels.
|
|
|
|
Ce document ne présente pas une décision finale. Il sert à recueillir vos commentaires avant de figer le format.
|
|
|
|
## Idée générale
|
|
|
|
Aujourd'hui, les données sont disponibles via Directus ou via des mécanismes de synchronisation propres à chaque site.
|
|
|
|
La proposition est de publier des fichiers JSON prêts à consommer, organisés par plateforme, par version et par publication.
|
|
|
|
Exemple:
|
|
|
|
```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/2026-07-30.json
|
|
/tfo/v1/runs/20260730-0900/schedule/2026-08-08.json
|
|
/tfo/v1/runs/20260730-0900/products/GP123456.json
|
|
/tfo/v1/runs/20260730-0900/collections/0123456/full.json
|
|
/tfo/v1/runs/20260730-0900/search/index.json
|
|
```
|
|
|
|
Les sites ne devraient pas coder un chemin de run en dur. Ils liraient d'abord:
|
|
|
|
```text
|
|
/tfo/v1/manifest.json
|
|
```
|
|
|
|
Puis utiliseraient le `base_path` retourné par le manifest pour charger les fichiers du run actif.
|
|
|
|
## Exemple de manifest
|
|
|
|
```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.json` permet de changer de publication de façon atomique. Si une nouvelle génération échoue, le manifest continue de pointer vers le dernier run valide.
|
|
|
|
## Runs complets et changements incrémentaux
|
|
|
|
Chaque run publié doit être considéré comme une version complète des données disponibles pour une plateforme.
|
|
|
|
Par contre, entre deux runs, tous les fichiers ne changent pas nécessairement.
|
|
|
|
Exemple:
|
|
|
|
```text
|
|
Run 1:
|
|
8 000 produits
|
|
|
|
Run 2:
|
|
10 nouveaux produits
|
|
5 produits retirés
|
|
7 produits modifiés
|
|
```
|
|
|
|
Dans ce cas, le run 2 reste un run complet pour le site, mais seuls les fichiers réellement impactés devraient changer.
|
|
|
|
Conséquence pour les sites:
|
|
|
|
- il faut toujours lire le `manifest.json` pour connaître le run actif;
|
|
- il ne faut pas supposer que tous les fichiers changent à chaque run;
|
|
- un fichier produit inchangé peut être identique entre deux runs;
|
|
- un produit retiré ne devrait plus apparaître dans les indexes du nouveau run;
|
|
- `latest.json` peut aider à savoir ce qui a été ajouté, modifié ou retiré.
|
|
|
|
Cette approche permet de publier plus vite et de réduire le risque de remplacer des données valides par des données incomplètes.
|
|
|
|
## Types de fichiers proposés
|
|
|
|
### today.json
|
|
|
|
Contient les contenus ou programmations pertinents pour la journée courante.
|
|
|
|
Le tableau `programs` contient des objets de programmation légers. Il ne contient pas tout le détail du produit ou de la collection. Pour le détail complet, le site utilise les liens vers les fichiers `products/{product_key}.json` ou `collections/{biznumber}/full.json`.
|
|
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"platform": "tfo",
|
|
"run_id": "20260730-0900",
|
|
"date": "2026-07-30",
|
|
"programs": [
|
|
{
|
|
"program_key": "190858829",
|
|
"product_key": "102828840",
|
|
"collection_biznumber": "0123456",
|
|
"serie_key": "S123",
|
|
"title": "Larguer les amarres",
|
|
"begin": "2026-07-30T06:00:00-04:00",
|
|
"end": "2026-07-30T06:24:00-04:00",
|
|
"duration_seconds": 1440,
|
|
"type": "Film",
|
|
"target": "G",
|
|
"territories": ["CA"],
|
|
"media_status": "ready",
|
|
"links": {
|
|
"product": "/tfo/v1/runs/20260730-0900/products/102828840.json",
|
|
"collection_full": "/tfo/v1/runs/20260730-0900/collections/0123456/full.json"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### latest.json
|
|
|
|
Contient les contenus ajoutés, modifiés ou retirés depuis la dernière publication.
|
|
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"platform": "tfo",
|
|
"run_id": "20260730-0900",
|
|
"added": [
|
|
{
|
|
"entity_type": "product",
|
|
"product_key": "102828840",
|
|
"collection_biznumber": "0123456",
|
|
"title": "Larguer les amarres",
|
|
"first_programmation": "2026-07-30T06:00:00-04:00",
|
|
"links": {
|
|
"product": "/tfo/v1/runs/20260730-0900/products/102828840.json"
|
|
}
|
|
}
|
|
],
|
|
"updated": [
|
|
{
|
|
"entity_type": "program",
|
|
"program_key": "190858829",
|
|
"product_key": "102828840",
|
|
"title": "Larguer les amarres",
|
|
"changed_fields": ["begin", "end"],
|
|
"links": {
|
|
"product": "/tfo/v1/runs/20260730-0900/products/102828840.json"
|
|
}
|
|
}
|
|
],
|
|
"removed": [
|
|
{
|
|
"entity_type": "product",
|
|
"product_key": "102000001",
|
|
"collection_biznumber": "0999999",
|
|
"title": "Ancien titre",
|
|
"reason": "not_in_current_snapshot"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### schedule/YYYY-MM-DD.json
|
|
|
|
Contient la programmation pour une date précise.
|
|
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"platform": "tfo",
|
|
"run_id": "20260730-0900",
|
|
"date": "2026-08-08",
|
|
"programs": [
|
|
{
|
|
"program_key": "123",
|
|
"product_key": "GP123456",
|
|
"collection_biznumber": "0123456",
|
|
"serie_key": "S123",
|
|
"begin": "2026-08-08T06:00:00-04:00",
|
|
"end": "2026-08-08T06:24:00-04:00",
|
|
"title": "Titre de l'épisode",
|
|
"duration_seconds": 1440,
|
|
"type": "Film",
|
|
"target": "G",
|
|
"territories": ["CA"],
|
|
"media_status": "ready",
|
|
"links": {
|
|
"product": "/tfo/v1/runs/20260730-0900/products/GP123456.json",
|
|
"collection_full": "/tfo/v1/runs/20260730-0900/collections/0123456/full.json"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
La première version viserait une fenêtre future jusqu'à J+10.
|
|
|
|
### products/{product_key}.json
|
|
|
|
Contient le détail d'un produit ou épisode.
|
|
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"platform": "tfo",
|
|
"run_id": "20260730-0900",
|
|
"product": {
|
|
"product_key": "GP123456",
|
|
"biznumber": "0123456",
|
|
"title": "Titre de l'épisode",
|
|
"description": "..."
|
|
},
|
|
"programmations": {
|
|
"current": [],
|
|
"upcoming": [],
|
|
"next": {
|
|
"date": "2026-08-08",
|
|
"begin": "2026-08-08T06:00:00-04:00"
|
|
}
|
|
},
|
|
"media": {},
|
|
"images": []
|
|
}
|
|
```
|
|
|
|
### Images
|
|
|
|
Les images pourraient être fournies avec des URLs déjà prêtes pour les principaux usages des sites.
|
|
|
|
Exemple:
|
|
|
|
```json
|
|
{
|
|
"images": [
|
|
{
|
|
"type": "thumbnail",
|
|
"alt": "Description de l'image",
|
|
"variants": {
|
|
"card": "https://images.example.com/tfo/card/abc.jpg",
|
|
"hero": "https://images.example.com/tfo/hero/abc.jpg",
|
|
"poster": "https://images.example.com/tfo/poster/abc.jpg",
|
|
"original": "https://assets.example.com/originals/abc.jpg"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
L'objectif est de ne pas forcer les sites à télécharger des images sources trop lourdes, tout en évitant de dupliquer inutilement les fichiers. Les variants exacts restent à confirmer avec vous.
|
|
|
|
### collections/{biznumber}/full.json
|
|
|
|
Contient une vue complète d'une collection, dans le sens attendu par les sites:
|
|
|
|
```text
|
|
collection -> saisons -> épisodes
|
|
```
|
|
|
|
Exemple:
|
|
|
|
```json
|
|
{
|
|
"schema_version": "1.0",
|
|
"platform": "tfo",
|
|
"run_id": "20260730-0900",
|
|
"collection": {
|
|
"biznumber": "0123456",
|
|
"title": "Titre de la collection",
|
|
"description": "...",
|
|
"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": {
|
|
"serie_key": "S123",
|
|
"title": "Saison 1"
|
|
},
|
|
"episodes": [
|
|
{
|
|
"product": {
|
|
"product_key": "GP123456",
|
|
"title": "Épisode 1"
|
|
},
|
|
"programmations": [],
|
|
"media": {},
|
|
"images": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### search/index.json
|
|
|
|
Fichier optionnel pouvant servir à alimenter un moteur de recherche comme Algolia, Meilisearch, Typesense ou un index interne.
|
|
|
|
```json
|
|
[
|
|
{
|
|
"objectID": "GP123456",
|
|
"type": "product",
|
|
"title": "Titre de l'épisode",
|
|
"slug": "titre-de-lepisode",
|
|
"image": "https://...",
|
|
"collection_biznumber": "0123456"
|
|
}
|
|
]
|
|
```
|
|
|
|
## Cache proposé
|
|
|
|
Le manifest aurait un cache court:
|
|
|
|
```text
|
|
/tfo/v1/manifest.json
|
|
Cache-Control: public, max-age=60, stale-while-revalidate=120
|
|
```
|
|
|
|
Les fichiers d'un run seraient immuables et pourraient être cachés longtemps:
|
|
|
|
```text
|
|
/tfo/v1/runs/20260730-0900/*
|
|
Cache-Control: public, max-age=31536000, immutable
|
|
```
|
|
|
|
Logique:
|
|
|
|
- le site consulte régulièrement `manifest.json`;
|
|
- si `run_id` change, le site charge les fichiers du nouveau run;
|
|
- les fichiers des runs ne changent jamais;
|
|
- un rollback peut être fait en repointant le manifest vers un run précédent.
|
|
|
|
## Garanties attendues
|
|
|
|
Le modèle proposé vise à garantir les comportements suivants:
|
|
|
|
- un run publié est complet pour la plateforme concernée;
|
|
- `manifest.json` pointe seulement vers un run valide;
|
|
- si une génération échoue, le manifest reste sur le dernier run valide;
|
|
- les fichiers d'un run ne changent pas après publication;
|
|
- les changements sont visibles via `latest.json`;
|
|
- les produits retirés ne sont plus présents dans les indexes du nouveau run;
|
|
- les anciens runs peuvent servir au rollback pendant la période de rétention.
|
|
|
|
Ce modèle permet aussi de publier rapidement des corrections ciblées. Par exemple, si une correction interne touche une collection ou un produit, seuls les fichiers impactés devraient changer dans le prochain run.
|
|
|
|
Limite importante: cette publication ne rend pas la source officielle instantanée. Si une donnée n'a pas encore été reçue par notre système, elle ne peut pas apparaître dans les JSON.
|
|
|
|
## Ce que ce feed n'est pas
|
|
|
|
Ce feed JSON n'est pas destiné à devenir:
|
|
|
|
- une API dynamique publique;
|
|
- un CMS éditorial;
|
|
- un moteur de recherche complet;
|
|
- un outil d'édition fournisseur;
|
|
- une refonte de votre site.
|
|
|
|
L'objectif est de fournir un contrat de données stable, versionné et facile à consommer.
|
|
|
|
## Points importants pour les sites
|
|
|
|
- Les JSON seraient versionnés dans le chemin: `/v1/`, puis éventuellement `/v2/`.
|
|
- Les changements cassants seraient publiés dans une nouvelle version.
|
|
- Les dates seraient fournies avec timezone explicite.
|
|
- Les fichiers seraient séparés pour éviter de télécharger un énorme JSON unique.
|
|
- Les sites pourraient consommer seulement les fichiers utiles à leurs pages.
|
|
- Les fournisseurs pourraient avoir accès uniquement à leur plateforme ou préfixe.
|
|
|
|
## Questions pour vous
|
|
|
|
Merci de nous dire si cette approche fonctionnerait pour votre site, et de commenter les points suivants.
|
|
|
|
### Consommation
|
|
|
|
- Est-ce que votre site peut consommer des fichiers JSON statiques via HTTP/CDN?
|
|
- Est-ce que votre site peut lire un `manifest.json` avant de charger les données?
|
|
- Avez-vous besoin d'une API dynamique, ou des fichiers JSON suffisent?
|
|
- Avez-vous des contraintes sur le nombre de fichiers chargés?
|
|
|
|
### Structure des données
|
|
|
|
- Le modèle `collection -> seasons -> episodes` convient-il à vos pages?
|
|
- Le fichier `products/{product_key}.json` contient-il le bon niveau de détail?
|
|
- Le fichier `collections/{biznumber}/full.json` est-il trop gros, trop petit ou correct?
|
|
- Avez-vous besoin d'autres regroupements?
|
|
- Quels champs sont obligatoires pour vos pages?
|
|
|
|
### Programmation
|
|
|
|
- La fenêtre future J+10 est-elle suffisante?
|
|
- Avez-vous besoin de programmation passée?
|
|
- Avez-vous besoin d'un fichier par date, par semaine ou par mois?
|
|
- Comment affichez-vous "prochain épisode" aujourd'hui?
|
|
|
|
### Media et images
|
|
|
|
- Quels champs media sont requis pour votre lecteur vidéo?
|
|
- Avez-vous besoin de plusieurs formats d'image?
|
|
- Quels variants d'image seraient utiles pour vos pages? Exemples: `card`, `hero`, `poster`, `thumbnail`, `original`.
|
|
- Préférez-vous recevoir des URLs d'image prêtes à l'emploi ou construire les URLs à partir d'un template documenté?
|
|
- Avez-vous besoin de sous-titres, transcriptions, audio ou autres assets dans le JSON?
|
|
|
|
### Recherche
|
|
|
|
- Utilisez-vous Algolia, Meilisearch, Typesense ou un autre moteur?
|
|
- Un fichier `search/index.json` vous serait-il utile?
|
|
- Quels champs devraient être inclus dans l'index?
|
|
|
|
### Cache et mise à jour
|
|
|
|
- Un cache court sur `manifest.json` vous convient-il?
|
|
- Quelle fréquence de vérification du manifest serait acceptable?
|
|
- Avez-vous besoin d'un webhook ou signal pour savoir qu'un nouveau run est disponible?
|
|
- Comment votre site ferait-il un rollback si nécessaire?
|
|
|
|
### Migration
|
|
|
|
- Pouvez-vous tester cette approche en parallèle de votre intégration actuelle?
|
|
- Quel serait le meilleur pilote pour vous: une page, une plateforme, une collection, une section?
|
|
- Quels risques voyez-vous dans une migration vers ce modèle?
|
|
|
|
## Commentaires attendus
|
|
|
|
Pour nous aider à valider l'approche, merci de répondre avec:
|
|
|
|
- les fichiers que vous utiliseriez;
|
|
- les champs manquants;
|
|
- les champs inutiles;
|
|
- les contraintes de performance ou cache;
|
|
- les impacts sur votre architecture;
|
|
- les risques de migration;
|
|
- une estimation du travail côté site.
|
|
|
|
## Décision recherchée
|
|
|
|
Nous voulons confirmer si cette approche JSON peut devenir un contrat stable entre notre système de publication et les sites.
|
|
|
|
La décision attendue n'est pas encore "on migre tout". La décision attendue est plutôt:
|
|
|
|
```text
|
|
Est-ce que ce modèle JSON est techniquement viable pour les sites?
|
|
Si oui, quels ajustements sont nécessaires avant un pilote?
|
|
``` |