# Schéma de données normalisé — DIGIPAV Research

Statut : **document de référence prototype**. Il décrit le modèle logique utilisé
aujourd'hui côté client (imports locaux + jeu de démonstration) et qui servira de
contrat lors du branchement d'un backend (Lovable Cloud / PostgreSQL).

Toute donnée affichée porte une provenance explicite :
`Données importées` ou `Démonstration`. Aucune valeur n'est un résultat
scientifique validé.

Source de vérité du code : `src/lib/import-schema.ts` (types `Imported*`,
`SCHEMAS`, `buildImportBundle`) et `src/lib/data-unifiee.ts` (fusion
import → démo).

## 1. Vue d'ensemble

```text
zone (agroécologique)
  └── site (station / localité)
        └── parcelle
              ├── ressource        (arbre, génotype, variété, champ semencier, parc à bois, média, document)
              ├── observation      (terrain, phénologie, sanitaire, mesure)
              └── analyse_sol      (prélèvement + résultats labo)
        └── climat                 (série mensuelle rattachée au site)
```

Règles de rattachement :

- `parcelle.siteId` → `site.id` (obligatoire)
- `ressource.parcelleId` → `parcelle.id` (optionnel) et/ou `ressource.siteId` → `site.id`
- `observation.parcelleId` → `parcelle.id` (obligatoire), `observation.arbreId` → `ressource.id` (optionnel)
- `analyse_sol.parcelleId` → `parcelle.id` (obligatoire)
- `climat.siteId` → `site.id` (obligatoire)

## 2. Entités

### zone

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | clé métier |
| code | string | oui | ex. `ZONE-V` |
| nom | string | oui | libellé de la zone agroécologique |
| description | string | non | |
| source | string | non | fichier / origine |

### site

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | ex. `SIT-01` |
| nom | string | oui | |
| region, commune, zoneAgro, bassin | string | non | rattachement territorial |
| altitude, pluvio, surface | number | non | m, mm/an, ha |
| lat, lon | number | non | WGS84 décimal |
| x, y | number | dérivé | position sur la carte simulée (0-100) |
| qualite | enum | non | `validee \| complete \| partielle \| a-verifier \| manquante` |
| responsable, creation | string / date | non | |
| source | string | dérivé | provenance de la ligne |

### parcelle

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | |
| siteId | string | oui | clé étrangère site |
| nom | string | oui | |
| culture | string | oui | `Cacao`, `Café Arabica`, `Café Robusta`, `Agroforêt mixte` |
| surface, anneePlantation, densite | number | non | ha, année, pieds/ha |
| systeme, pente, responsable | string | non | |
| ombrage | number \| null | non | % |
| rendement | number \| null | non | kg/ha (déclaratif, non validé) |
| polygone | `[lon, lat][]` | non | issu de GeoJSON (`Polygon`, 1er anneau) |
| qualite, statutSol | enum | non | idem site |
| observations | number | dérivé | compteur |
| source | string | dérivé | |

Distinctions métier portées par `ressource.type` plutôt que par un champ
parcelle : parcelle expérimentale, champ semencier, parc à bois.

### ressource

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | |
| type | enum | oui | `arbre \| genotype \| variete \| champ-semencier \| parc-a-bois \| media \| document \| experimentation` |
| nom | string | oui | |
| siteId / parcelleId | string | non | rattachement (au moins un recommandé) |
| code, culture, espece, varieteId | string | non | identification du matériel |
| geniteur, sexe, origine, conservation, materiel | string | non | banque de gènes |
| statut, sante | string | non | |
| plantation, entree, creation | number / date | non | |
| lat, lon | number | non | point GPS (GeoJSON `Point`) |
| hauteur, circonference, surface | number | non | cm / m / ha |
| qualite | enum | non | |
| source | string | dérivé | |

### observation

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | |
| parcelleId | string | oui | |
| arbreId | string | non | ressource de type `arbre` |
| date | date | oui | ISO `YYYY-MM-DD` |
| type | string | oui | ex. `Floraison`, `Pourriture brune` |
| valeur | string | oui | valeur ou classe observée |
| auteur, gps | string | non | traçabilité de la saisie |
| statut | enum | non | qualité de la donnée |
| source | string | dérivé | |

### climat

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | |
| siteId | string | oui | |
| mois | string | oui | libellé ou `01`..`12` |
| date | date | non | pour séries journalières agrégées |
| pluie, tmoy, humidite, eto | number | non | mm, °C, %, mm |
| statut | enum | non | |
| source | string | dérivé | |

L'agrégat annuel (`ClimatAnnuel` : `pluieTotale`, `tmoy`, `humidite`, `eto`) est
**calculé**, jamais importé.

### analyse_sol

| Champ | Type | Requis | Note |
| --- | --- | --- | --- |
| id | string | oui | |
| campagne | string | oui | ex. `Campagne sols 2024-A` |
| parcelleId | string | oui | |
| date | date | oui | |
| profondeur | string | non | ex. `0-20 cm` |
| preleveur, laboratoire, protocole | string | non | traçabilité analytique |
| ph, matiereOrganique, azote, phosphore, potassium, cec | number | non | unités labo |
| texture, commentaire | string | non | |
| statut | enum | non | |
| source | string | dérivé | |

## 3. Normalisation appliquée à l'import

- Détection automatique du séparateur CSV (`;`, `,`, tabulation) et gestion des
  guillemets, y compris `""` échappés.
- Nombres : virgule décimale et espaces admis (`1 250,5` → `1250.5`).
- Dates : ISO ou numéro de série Excel (converti depuis 1899-12-30).
- Booléens : `true/1/oui/yes`.
- Coordonnées : `lat,lon` textuel, ou géométries GeoJSON `Point` / `Polygon`.
- Qualité : libellés libres ramenés à l'énumération (`normaliserQualite`).
- Erreurs collectées ligne par ligne (`{ ligne, fichier, type, message }`), la
  ligne 2 correspondant au premier enregistrement après l'en-tête.

## 4. Chemin de branchement backend

1. Traduire chaque entité ci-dessus en table (`zone`, `site`, `parcelle`,
   `ressource`, `observation`, `climat`, `analyse_sol`), clés primaires métier
   conservées comme `code` + UUID technique.
2. Conserver les colonnes de traçabilité (`source`, `qualite`/`statut`,
   horodatage, auteur) : elles portent l'étiquetage provenance de l'interface.
3. Remplacer la persistance IndexedDB (`src/lib/import-persistence.ts`) par des
   écritures serveur, en gardant `ImportBundle` comme format de transport.
4. Garder le jeu de démonstration comme fallback explicitement étiqueté jusqu'à
   la recette IRAD.
5. Les règles du moteur de simulation (`src/lib/moteur-simulation.ts`,
   version `2026-01-09-provisoire`) restent **provisoires à valider IRAD** et
   doivent être versionnées côté serveur avec les exécutions.
