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.
CodeDossier(texte ≤ 20) : identité stable d'une société. Relieidentite.dossier↔ annuaireTenants↔theia.Societe.CodeDossier↔pos.Store.Dossier.subKeycloak (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é.
+ 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;
| Base | Propriétaire | Persistance | Contenu |
|---|---|---|---|
identite | Identité | Dapper + DDL SQL idempotent | distributeurs, dossiers, users, droits, entitlements, clés PDP |
portail | Portail Client | EF Core (migrations) + control-plane (raw SQL) | clients, utilisateurs, GED, arbo, tuiles + annuaire shards/tenants |
theia (+ theia_shard2…) | Factures | EF Core + MigrateurLeger (additif) | facturation ventes/achats, référentiels, stock, PDP |
pos | POS | EF Core (migrations, schéma pos) | magasins, caisses, tickets NF525, clients enseigne |
catalogue | Catalogue | EF Core (EnsureCreated) | articles, déclinaisons, stock valorisé (multi-établissement) |
theia_tiers | Tiers | EF 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.
| Table | PK | Colonnes clés | Rôle |
|---|---|---|---|
distributeur | id (serial) | code (unique), nom, siren (unique partiel), actif | Cabinet / distributeur (porte les clés PDP) |
cle_pdp | id | distributeur_id (FK), client_id, client_secret (BYTEA chiffré AES-GCM), token_url, url_api, type_api | Identifiants OAuth PDP (1 active/distributeur) |
dossier | id (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_dossier | dossier_id (FK 1:1) | nom, prenom, email, telephone | Contact (pas un utilisateur) |
utilisateur | id (UUID = sub) | email (index lower), nom, prenom, actif | Miroir du compte Keycloak |
rattachement | id (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 |
entitlement | id | dossier_id (FK), application (THEIA/POS), statut — UNIQUE (dossier_id, application) | Activation produit par dossier |
admin_distributeur | (utilisateur_id, distributeur_id) | FKs | Périmètre admin distributeur |
audit_admin | id (bigserial) | acteur_id, action, cible_sub, code_dossier, details_json (JSONB) | Journal d'audit admin |
pdp_tenant_cache | (distributeur_id, siren) | organization_id, raison_sociale | Cache SIREN→org_id Serensia |
v_habilitations (vue) | — | sub, code_dossier, raison_sociale, est_chef, module, niveau, siren | Droits 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.
| Table | PK | Colonnes clés | Rôle |
|---|---|---|---|
Client | Id (int) | Nom, CodeInterne (= CodeDossier), Siren, SocieteTheiaId?, Actif | Espace client = racine du cloisonnement |
Utilisateur | Id (int) | ExternalId (sub, unique), ClientId (FK, null=transversal), Email (unique), Role (enum) | Compte portail |
Document | Id (int) | ClientId (FK), Sens, HashSha256, CheminStockage (clé S3), TypeDocument, DateDocument, ContenuTexte, RechercheTsv (tsvector GIN, fr_unaccent), StatutTransmission | GED (métadonnées ; binaire en objet S3) |
Dossier | Id (int) | ClientId (FK), ParentId (self FK), Nom | Arborescence de rangement |
ApplicationLien | Id (int) | Nom, Url, Icone, Ordre, VisiblePourClients | Tuiles lanceur d'apps |
Shards | Id (int) | Code (unique), ConnectionString, Actif | Base mutualisée hébergeant N tenants |
Tenants | Id (int) | CodeDossier (unique), Nom, ShardId? (FK), ConnectionString? (=silo dédié), Actif | Annuaire 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.
Ventes & référentiels
| Table | Colonnes clés | Relations |
|---|---|---|
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 |
Client | Cle (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 Nouveau | Nom, ParDefaut, CibleType?, VerrouFinalisation, Autofacturation, RegimeTva, TaxeParDefautId?, VatexParDefaut, RemiseParDefaut, CategorieOperationParDefaut?, AcomptePourcentageParDefaut, LignesPreremplies, mentions/textes, ConditionPaiementParDefautId? | profil de règles ; affecté au Client / à la Facture |
Article | Cle (Guid, sync Catalogue), Type, Nature, PrixVente/Achat, UniteVenteCode, stock (Suivi, Quantite, Valorisation, CMP) | N-1 Categorie ; N-N Taxe |
Taxe / GroupeTaxe | Categorie (Tva/Autre), ModeCalcul, Montant, CategorieTvaEn16931, AffecteBaseSuivantes | N-N Article & LigneFacture |
Compte / Journal / ConditionPaiement / PositionFiscale / MappingTaxe | plan comptable, séquences de numérotation, délais, substitution de taxe | référentiel comptable |
Facture | Type, Nature, Numero, Etat, dates, TotalHt/Taxes/Ttc, StatutPaiement, MontantPaye, StatutPdp, PdpFlowId, PdfSha256, ModeleFactureId?, Autofacturation (BT-3 389/261), liens devis/acompte/solde | N-1 Client/Journal ; 1-N LigneFacture |
LigneFacture | Libelle, TypeLigne (Standard/Commentaire/SousTotal), Quantite, PrixUnitaire, Remise, UniteCode, VatexCode, Optionnelle, montants | cascade avec Facture ; N-N Taxe ; N-1 Article? |
MouvementStock / CoucheStock | Type, Quantite signée, CoutUnitaire / couches FIFO-LIFO | N-1 Article |
Achats & logistique
| Table | Colonnes clés | Relations |
|---|---|---|
FactureAchat | InvoiceId (clé Effinum), Numero, fournisseur (CompanyId/Siren/Tva), montants, Statut (cycle de vie), EstDoublon, BonCommandeFournisseurId? | 1-N LigneAchat |
LigneAchat | LibelleProduit, Ean, Quantite, PrixUnitaire, MontantHt, TauxTva, StockEntree (idempotence) | N-1 FactureAchat ; N-1 Article? |
Fournisseur | CompanyId, Siren, Nom, stats (NbFactures, TotalTtc), enrichissement RNE | référencé par BC/BL |
BonCommandeFournisseur / LigneBonCommandeFournisseur | Numero, Statut, dates, QuantiteRecue/Restante | 1-N lignes (cascade) |
BonLivraison / LigneBonLivraison | Sens (Client/Fournisseur), Statut, piece-jointe (Sha256), liens BC/Facture | 1-N lignes (cascade) |
ConfigPdp / ServeurSmtp | OAuth 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.
| Table | Colonnes clés | Rôle |
|---|---|---|
Caisse | Nom, référence, active | Caisse déclarée de la société |
JourneeCaisse | CaisseId (FK), Date, totaux, Statut (ouverte/validée), snapshot de validation | Journée de recettes (brouillard) |
LigneRecette | JourneeCaisseId (FK cascade), libellé, montant | Détail des recettes du jour |
VentilationPaiement / VentilationTva | JourneeCaisseId (FK cascade), moyen de paiement / taux, montant | Ventilations par paiement & par TVA |
MouvementEspeces | JourneeCaisseId (FK cascade), sens, montant, motif | Entrées/sorties d'espèces |
ZReportManuel | date, totaux saisis, statut dépôt PDP | E-reporting saisi à la main (Z externe) |
ExportComptable / ParametrageComptable | période, écritures, verrou / comptes & journaux de rattachement | Export 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.
| Table | Colonnes clés | Rôle |
|---|---|---|
Store | Name, Profile, Code, Dossier (CodeDossier), NextLoyaltySeq | Magasin (clé de cloisonnement société) |
Register | StoreId (FK), Name, ApiKey (X-Api-Key), LastChainHash | Caisse (auth machine + ancre NF525) |
Seller | StoreId, Name, PinHash/PinSalt (PBKDF2) | Caissier |
Customer | Cle (Guid, sync Tiers), StoreId, LoyaltyCardNumber (unique), LoyaltyPoints, WalletBalance, UpdatedAt | Client enseigne (sync incrémentale) |
Ticket | RegisterId, Number (unique/caisse), Status, totaux, ChainHash / PreviousChainHash | Vente (chaînée NF525) |
TicketLine / Payment | Quantity (10,3), UnitPriceInclTax, VatRate / Method, Amount, ChangeGiven | lignes & règlements (cascade) |
CashSession | OpeningFloat, CountedCash, ExpectedCash, CashVariance, ZNumber | Ouverture → clôture Z |
CustomerOrder / CustomerOrderLine | DueAt, Deposit, Status | Commande / réservation client |
AssortimentArticle | ArticleCle (PK = Cle Catalogue), StoreId, IsFavorite, OrdreGrille | Overlay POS sur l'article Catalogue |
EmailOutbox / CustomerTombstone | ToAddress, HtmlBody, PdfAttachment, Status / Id supprimé, DeletedAt | Tickets 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.
| Table | PK | Colonnes clés |
|---|---|---|
CatalogueArticles | Cle (Guid) | SocieteCode, CategorieCle (FK), CodeBarres, Reference, prix HT, SuiviStock, Valorisation |
CatalogueCategories | Cle | SocieteCode, Valorisation (PMP/FIFO/LIFO) |
CatalogueEtablissements | Cle | SocieteCode (magasin/entrepôt) |
CatalogueTaxesArticle | Id | ArticleCle (FK cascade), CategorieTvaEn16931 |
CatalogueDeclinaisons | Cle | ArticleCle (FK), CodeBarres (taille/couleur) |
CatalogueStock | Id | UNIQUE (ArticleCle, DeclinaisonCle, EtablissementCle), Quantite, CoutMoyenPondere |
CatalogueMouvements / CatalogueCouches | Cle | journal 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.
| Table | PK | Colonnes clés |
|---|---|---|
Tiers | Cle (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é.
DbContext / entités (et du SchemaInitializer pour Identité) à chaque évolution de schéma.