app.parcelle_version
Description
Section intitulée « Description »Version d’un polygone de parcelle ou de zone de cueillette. En ajout seul : une correction est un nouveau relevé, l’ancienne version reste lisible. Un polygone invalide est conservé tel quel, jamais corrigé (pas de ST_MakeValid).
| Name | Type | Default | Nullable | Extra Definition | Children | Parents | Comment |
|---|---|---|---|---|---|---|---|
| id | uuid | app.uuid_v7() | false | sync.controle app.capacite_version | Identifiant stable (UUID v7). | ||
| organisation_id | uuid | false | sync.controle app.capacite_version | app.organisation app.utilisateur app.fichier app.parcelle app.zone_cueillette | Organisation propriétaire. Sert à l’isolation par RLS (EC-032). | ||
| groupement_id | uuid | false | app.parcelle app.zone_cueillette | Groupement de la cible, repris d’elle quand il n’est pas donné. Le téléphone filtre dessus. | |||
| parcelle_id | uuid | true | app.parcelle | Parcelle cible. Exactement une cible entre parcelle et zone de cueillette. | |||
| zone_cueillette_id | uuid | true | app.zone_cueillette | Zone de cueillette cible. Exactement une cible entre parcelle et zone de cueillette. | |||
| version | integer | false | Numéro de version de la cible, à partir de 1, attribué par la base quand il n’est pas donné. La plus élevée est la version en vigueur. | ||||
| geom | geometry(Polygon,4326) | false | Polygone en WGS 84 (SRID 4326). Peut être invalide : il est alors signalé, jamais réparé. | ||||
| geojson | jsonb | false | Le même polygone en GeoJSON, tenu par la base : c’est ce que le téléphone reçoit. | ||||
| valide | boolean | false | Résultat de ST_IsValid sur le polygone, calculé par la base. | ||||
| motif_invalidite | text | true | Raison donnée par ST_IsValidReason quand le polygone est invalide, sinon vide. | ||||
| surface_mesuree_m2 | bigint | true | Surface mesurée en m² (ST_Area en géographie, arrondie). Vide si le polygone est invalide. Base de toute capacité (AV1-01). | ||||
| perimetre_m | bigint | true | Périmètre en mètres (ST_Perimeter en géographie, arrondi). Vide si le polygone est invalide. | ||||
| methode | text | false | Méthode de relevé (GPS-03) : sommets, marche, dessin ou import (EC-048). |
||||
| precision_mediane_cm | integer | false | Précision médiane déclarée du relevé, en centimètres (GPS-03). Pour un import, la précision lue dans le fichier. | ||||
| appareil | text | true | Appareil ou récepteur utilisé pour le relevé (GPS-03), en texte libre. | ||||
| trace_fichier_id | uuid | true | app.fichier | Trace brute du relevé (fichier de la même organisation), conservée pour l’audit (GPS-03). | |||
| incertitude_m2 | bigint | true | GENERATED ALWAYS AS CASE WHEN (perimetre_m IS NULL) THEN NULL::bigint ELSE (round((((perimetre_m * precision_mediane_cm))::numeric / 100.0)))::bigint END STORED |
Incertitude de la surface mesurée (GPS-04) : périmètre × précision médiane, calculée. Un écart avec la surface déclarée plus petit n’est pas une anomalie. | |||
| cree_par | uuid | true | app.utilisateur | Utilisateur qui a importé ou relevé la version. | |||
| cree_le | timestamp with time zone | now() | false | Date de création de la version : début de sa période de vigueur. |
Constraints
Section intitulée « Constraints »| Name | Type | Definition |
|---|---|---|
| parcelle_version_check | CHECK | CHECK (((parcelle_id IS NULL) <> (zone_cueillette_id IS NULL))) |
| parcelle_version_check1 | CHECK | CHECK ((valide = ((surface_mesuree_m2 IS NOT NULL) AND (perimetre_m IS NOT NULL)))) |
| parcelle_version_check2 | CHECK | CHECK ((valide = (motif_invalidite IS NULL))) |
| parcelle_version_methode_check | CHECK | CHECK ((methode = ANY (ARRAY[‘sommets’::text, ‘marche’::text, ‘dessin’::text, ‘import’::text]))) |
| parcelle_version_perimetre_m_check | CHECK | CHECK ((perimetre_m > 0)) |
| parcelle_version_precision_mediane_cm_check | CHECK | CHECK ((precision_mediane_cm >= 0)) |
| parcelle_version_surface_mesuree_m2_check | CHECK | CHECK ((surface_mesuree_m2 > 0)) |
| parcelle_version_version_check | CHECK | CHECK ((version > 0)) |
| parcelle_version_organisation_id_fkey | FOREIGN KEY | FOREIGN KEY (organisation_id) REFERENCES app.organisation(id) |
| parcelle_version_organisation_id_cree_par_fkey | FOREIGN KEY | FOREIGN KEY (organisation_id, cree_par) REFERENCES app.utilisateur(organisation_id, id) |
| parcelle_version_organisation_id_trace_fichier_id_fkey | FOREIGN KEY | FOREIGN KEY (organisation_id, trace_fichier_id) REFERENCES app.fichier(organisation_id, id) |
| parcelle_version_organisation_id_groupement_id_parcelle_id_fkey | FOREIGN KEY | FOREIGN KEY (organisation_id, groupement_id, parcelle_id) REFERENCES app.parcelle(organisation_id, groupement_id, id) |
| parcelle_version_organisation_id_groupement_id_zone_cueill_fkey | FOREIGN KEY | FOREIGN KEY (organisation_id, groupement_id, zone_cueillette_id) REFERENCES app.zone_cueillette(organisation_id, groupement_id, id) |
| parcelle_version_pkey | PRIMARY KEY | PRIMARY KEY (id) |
| parcelle_version_organisation_id_id_key | UNIQUE | UNIQUE (organisation_id, id) |
| parcelle_version_parcelle_id_version_key | UNIQUE | UNIQUE (parcelle_id, version) |
| parcelle_version_zone_cueillette_id_version_key | UNIQUE | UNIQUE (zone_cueillette_id, version) |
| Name | Definition |
|---|---|
| parcelle_version_pkey | CREATE UNIQUE INDEX parcelle_version_pkey ON app.parcelle_version USING btree (id) |
| parcelle_version_organisation_id_id_key | CREATE UNIQUE INDEX parcelle_version_organisation_id_id_key ON app.parcelle_version USING btree (organisation_id, id) |
| parcelle_version_parcelle_id_version_key | CREATE UNIQUE INDEX parcelle_version_parcelle_id_version_key ON app.parcelle_version USING btree (parcelle_id, version) |
| parcelle_version_zone_cueillette_id_version_key | CREATE UNIQUE INDEX parcelle_version_zone_cueillette_id_version_key ON app.parcelle_version USING btree (zone_cueillette_id, version) |
| parcelle_version_geom_idx | CREATE INDEX parcelle_version_geom_idx ON app.parcelle_version USING gist (geom) |
Triggers
Section intitulée « Triggers »| Name | Definition |
|---|---|
| journal | CREATE TRIGGER journal AFTER INSERT OR DELETE OR UPDATE ON app.parcelle_version FOR EACH ROW EXECUTE FUNCTION journal.tg_journaliser() |
| ajout_seul | CREATE TRIGGER ajout_seul BEFORE DELETE OR UPDATE ON app.parcelle_version FOR EACH ROW EXECUTE FUNCTION app.tg_ajout_seul() |
| calcul | CREATE TRIGGER calcul BEFORE INSERT ON app.parcelle_version FOR EACH ROW EXECUTE FUNCTION app.tg_parcelle_version_calcul() |
| controle_invalide | CREATE TRIGGER controle_invalide AFTER INSERT ON app.parcelle_version FOR EACH ROW EXECUTE FUNCTION app.tg_parcelle_version_controle() |
Relations
Section intitulée « Relations »erDiagram
"sync.controle" }o--|| "app.parcelle_version" : "FOREIGN KEY (organisation_id, parcelle_version_id) REFERENCES app.parcelle_version(organisation_id, id)"
"app.capacite_version" }o--|| "app.parcelle_version" : "FOREIGN KEY (organisation_id, parcelle_version_id) REFERENCES app.parcelle_version(organisation_id, id)"
"app.parcelle_version" }o--|| "app.organisation" : "FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)"
"app.parcelle_version" }o--|| "app.utilisateur" : "FOREIGN KEY (organisation_id, cree_par) REFERENCES app.utilisateur(organisation_id, id)"
"app.parcelle_version" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, trace_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.parcelle_version" }o--|| "app.parcelle" : "FOREIGN KEY (organisation_id, groupement_id, parcelle_id) REFERENCES app.parcelle(organisation_id, groupement_id, id)"
"app.parcelle_version" }o--|| "app.zone_cueillette" : "FOREIGN KEY (organisation_id, groupement_id, zone_cueillette_id) REFERENCES app.zone_cueillette(organisation_id, groupement_id, id)"
"app.parcelle_version" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement de la cible, repris d'elle quand il n'est pas donné. Le téléphone filtre dessus."
uuid parcelle_id FK "Parcelle cible. Exactement une cible entre parcelle et zone de cueillette."
uuid zone_cueillette_id FK "Zone de cueillette cible. Exactement une cible entre parcelle et zone de cueillette."
integer version "Numéro de version de la cible, à partir de 1, attribué par la base quand il n'est pas donné. La plus élevée est la version en vigueur."
geometry_Polygon_4326_ geom "Polygone en WGS 84 (SRID 4326). Peut être invalide : il est alors signalé, jamais réparé."
jsonb geojson "Le même polygone en GeoJSON, tenu par la base : c'est ce que le téléphone reçoit."
boolean valide "Résultat de ST_IsValid sur le polygone, calculé par la base."
text motif_invalidite "Raison donnée par ST_IsValidReason quand le polygone est invalide, sinon vide."
bigint surface_mesuree_m2 "Surface mesurée en m² (ST_Area en géographie, arrondie). Vide si le polygone est invalide. Base de toute capacité (AV1-01)."
bigint perimetre_m "Périmètre en mètres (ST_Perimeter en géographie, arrondi). Vide si le polygone est invalide."
text methode "Méthode de relevé (GPS-03) : `sommets`, `marche`, `dessin` ou `import` (EC-048)."
integer precision_mediane_cm "Précision médiane déclarée du relevé, en centimètres (GPS-03). Pour un import, la précision lue dans le fichier."
text appareil "Appareil ou récepteur utilisé pour le relevé (GPS-03), en texte libre."
uuid trace_fichier_id FK "Trace brute du relevé (fichier de la même organisation), conservée pour l'audit (GPS-03)."
bigint incertitude_m2 "Incertitude de la surface mesurée (GPS-04) : périmètre × précision médiane, calculée. Un écart avec la surface déclarée plus petit n'est pas une anomalie."
uuid cree_par FK "Utilisateur qui a importé ou relevé la version."
timestamp_with_time_zone cree_le "Date de création de la version : début de sa période de vigueur."
}
"sync.controle" {
uuid id "Identifiant du contrôle (UUID v7)."
uuid organisation_id FK "Organisation propriétaire de la ligne. Sert à l'isolation par RLS (EC-032) et au filtrage de la synchronisation."
uuid commande_id FK "Commande à l'origine du contrôle."
text motif "Motif du contrôle, parmi le catalogue du protocole (§9). « module_inactif » (EC-096) : commande d'un module inactif, conservée sans écriture métier."
jsonb details "Éléments de contexte, en JSON."
text statut "Statut : ouvert, en_cours ou leve."
text decision "Décision de levée. Renseignée si et seulement si le contrôle est levé."
text motif_decision "Motif de la décision."
uuid decide_par FK "Utilisateur qui a levé le contrôle. Jamais l'auteur de la commande."
timestamp_with_time_zone decide_le "Date de la levée."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
uuid producteur_id FK "Producteur concerné par le contrôle (de la même organisation), par exemple pour un doublon de pièce d'identité (AV1-02)."
uuid parcelle_version_id FK "Version de polygone concernée par le contrôle (de la même organisation) : polygone invalide ou chevauchement."
}
"app.capacite_version" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement de la cible, repris d'elle par la base. Le téléphone filtre dessus."
uuid parcelle_id FK "Parcelle cible. Exactement une cible entre parcelle et zone de cueillette."
uuid zone_cueillette_id FK "Zone de cueillette cible (EC-050)."
uuid campagne_id FK "Campagne de la capacité. Deux campagnes la même année portent chacune la leur."
integer version "Numéro de version pour la cible et la campagne, attribué par la base."
uuid parcelle_version_id FK "Version de polygone sur laquelle la capacité est calculée, posée par la base. Si le polygone change, la capacité n'est plus applicable (EC-012)."
bigint surface_mesuree_m2 "Surface mesurée de cette version de polygone, en m², posée par la base. La surface déclarée n'entre jamais dans le calcul (AV1-01)."
bigint rendement_g_ha "Rendement de référence en vigueur lors de la saisie, en g/ha, posé par la base."
bigint capacite_g "Capacité en grammes, calculée : surface mesurée × rendement / 10 000, arrondie au plus proche (RG-020). Seule formule du projet pour la capacité."
uuid cree_par FK "Auteur de la proposition : il ne peut pas la valider (SB-11)."
timestamp_with_time_zone cree_le "Date de création de la version."
}
"app.organisation" {
uuid id "Identifiant de l'organisation (UUID v7)."
text code "Code court en majuscules. Immuable : il figure dans les identifiants Keycloak (coopa.agent01). « EXT » est réservé."
text nom "Nom de l'organisation."
text pays "Pays, code ISO 3166-1 alpha-2."
text langue "Langue de l'organisation : fr ou en."
text fuseau_horaire "Fuseau horaire IANA utilisé pour l'affichage des dates."
text devise_defaut "Devise par défaut des montants, code ISO 4217."
text keycloak_organisation_id "Identifiant de l'organisation dans Keycloak."
text organisme_certificateur "Organisme de certification de l'organisation. Aucun contrôle de format (EC-027)."
text code_operateur "Code d'opérateur attribué par l'organisme certificateur."
uuid logo_fichier_id FK "Fichier du logo (EC-029)."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
text source_conformite "Source des décisions de conformité : `interne` (contrôle interne de BioTrace) ou `externe` (outil tiers). Une seule source active à la fois ; app.statut_conformite.source doit lui être égale."
text statut "État du compte client : `active` ou `suspendue`. Une organisation suspendue est refusée par la garde d'authentification (`organisation_suspendue`) ; ses données et ses comptes sont conservés. Décidé par l'équipe de l'éditeur (EC-126)."
timestamp_with_time_zone suspendue_le "Date de la suspension en cours ; nulle tant que l'organisation est active."
}
"app.utilisateur" {
uuid id "Identifiant de l'utilisateur (UUID v7)."
uuid organisation_id FK "Organisation propriétaire de la ligne. Sert à l'isolation par RLS (EC-032) et au filtrage de la synchronisation."
uuid keycloak_sub "Identifiant du compte Keycloak (revendication sub). Identique d'une organisation à l'autre pour un compte externe."
text identifiant "Identifiant local de connexion, sans le code de l'organisation : 3 à 32 caractères parmi a-z, 0-9, _ et -. Unique dans l'organisation."
text nom_affiche "Nom affiché dans l'application."
text telephone "Numéro de téléphone. Attribut du compte, jamais son identifiant."
text statut "Statut du compte : actif, suspendu ou desactive."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
}
"app.fichier" {
uuid id "Identifiant du fichier (UUID v7, généré sur l'appareil ou par l'API)."
uuid organisation_id FK "Organisation propriétaire de la ligne. Sert à l'isolation par RLS (EC-032) et au filtrage de la synchronisation."
text cle_objet "Clé de l'objet dans le stockage."
text type_mime "Type MIME du contenu."
bigint taille_octets "Taille en octets."
text sha256 "Empreinte SHA-256 du contenu, en hexadécimal."
text statut "Statut : attendu, recu ou empreinte_invalide. Un fichier reçu n'est plus modifiable."
uuid appareil_id FK "Appareil d'origine du dépôt."
uuid depose_par FK "Utilisateur qui a déposé le fichier."
timestamp_with_time_zone depose_le "Date de réception du contenu par le stockage."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
}
"app.parcelle" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement de la parcelle, identique à celui de son producteur (clé composée) : un producteur qui a des parcelles ne change pas de groupement."
uuid producteur_id FK "Producteur propriétaire de la parcelle (de la même organisation)."
uuid produit_id FK "Produit cultivé (de la même organisation)."
text code "Code de la parcelle, unique par organisation."
text type_surface "`cultures`, `serres` ou `prairies` : sert aux seuils d'éligibilité au groupe (RG-024)."
bigint surface_declaree_m2 "Surface déclarée par le producteur, en m² (EC-030). Jamais la base d'une capacité : c'est la surface mesurée (AV1-01)."
text region_facteur FK "Constante `region` : nom du facteur de la clé étrangère composée vers facteur_valeur."
text region FK "Région (valeur du facteur `region`), facultative."
text mode_culture_facteur FK "Constante `mode_culture` : nom du facteur de la clé étrangère composée vers facteur_valeur."
text mode_culture FK "Mode de culture (`pluvial` ou `irrigue`), facultatif."
text type_sol_facteur FK "Constante `type_sol` : nom du facteur de la clé étrangère composée vers facteur_valeur."
text type_sol FK "Type de sol (valeur du facteur `type_sol`), facultatif."
boolean actif "Faux quand la parcelle n'est plus utilisée. Une parcelle n'est jamais supprimée."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.zone_cueillette" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement qui exploite la zone (de la même organisation)."
uuid produit_id FK "Produit cueilli (de la même organisation)."
text code "Code de la zone, unique par organisation."
text nom "Nom de la zone."
boolean actif "Faux quand la zone n'est plus utilisée. Une zone n'est jamais supprimée."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
Generated by tbls