# Schéma JSON — documentation de référence

Documente `exemple-template.json` (complet) et
`exemple-template-minimal.json` (minimal). Ne pas confondre avec le
balisage schema.org (LocalBusiness/Person/FAQPage), généré par le
template à partir de ces données — deux choses différentes malgré le
nom proche.

Toute clé absente du JSON d'un client doit être traitée par le
template comme "non renseignée", jamais comme une erreur. Sérialisation
toujours en `JSON_PRETTY_PRINT`, clés triées alphabétiquement.

## Identité (obligatoire)

| Clé | Type | Description |
|---|---|---|
| `slug` | string | Identifiant stable du client. Nom du dossier dans `storage/app/tenants/` et `public/tenants/`. Ne change jamais, même si le client change de domaine. |
| `prenom` | string | Toujours séparé de `nom`, jamais fusionné. |
| `nom` | string | |
| `template` | string | Slug du template à utiliser (ex. `template-2-0`), correspond à un dossier dans `resources/views/tenant-templates/`. |

## Localisation (obligatoire)

| Clé | Type | Description |
|---|---|---|
| `metier` | objet `{slug, libelle}` | Ex. `{"slug": "sophrologue", "libelle": "Sophrologue"}`. Prépare un futur annuaire `/ville/metier/`, non construit actuellement. |
| `ville` | string | Sert à la fois à l'affichage et au futur annuaire — ne pas dupliquer dans `adresse`. |
| `adresse` | objet `{rue, code_postal}` | La ville n'y figure pas, elle vient du champ `ville` ci-dessus. Une seule représentation, jamais de `adresse_2` secondaire. |

## Contact & action (obligatoire sauf mention contraire)

| Clé | Type | Description |
|---|---|---|
| `telephone` | string | Format humain, pour affichage (`"04 68 00 00 00"`). |
| `email` | string, **optionnel** | Absent si le client ne souhaite pas publier d'email. |
| `cta` | objet `{lien, label?, icone?}` | Seul `lien` est obligatoire (peut être `tel:...`, `mailto:...`, ou une URL de prise de RDV externe). `label` par défaut `"Prendre RDV"`, `icone` par défaut `"bi-calendar-date"` si absents. Remplace toutes les anciennes conventions concurrentes de l'ancien système. |
| `domaines` | array de strings | Noms de domaine du client. **Peut être vide** avant le lancement (client encore en construction). |
| `publie` | boolean | Contrôle l'indexation Google, indépendamment de l'URL utilisée. `false` par défaut à la création. |

## SEO (obligatoire)

| Clé | Type | Description |
|---|---|---|
| `meta_accueil` | objet `{titre, description}` | Title et meta description de la page d'accueil. Pas de champ `canonical` stocké : calculé par Laravel à partir de la route, jamais dupliqué en donnée. |
| `google_site_verification` | string ou absent | Hash du fichier `google{hash}.html` si le client est vérifié dans Search Console. Absent si non vérifié. |

## Champs optionnels liés à la verticale métier

| Clé | Type | Description |
|---|---|---|
| `adeli` | string, **optionnel** | Uniquement pour les professions de santé réglementées. Absent pour les autres métiers (jamais présent-mais-vide). |
| `rpps` | string, **optionnel** | Idem. |

## Contenu narratif (optionnel)

| Clé | Type | Description |
|---|---|---|
| `biographie` | objet `{intro, items[]}`, **optionnel** | `items` est un vrai tableau, longueur libre. |
| `approche` | objet `{intro?, vision?, mission?, valeurs?}`, **optionnel** | Chaque sous-champ est indépendamment optionnel. |
| `specialites` | array de strings, **optionnel** | Longueur libre, remplace les anciennes clés `ent_specialite_1..N`. |

## Prestations (obligatoire, tableau vide accepté)

`prestations` est un tableau d'objets "prestation" — **le même type
d'objet** est réutilisé à l'intérieur de son propre champ
`pages_liees`. Un seul schéma, un seul template Blade pour l'afficher.

| Clé (dans un objet prestation) | Type | Description |
|---|---|---|
| `nom` | string | Obligatoire. |
| `slug` | string | Obligatoire. Sert aussi de nom de dossier portfolio (`public/tenants/{slug-client}/portfolio/{slug-prestation}/`) — jamais un numéro. |
| `description` | string | Obligatoire. |
| `tarif` | string, **optionnel** | |
| `meta` | objet `{titre, description}`, **optionnel** | Si absent, le template génère un titre par défaut à partir de `nom`. |
| `citation` | objet `{texte, auteur?}`, **optionnel** | `auteur` lui-même optionnel — jamais de placeholder type `"Auteur anonyme"`, absent si inconnu. |
| `pages_liees` | array d'objets prestation, **optionnel** | Mêmes champs qu'une prestation normale, mais **ne doit pas contenir son propre `pages_liees`** (pas de nesting à plus d'un niveau) — invisible du menu, avec lien retour automatique vers sa prestation parente. |

**Portfolio : pas de champ dans l'objet prestation.** La présence d'un
dossier `public/tenants/{slug-client}/portfolio/{slug-prestation}/`
détermine si la prestation a un portfolio — jamais une liste de
photos dans le JSON (voir `legendes_portfolio` ci-dessous et
`STRUCTURE_DOSSIER_CLIENT.md`).

## Avis et FAQ (optionnel)

| Clé | Type | Description |
|---|---|---|
| `avis` | array de `{auteur, texte, note?}`, **optionnel** | `note` (1 à 5) optionnelle. |
| `faq` | array de `{question, reponse}`, **optionnel** | |

## Portfolio et partenaires (optionnel)

| Clé | Type | Description |
|---|---|---|
| `legendes_portfolio` | objet, **optionnel** | Clé = chemin relatif `{slug-prestation}/{thematique}/{fichier}`, valeur = `{titre, description}`. Une photo sans entrée ici s'affiche quand même, sans légende. |
| `liens_partenaires` | array de `{label, url}`, **optionnel** | |

## Convention générale de valeur vide

Absence de clé, ou `null` si la clé doit rester présente pour une
raison de lisibilité. Jamais `""`, jamais de texte placeholder, jamais
de booléen dédié type `prest_01_active`.
