# Phase 1B — Fournisseurs, sources et identifiants externes

Version : 0.2.0

## Objectif

Cette phase ajoute le socle permettant de brancher des sources externes sans faire dépendre les données canoniques Coaster World de leurs identifiants ou de leur disponibilité.

Elle ne récupère encore aucune donnée automatiquement : les connecteurs, la provenance champ par champ et les niveaux de confiance viendront dans les phases suivantes.

## Tables ajoutées

### `providers`

Catalogue des fournisseurs de données.

Un fournisseur peut représenter une API, un dataset, un site web, une application de parc, un connecteur spécifique ou plus tard un agent IA.

Champs structurants :

- `kind` : type libre et extensible du fournisseur ;
- `status` : activation logique ;
- `scope` : portée (`global`, `selected_parks`, etc.) ;
- `default_priority` : priorité générale, plus la valeur est petite plus le fournisseur est prioritaire ;
- `poll_interval_seconds` : fréquence cible éventuelle pour les données dynamiques ;
- URLs de référence et notes techniques.

Aucun secret/API key n'est stocké dans cette table.

### `provider_capabilities`

Déclare ce que sait fournir un provider, par exemple :

- `park_details`
- `attractions`
- `wait_times`
- `opening_hours`
- `closures`
- `media`

Les capacités restent des chaînes et non des ENUM SQL afin de pouvoir ajouter de nouveaux cas sans migration de schéma.

Une priorité peut être définie pour une capacité particulière.

### `provider_park`

Permet de limiter ou spécialiser un fournisseur à un ou plusieurs parcs.

C'est ce mécanisme qui permettra par exemple d'avoir un provider développé uniquement pour un parc lorsque son application ou son site officiel expose des temps d'attente de meilleure qualité.

Une priorité spécifique au parc peut surcharger la priorité générale du fournisseur.

### `sources`

Registre des sources concrètes : page officielle, endpoint API, dataset, documentation, etc.

Une source peut être liée à un provider ou être indépendante, par exemple une page officielle utilisée manuellement.

Les dates `last_checked_at` et `last_fetched_at` préparent le suivi de fraîcheur sans lancer encore de collecte automatique.

### `external_identifiers`

Fait le lien entre l'identité canonique Coaster World et les identifiants utilisés par les systèmes externes.

Exemple conceptuel :

- Coaster World : parc `42`
- Provider A : `park_id=123`
- Wikidata : `Qxxxx`

Les identifiants peuvent être attachés aux parcs, zones, attractions, coasters, POI et organisations.

Le stockage polymorphique utilise des types stables (`park`, `attraction`, etc.) définis par le morph map Laravel ; les noms de classes PHP ne sont donc pas enregistrés dans la base.

## Règles importantes

- Les données canoniques ne dépendent jamais d'un ID externe.
- Un provider peut être global ou limité à certains parcs.
- Un provider annonce explicitement ses capacités.
- Un même identifiant externe ne peut pas être associé à deux entités Coaster World pour le même provider et namespace.
- Les secrets fournisseurs ne sont pas stockés dans ces tables.
- Les champs de configuration JSON sont réservés aux options non sensibles et extensibles.
- Les valeurs réellement collectées, leurs sources, conflits et scores de confiance restent hors périmètre de cette phase et seront traités en Phase 1C.
