Aller au contenu

app.fichier

Référence d’un objet du stockage compatible S3 (EC-029). La base garde la référence et l’empreinte, pas le contenu.

Name Type Default Nullable Children Parents Comment
id uuid false app.organisation app.producteur app.parcelle_version app.certificat app.contrat app.preuve app.reception Identifiant du fichier (UUID v7, généré sur l’appareil ou par l’API).
organisation_id uuid false app.producteur app.parcelle_version app.certificat app.contrat app.preuve app.reception app.organisation app.utilisateur app.appareil Organisation propriétaire de la ligne. Sert à l’isolation par RLS (EC-032) et au filtrage de la synchronisation.
cle_objet text false Clé de l’objet dans le stockage.
type_mime text false Type MIME du contenu.
taille_octets bigint true Taille en octets.
sha256 text false Empreinte SHA-256 du contenu, en hexadécimal.
statut text ‘attendu’::text false Statut : attendu, recu ou empreinte_invalide. Un fichier reçu n’est plus modifiable.
appareil_id uuid true app.appareil Appareil d’origine du dépôt.
depose_par uuid true app.utilisateur Utilisateur qui a déposé le fichier.
depose_le timestamp with time zone true Date de réception du contenu par le stockage.
cree_le timestamp with time zone now() false Date de création de la ligne.
modifie_le timestamp with time zone now() false Date de la dernière modification, tenue par un déclencheur.
Name Type Definition
fichier_check CHECK CHECK (((statut = ‘recu’::text) = (depose_le IS NOT NULL)))
fichier_sha256_check CHECK CHECK ((sha256 ~ ‘^[0-9a-f]{64}$’::text))
fichier_statut_check CHECK CHECK ((statut = ANY (ARRAY[‘attendu’::text, ‘recu’::text, ‘empreinte_invalide’::text])))
fichier_taille_octets_check CHECK CHECK ((taille_octets >= 0))
fichier_organisation_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)
fichier_organisation_id_depose_par_fkey FOREIGN KEY FOREIGN KEY (organisation_id, depose_par) REFERENCES app.utilisateur(organisation_id, id)
fichier_organisation_id_appareil_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id, appareil_id) REFERENCES app.appareil(organisation_id, id)
fichier_pkey PRIMARY KEY PRIMARY KEY (id)
fichier_cle_objet_key UNIQUE UNIQUE (cle_objet)
fichier_organisation_id_id_key UNIQUE UNIQUE (organisation_id, id)
Name Definition
fichier_pkey CREATE UNIQUE INDEX fichier_pkey ON app.fichier USING btree (id)
fichier_cle_objet_key CREATE UNIQUE INDEX fichier_cle_objet_key ON app.fichier USING btree (cle_objet)
fichier_organisation_id_id_key CREATE UNIQUE INDEX fichier_organisation_id_id_key ON app.fichier USING btree (organisation_id, id)
Name Definition
journal CREATE TRIGGER journal AFTER INSERT OR DELETE OR UPDATE ON app.fichier FOR EACH ROW EXECUTE FUNCTION journal.tg_journaliser()
modifie_le CREATE TRIGGER modifie_le BEFORE UPDATE ON app.fichier FOR EACH ROW EXECUTE FUNCTION app.tg_modifie_le()
fichier_fige CREATE TRIGGER fichier_fige BEFORE UPDATE ON app.fichier FOR EACH ROW EXECUTE FUNCTION app.tg_fichier_fige()
erDiagram

"app.organisation" }o--o| "app.fichier" : "FOREIGN KEY (logo_fichier_id) REFERENCES app.fichier(id)"
"app.producteur" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, photo_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.producteur" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, piece_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.parcelle_version" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, trace_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.certificat" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.contrat" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.preuve" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.reception" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, ticket_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.fichier" }o--|| "app.organisation" : "FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)"
"app.fichier" }o--|| "app.utilisateur" : "FOREIGN KEY (organisation_id, depose_par) REFERENCES app.utilisateur(organisation_id, id)"
"app.fichier" }o--|| "app.appareil" : "FOREIGN KEY (organisation_id, appareil_id) REFERENCES app.appareil(organisation_id, id)"

"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.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.producteur" {
  uuid id "Identifiant stable (UUID v7), clé d'échange avec le système de contrôle interne."
  uuid organisation_id FK "Organisation qui enrôle le producteur. Sert à l'isolation par RLS (EC-032)."
  uuid groupement_id FK "Groupement d'appartenance (de la même organisation). Le téléphone filtre sur ce groupement."
  text code "Code du producteur, unique par organisation et définitif (RG-010, EC-031)."
  text nom_complet "Nom complet du producteur."
  text telephone "Téléphone. Donnée personnelle : accès réservé aux rôles qui en ont l'usage (EX-063)."
  text village "Village."
  text canton "Canton."
  text zone_production "Zone de production."
  date date_inscription "Date d'inscription du producteur, transmise au système de contrôle interne."
  text type_piece_identite "Type de la pièce d'identité (carte nationale, passeport…). Vocabulaire non contrôlé pour l'instant. Renseigné avec le numéro, ou absent avec lui."
  text numero_piece_identite "Numéro de la pièce d'identité, tel que saisi. Le doublon ne bloque rien : il ouvre un contrôle (AV1-02)."
  text numero_piece_normalise "Numéro de pièce en majuscules, sans espace ni tiret, calculé. Sert à rapprocher deux saisies du même numéro."
  uuid photo_fichier_id FK "Photo du producteur (fichier de la même organisation)."
  uuid piece_fichier_id FK "Image de la pièce d'identité (fichier de la même organisation)."
  bigint chiffre_affaires_valeur "Chiffre d'affaires annuel, en unités mineures de sa devise (EC-028). Sert à l'éligibilité au groupe (EC-014)."
  text chiffre_affaires_devise "Devise ISO 4217 du chiffre d'affaires. Renseignée avec la valeur, ou absente avec elle."
  boolean actif "Faux quand le producteur est retiré des listes de saisie sans altérer l'historique (RG-011). Toujours faux pour une fiche fusionnée."
  text statut "`actif` ou `fusionnee`. Une fiche fusionnée renvoie à la fiche retenue et ne se réactive pas."
  uuid fusionnee_dans_id FK "Fiche retenue quand celle-ci a été absorbée par une fusion. Renseignée si et seulement si le statut est `fusionnee`."
  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.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."
}
"app.certificat" {
  uuid id "Identifiant stable (UUID v7)."
  uuid organisation_id FK "Organisation qui enregistre le certificat. Sert à l'isolation par RLS (EC-032)."
  uuid referentiel_id FK "Référentiel coché par l'organisation (app.organisation_referentiel) que le certificat atteste (EC-101)."
  uuid operateur_id FK "Titulaire opérateur : l'organisation elle-même. Exactement un titulaire entre opérateur, groupement et fournisseur (EC-025)."
  uuid groupement_id FK "Titulaire groupement (de la même organisation). Un certificat de groupe couvre ses membres."
  uuid fournisseur_id FK "Titulaire fournisseur (de la même organisation). Un fournisseur ne se crée pas sans son certificat (EC-053)."
  text organisme_nom "Nom de l'organisme certificateur."
  text organisme_code "Code de l'organisme certificateur, sans contrôle de format (EC-027)."
  text numero "Numéro du certificat, sans contrôle de format."
  date date_debut "Premier jour de validité, inclus."
  date date_fin "Dernier jour de validité, inclus. Jamais avant date_debut. L'expiration se calcule depuis cette date."
  text statut "`valide`, `suspendu` ou `retire`. Pas de valeur « expiré » : il se calcule. La date d'une suspension ou d'un retrait n'est pas stockée (EC-072) ; le journal d'audit en garde la trace."
  uuid fichier_id FK "PDF du certificat (fichier de la même organisation). Obligatoire pour un fournisseur (EC-053)."
  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.contrat" {
  uuid id "Identifiant stable (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
  text code "Code du contrat, unique par organisation."
  text type "`achat` (producteur, groupement ou fournisseur), `vente` (client) ou `prestation` (client ou fournisseur, EC-052)."
  uuid producteur_id FK "Contrepartie producteur (achat). Exactement une contrepartie entre producteur, groupement, fournisseur et client."
  uuid groupement_id FK "Contrepartie groupement (achat)."
  uuid fournisseur_id FK "Contrepartie fournisseur (achat ou prestation)."
  uuid client_id FK "Contrepartie client (vente ou prestation)."
  uuid campagne_id FK "Campagne du contrat (de la même organisation)."
  date date_debut "Premier jour de la période du contrat."
  date date_fin "Dernier jour de la période du contrat. Jamais avant le début."
  text statut "`brouillon`, `actif`, `solde` ou `resilie`. Pas de retour en arrière ; l'activation exige une ligne."
  text conditions_paiement "Conditions de paiement, en texte, facultatives."
  uuid fichier_id FK "Pièce jointe du contrat (fichier de la même organisation), facultative."
  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.preuve" {
  uuid id "Identifiant stable (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
  uuid fichier_id FK "Fichier déposé (de la même organisation)."
  uuid point_controle_id FK "Point de contrôle que la pièce appuie."
  text objet_type "Type de l'objet appuyé. Vide : toute l'organisation."
  uuid objet_id "Identifiant de l'objet appuyé. Renseigné avec `objet_type`, ou pas du tout."
  uuid evaluation_point_id FK "Évaluation que la pièce a motivée, si elle a été liée à ce moment."
  uuid depose_par FK "Utilisateur qui a lié la pièce."
  timestamp_with_time_zone cree_le "Date de liaison."
}
"app.reception" {
  uuid id "Identifiant de la réception (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
  uuid campagne_id FK "Campagne de la réception."
  uuid produit_id FK "Produit reçu."
  uuid producteur_id FK "Producteur qui livre ; vide si la matière vient d'un fournisseur (l'un ou l'autre, jamais les deux)."
  uuid fournisseur_id FK "Fournisseur qui livre ; vide si la matière vient d'un producteur."
  uuid contrat_id FK "Contrat dont la formule de réfaction s'applique ; vide si aucun contrat (aucune réfaction)."
  uuid lot_id FK "Lot créé par la réception, avec son mouvement de création (I4). Un lot naît d'une seule réception."
  timestamp_with_time_zone date_operation "Date de la réception, saisie sur le terrain : c'est elle qui sert à apprécier l'état du certificat (RG-014)."
  text statut "Statut : en_attente, validee ou rejetee. Ne revient jamais en arrière ; une erreur se corrige par annulation (L2-6)."
  jsonb formule_refaction "Formule de réfaction retenue, copiée du contrat à l'enregistrement : c'est elle qui est imprimée sur le bon de réception (RG-171)."
  jsonb detail_calcul "Détail du calcul du poids net marchand (brut, tare, net, excédent, réfaction), figé tel qu'imprimé (RG-171)."
  bigint net_marchand_g "Poids net marchand en grammes : net de pesée moins la réfaction du contrat. Copie du détail pour les lectures."
  uuid ticket_fichier_id FK "Ticket de pesée conservé (RG-170), facultatif tant que le stockage objet n'est pas en place."
  text derogation_motif "Justification de la dérogation de la direction quand une règle bloque la réception (RG-014) ; vide sans dérogation."
  uuid derogation_par FK "Utilisateur de la direction qui a donné la dérogation."
  timestamp_with_time_zone derogation_le "Date de la dérogation."
  uuid decide_par FK "Utilisateur qui a validé ou rejeté la réception ; vide tant qu'elle est en attente."
  timestamp_with_time_zone decide_le "Date de la décision ; vide tant que la réception est en attente."
  uuid cree_par FK "Utilisateur qui a enregistré la réception."
  timestamp_with_time_zone cree_le "Date d'enregistrement de la réception."
  timestamp_with_time_zone modifie_le "Date de la dernière modification (décision ou dérogation)."
}
"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.appareil" {
  uuid id "Identifiant de l'appareil (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."
  text code "Code court unique de l'appareil, utilisé dans les références provisoires (EC-009)."
  uuid utilisateur_id FK "Agent titulaire de l'appareil."
  text modele "Modèle du téléphone."
  boolean gnss_bifrequence "Vrai si le téléphone dispose d'un récepteur GNSS bifréquence (GPS-03, GPS-05)."
  text version_application "Dernière version de l'application terrain connue."
  text statut "Statut : actif, revoque ou remplace."
  timestamp_with_time_zone enrole_le "Date d'enrôlement."
  timestamp_with_time_zone revoque_le "Date de révocation. Nulle si l'appareil n'est pas révoqué."
  uuid revoque_par FK "Utilisateur qui a révoqué l'appareil."
  text motif_revocation "Motif de la révocation, obligatoire dès qu'elle a lieu."
  bigint derniere_sequence "Dernière séquence de commande traitée pour cet appareil. Ne diminue jamais."
  timestamp_with_time_zone derniere_synchro "Date de la dernière synchronisation."
  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."
}

Generated by tbls