Technique · Base de donnéesPostgreSQL · EF Core / Dapper

Structure base de données

Un schéma par contexte métier (une base PostgreSQL par application), reliés par des clés partagées stables.

Clés de liaison inter-bases (à connaître).
  • CodeDossier (texte ≤ 20) : identité stable d'une société. Relie identite.dossier ↔ annuaire Tenants ↔ theia.Societe.CodeDossier ↔ pos.Store.Dossier.
  • sub Keycloak (UUID) : identité stable d'un utilisateur. = identite.utilisateur.id = *.Utilisateur.ExternalId.
  • Cle (Guid) : identité partagée d'un article (⇄ module Catalogue) et d'un client/tiers (⇄ module Tiers).
  • SocieteCode : cloisonnement des modules partagés (Catalogue, Tiers) = le CodeDossier, transporté par un jeton signé.
graph TD ID[("identite")]:::db POR[("portail
+ control-plane")]:::db TH[("theia
(+ shards)")]:::db PO[("pos")]:::db CA[("catalogue")]:::db TI[("theia_tiers")]:::db RNE[("rne (lecture)")]:::db ID -- "CodeDossier / sub" --> POR POR -- "annuaire Tenants" --> TH POR -- "annuaire Tenants" --> PO TH -- "Cle article" --> CA PO -- "Cle article" --> CA TH -- "Cle tiers" --> TI PO -- "Cle tiers" --> TI TH -- "enrichissement" --> RNE classDef db fill:#eef2ff,stroke:#4f46e5,stroke-width:1px;
BasePropriétairePersistanceContenu
identiteIdentitéDapper + DDL SQL idempotentdistributeurs, dossiers, users, droits, entitlements, clés PDP
portailPortail ClientEF Core (migrations) + control-plane (raw SQL)clients, utilisateurs, GED, arbo, tuiles + annuaire shards/tenants
theia (+ theia_shard2…)FacturesEF Core + MigrateurLeger (additif)facturation ventes/achats, référentiels, stock, PDP
posPOSEF Core (migrations, schéma pos)magasins, caisses, tickets NF525, clients enseigne
catalogueCatalogueEF Core (EnsureCreated)articles, déclinaisons, stock valorisé (multi-établissement)
theia_tiersTiersEF Core (EnsureCreated)tiers/clients partagés (table unique, dédup)
rne—PostgreSQL (lecture)registre INPI (enrichissement fournisseurs/tiers)

Base identite

Autorisation fine (Keycloak ne porte que l'authentification + rôles grossiers). Schéma créé au démarrage (SchemaInitializer.cs), accès Dapper.

erDiagram distributeur ||--o{ dossier : "possède" distributeur ||--o{ cle_pdp : "1 active max" distributeur }o--o{ utilisateur : "admin_distributeur" dossier ||--o| contact_dossier : "1:1" dossier ||--o{ entitlement : "app (THEIA/POS)" dossier ||--o{ rattachement : "" utilisateur ||--o{ rattachement : "membre de" rattachement ||--o{ habilitation : "droit par module"
TablePKColonnes clésRôle
distributeurid (serial)code (unique), nom, siren (unique partiel), actifCabinet / distributeur (porte les clés PDP)
cle_pdpiddistributeur_id (FK), client_id, client_secret (BYTEA chiffré AES-GCM), token_url, url_api, type_apiIdentifiants OAuth PDP (1 active/distributeur)
dossierid (bigint)code_dossier, distributeur_id (FK), siren, raison_sociale, organization_id_pdp, eas, endpoint — UNIQUE (distributeur_id, code_dossier)Société membre = 1 tenant THEIA
contact_dossierdossier_id (FK 1:1)nom, prenom, email, telephoneContact (pas un utilisateur)
utilisateurid (UUID = sub)email (index lower), nom, prenom, actifMiroir du compte Keycloak
rattachementid (serial)utilisateur_id (FK), dossier_id (FK), est_chef — UNIQUE (utilisateur_id, dossier_id)Appartenance user ↔ dossier
habilitation(rattachement_id, module)module (enum), niveau (enum)Matrice droits : module × niveau
entitlementiddossier_id (FK), application (THEIA/POS), statut — UNIQUE (dossier_id, application)Activation produit par dossier
admin_distributeur(utilisateur_id, distributeur_id)FKsPérimètre admin distributeur
audit_adminid (bigserial)acteur_id, action, cible_sub, code_dossier, details_json (JSONB)Journal d'audit admin
pdp_tenant_cache(distributeur_id, siren)organization_id, raison_socialeCache SIREN→org_id Serensia
v_habilitations (vue)—sub, code_dossier, raison_sociale, est_chef, module, niveau, sirenDroits aplatis (lecture)

Enums : module_fonctionnel = FactureAchat / FactureVente / Reglement · niveau_droit = Aucun / Lecture / Modification · type_api_pdp = Afnor / Proprietaire.

Base portail (+ control-plane)

EF Core (PortailDbContext). Deux entités (Document, Dossier) portent un filtre global par ClientId. La base héberge aussi l'annuaire multi-tenant (ControlDbContext) dont le Portail est propriétaire.

erDiagram Client ||--o{ Utilisateur : "" Client ||--o{ Document : "GED (filtre ClientId)" Client ||--o{ Dossier : "arborescence" Dossier ||--o{ Dossier : "parent/enfants" Dossier ||--o{ Document : "rangement" Shard ||--o{ Tenant : "héberge"
TablePKColonnes clésRôle
ClientId (int)Nom, CodeInterne (= CodeDossier), Siren, SocieteTheiaId?, ActifEspace client = racine du cloisonnement
UtilisateurId (int)ExternalId (sub, unique), ClientId (FK, null=transversal), Email (unique), Role (enum)Compte portail
DocumentId (int)ClientId (FK), Sens, HashSha256, CheminStockage (clé S3), TypeDocument, DateDocument, ContenuTexte, RechercheTsv (tsvector GIN, fr_unaccent), StatutTransmissionGED (métadonnées ; binaire en objet S3)
DossierId (int)ClientId (FK), ParentId (self FK), NomArborescence de rangement
ApplicationLienId (int)Nom, Url, Icone, Ordre, VisiblePourClientsTuiles lanceur d'apps
ShardsId (int)Code (unique), ConnectionString, ActifBase mutualisée hébergeant N tenants
TenantsId (int)CodeDossier (unique), Nom, ShardId? (FK), ConnectionString? (=silo dédié), ActifAnnuaire CodeDossier → base

Enums : RolePortail (Client / AgentCabinet / Admin) · SensDocument (Descendant / Ascendant) · ServiceCible (Comptabilite / Paye / Conseil / Juridique) · StatutTransmission (NonRequis / EnAttente / Transmis / Erreur).

Base theia (facturation)

La plus riche. EF Core (TheiaDbContext) + MigrateurLeger (additif). Cloisonnement société : toute entité IEntiteSociete (SocieteId) subit un filtre global SocieteCouranteId == null || e.SocieteId == SocieteCouranteId. Décimaux en numeric(18,4).

Entités globales (sans SocieteId) : UniteMesure, MotifExonerationTva, Utilisateur, UtilisateurSociete, PdpWorkerLease.

erDiagram Societe ||--o{ Client : "" Societe ||--o{ Article : "" Client ||--o{ Facture : "" Journal ||--o{ Facture : "" Facture ||--o{ LigneFacture : "cascade" Article ||--o{ LigneFacture : "" Article }o--o{ Taxe : "ArticleTaxes" LigneFacture }o--o{ Taxe : "LigneFactureTaxes" FactureAchat ||--o{ LigneAchat : "cascade" Fournisseur ||--o{ FactureAchat : "" BonCommandeFournisseur ||--o{ FactureAchat : "3-way match"

Ventes & référentiels

TableColonnes clésRelations
Societe (le tenant)Nom, CodeDossier, Siren/Siret/NumeroTva, Iban/Bic, numérotation, config relances, RneSnapshot, personnalisation (logo/couleurs/polices, CouleurFondPage, FiligraneTexte/Opacite, disposition)racine ; référencée partout
ClientCle (Guid, sync Tiers), Nom, Type (Particulier/Entreprise/Administration/Association), Civilite, Prenom, Siret, FormatEFacture, Peppol Eas/Endpoint, Iban/Bic, ModeleFactureParDefautId?N-1 Societe ; 1-N Facture ; N-1 ModeleFacture?
ModeleFacture NouveauNom, ParDefaut, CibleType?, VerrouFinalisation, Autofacturation, RegimeTva, TaxeParDefautId?, VatexParDefaut, RemiseParDefaut, CategorieOperationParDefaut?, AcomptePourcentageParDefaut, LignesPreremplies, mentions/textes, ConditionPaiementParDefautId?profil de règles ; affecté au Client / à la Facture
ArticleCle (Guid, sync Catalogue), Type, Nature, PrixVente/Achat, UniteVenteCode, stock (Suivi, Quantite, Valorisation, CMP)N-1 Categorie ; N-N Taxe
Taxe / GroupeTaxeCategorie (Tva/Autre), ModeCalcul, Montant, CategorieTvaEn16931, AffecteBaseSuivantesN-N Article & LigneFacture
Compte / Journal / ConditionPaiement / PositionFiscale / MappingTaxeplan comptable, séquences de numérotation, délais, substitution de taxeréférentiel comptable
FactureType, Nature, Numero, Etat, dates, TotalHt/Taxes/Ttc, StatutPaiement, MontantPaye, StatutPdp, PdpFlowId, PdfSha256, ModeleFactureId?, Autofacturation (BT-3 389/261), liens devis/acompte/soldeN-1 Client/Journal ; 1-N LigneFacture
LigneFactureLibelle, TypeLigne (Standard/Commentaire/SousTotal), Quantite, PrixUnitaire, Remise, UniteCode, VatexCode, Optionnelle, montantscascade avec Facture ; N-N Taxe ; N-1 Article?
MouvementStock / CoucheStockType, Quantite signée, CoutUnitaire / couches FIFO-LIFON-1 Article

Achats & logistique

TableColonnes clésRelations
FactureAchatInvoiceId (clé Effinum), Numero, fournisseur (CompanyId/Siren/Tva), montants, Statut (cycle de vie), EstDoublon, BonCommandeFournisseurId?1-N LigneAchat
LigneAchatLibelleProduit, Ean, Quantite, PrixUnitaire, MontantHt, TauxTva, StockEntree (idempotence)N-1 FactureAchat ; N-1 Article?
FournisseurCompanyId, Siren, Nom, stats (NbFactures, TotalTtc), enrichissement RNEréférencé par BC/BL
BonCommandeFournisseur / LigneBonCommandeFournisseurNumero, Statut, dates, QuantiteRecue/Restante1-N lignes (cascade)
BonLivraison / LigneBonLivraisonSens (Client/Fournisseur), Statut, piece-jointe (Sha256), liens BC/Facture1-N lignes (cascade)
ConfigPdp / ServeurSmtpOAuth PDP (TokenUrl, ClientId, OrganizationId, Eas), DepotAutomatique, polling / SMTP sociétépar société

Enums notables : TypeDocument (FactureVente/AvoirVente/FactureAchat/AvoirAchat/Devis), TypeClient (Particulier/Entreprise/Administration/Association), RegimeTvaModele (Normal/Autoliquidation/FranchiseTva/Intracommunautaire/Export/Exonere), TypeLigne (Standard/Commentaire/SousTotal), EtatFacture (Brouillon/Comptabilisee/Annulee), StatutPdp (NonDepose/Depose/Acquitte/Rejete/Echec), StatutCycleVieFacture (aligné API Effinum), FormatEFacture (FacturX/UBL…), MethodeValorisation (Pmp/Fifo/Lifo), CategorieTaxe (Tva/Autre). (≈35 enums au total — voir Theia.Core\Domaine\Enums.cs.)

E-reporting — brouillard de caisse Nouveau

Nouvelles entités IEntiteSociete (mêmes filtre société & migrateur additif) pour le livre de caisse et l'e-reporting PDP.

erDiagram Caisse ||--o{ JourneeCaisse : "" JourneeCaisse ||--o{ LigneRecette : "cascade" JourneeCaisse ||--o{ VentilationPaiement : "cascade" JourneeCaisse ||--o{ VentilationTva : "cascade" JourneeCaisse ||--o{ MouvementEspeces : "cascade"
TableColonnes clésRôle
CaisseNom, référence, activeCaisse déclarée de la société
JourneeCaisseCaisseId (FK), Date, totaux, Statut (ouverte/validée), snapshot de validationJournée de recettes (brouillard)
LigneRecetteJourneeCaisseId (FK cascade), libellé, montantDétail des recettes du jour
VentilationPaiement / VentilationTvaJourneeCaisseId (FK cascade), moyen de paiement / taux, montantVentilations par paiement & par TVA
MouvementEspecesJourneeCaisseId (FK cascade), sens, montant, motifEntrées/sorties d'espèces
ZReportManueldate, totaux saisis, statut dépôt PDPE-reporting saisi à la main (Z externe)
ExportComptable / ParametrageComptablepériode, écritures, verrou / comptes & journaux de rattachementExport comptable (verrouillé) & paramétrage

Base pos

EF Core (PosDbContext, schéma pos, migrations versionnées). Cloisonnement par Store.Dossier (= CodeDossier) + routing multi-base par shard. Tickets chaînés NF525.

erDiagram Store ||--o{ Register : "" Store ||--o{ Seller : "" Store ||--o{ Customer : "" Register ||--o{ Ticket : "" Ticket ||--o{ TicketLine : "cascade" Ticket ||--o{ Payment : "cascade" Register ||--o{ CashSession : "" Store ||--o{ CustomerOrder : "" CustomerOrder ||--o{ CustomerOrderLine : "cascade"
TableColonnes clésRôle
StoreName, Profile, Code, Dossier (CodeDossier), NextLoyaltySeqMagasin (clé de cloisonnement société)
RegisterStoreId (FK), Name, ApiKey (X-Api-Key), LastChainHashCaisse (auth machine + ancre NF525)
SellerStoreId, Name, PinHash/PinSalt (PBKDF2)Caissier
CustomerCle (Guid, sync Tiers), StoreId, LoyaltyCardNumber (unique), LoyaltyPoints, WalletBalance, UpdatedAtClient enseigne (sync incrémentale)
TicketRegisterId, Number (unique/caisse), Status, totaux, ChainHash / PreviousChainHashVente (chaînée NF525)
TicketLine / PaymentQuantity (10,3), UnitPriceInclTax, VatRate / Method, Amount, ChangeGivenlignes & règlements (cascade)
CashSessionOpeningFloat, CountedCash, ExpectedCash, CashVariance, ZNumberOuverture → clôture Z
CustomerOrder / CustomerOrderLineDueAt, Deposit, StatusCommande / réservation client
AssortimentArticleArticleCle (PK = Cle Catalogue), StoreId, IsFavorite, OrdreGrilleOverlay POS sur l'article Catalogue
EmailOutbox / CustomerTombstoneToAddress, HtmlBody, PdfAttachment, Status / Id supprimé, DeletedAtTickets dématérialisés (AGEC) / propagation des suppressions

Enums : PaymentMethod (Card/Cash/Check/MealVoucher/GiftCard/Credit/Transfer/Loyalty), TicketStatus (Completed/Cancelled), SaleUnit (Piece/Weight), OrderStatus, EmailStatus. Les données « article » de base (nom/prix/TVA/stock/variantes) vivent dans le module Catalogue, pas ici.

Base catalogue

Module central articles/stock. Cloisonné par SocieteCode ; stock toujours clé par (article, déclinaison?, établissement) → stock par magasin et par variante.

TablePKColonnes clés
CatalogueArticlesCle (Guid)SocieteCode, CategorieCle (FK), CodeBarres, Reference, prix HT, SuiviStock, Valorisation
CatalogueCategoriesCleSocieteCode, Valorisation (PMP/FIFO/LIFO)
CatalogueEtablissementsCleSocieteCode (magasin/entrepôt)
CatalogueTaxesArticleIdArticleCle (FK cascade), CategorieTvaEn16931
CatalogueDeclinaisonsCleArticleCle (FK), CodeBarres (taille/couleur)
CatalogueStockIdUNIQUE (ArticleCle, DeclinaisonCle, EtablissementCle), Quantite, CoutMoyenPondere
CatalogueMouvements / CatalogueCouchesClejournal entrées/sorties / couches de coût FIFO-LIFO

Base theia_tiers

Module central clients (tiers). Table unique, source de vérité, synchro write-through THEIA ⇄ POS.

TablePKColonnes clés
TiersCle (Guid)UNIQUE (SocieteCode, CleDedup), Type, Nom, Siren/Siret/NumeroTva, contact, adresse, Eas/EndpointElectronique (e-facture), RneSnapshot, Actif, MajLe

CleDedup = clé de dédoublonnage déterministe (SIREN > email > tél > nom+CP ; null = anonyme, jamais dédupliqué). Chaque app consommatrice garde ses attributs métier propres (fidélité, conditions de paiement) hors de ce contrat partagé.

Document vivant. Ce modèle reflète l'état au 27/09/2026 ; les applications vont évoluer. Régénérer cette page à partir des DbContext / entités (et du SchemaInitializer pour Identité) à chaque évolution de schéma.
IIQARION — Structure base de données · 27/09/2026.