Architecture de données — OLTP, plateforme analytique, isolation
Vous êtes ici : Comprendre — les fondations : où vivent les données de la suite. Comment GS-Apps range, isole et alimente ses données. Lecture 12 min. Audience : devs, data engineers, auditeurs. Date : 2026-10-09 | Version : 1.4 — trajectoire unique ADR-094 (une base
GS_Apps, déclencheur charge 80 % / 30 min) ; RLS et médaillon inchangés depuis 1.3
| Question | Réponse | Source de vérité |
|---|---|---|
| Où vivent les données des apps ? | Un schéma par domaine métier : ug, adm, bil, inv, fbk, ntf, ptl, audit, … (liste ouverte) |
Base GS_Apps (OLTP) |
| Où vit l’analytique ? | Médaillon sur la même base : bronze (stg_<source>) → dim → (fact direct ou silver) → gold (ordre DAG, ADR-094 règle 5) |
Base GS_Apps |
| D’où viennent les données analytiques ? | De SOFI aujourd’hui ; puis d’autres sources (Proful, Geotab, Monday, …) — chacune atterrit dans son schéma bronze stg_<source> |
Sources externes, lecture seule |
| Les apps utilisent-elles ces données ? | Oui — les dimensions conformes (employés, succursales…) servent de données de référence aux apps, en plus de nourrir la BI | dim.* |
| Quand la base change-t-elle ? | Un seul déclencheur : charge GS_Apps ≥ 80 % en moyenne sur 30 minutes (alerte alert-gs-apps-charge-de-la-base). Puis question fermée à l’exploitant — pas de scission automatique |
ADR-094 |
| Comment une compagnie est-elle isolée ? | RLS (Row-Level Security) sur les tables tenant — ug.* et les couches silver/gold/dim/fact — prédicat sur company_id |
Politique RLS en base |
| Comment une app se connecte ? | Convention unique AZURE_SQL_*, un seul pool |
@gs/config + test de contrat |
Vue d’ensemble — la carte des données
Section intitulée « Vue d’ensemble — la carte des données »La bonne image n’est pas « deux murs séparés », mais un flux. Des sources (SOFI aujourd’hui) alimentent une plateforme de données en médaillon, qui sert deux consommateurs : les apps (transactionnel) et la BI (analytique). Les apps tournent autour d’un cœur partagé — le schéma ug (identités, compagnies) que les autres référencent — et réutilisent les données de référence (employés, succursales…) que la plateforme tire des sources.
1. Domaine transactionnel (OLTP) — un schéma par contexte
Section intitulée « 1. Domaine transactionnel (OLTP) — un schéma par contexte »Chaque domaine métier vit dans son propre schéma, nommé sur 3 lettres minuscules — et la liste est ouverte (ug, adm, bil, inv, fbk, ntf, ptl, audit, … d’autres domaines viendront). Pas de tables métier dans dbo.
Mais tous les domaines ne sont pas au même niveau. ug est le cœur partagé : il détient les identités, les compagnies et les rôles que les autres schémas référencent — une facture bil pointe une compagnie ug, un mouvement de stock inv pointe un utilisateur ug. On lit chez le voisin par clé/jointure explicite, jamais par copie sauvage : un schéma possède sa donnée, les autres la référencent. C’est ce qui empêche la « soupe de tables ».
| Schéma | Domaine | Tables clés |
|---|---|---|
ug |
Accès (identités, rôles, délégation — Système C) | Users, Companies, UserCompanyBcRoles, UserCompanyAccess, RoleTemplates, CompanyBranding(Assets) |
adm |
Administration / ETL (registre d’apps, orchestration des syncs) | Apps, Sources, SyncConfigs, SyncLogs, Watermarks, SyncLocks, EtlControl |
bil |
Facturation | Clients, Contracts, ContractCodes, BillingPeriods, ExportHistory |
inv |
Inventaire | Items, PurchaseOrders(+Lines), Receptions, StockMovements, Suppliers, WeeklyReports |
fbk |
Feedback (tickets internes) | Tickets, Messages, Activity, StatusHistory, Attachments |
ntf |
Notifications | Notifications, NotificationReads |
ptl |
Palettes (étiquettes / traçabilité) | Stickers, StickerBatches, StickerSequence |
audit |
Journal d’accès PII (cible du pool audit) | PiiAccessLog |
2. Plateforme analytique — médaillon
Section intitulée « 2. Plateforme analytique — médaillon »L’analytique suit le patron médaillon (standard data-platform) : des couches de raffinage successives. Chaque source atterrit d’abord telle quelle, puis est nettoyée, puis modélisée. Aujourd’hui la source est SOFI (on-prem, lue en seule lecture via VNet — jamais d’écriture vers SOFI) ; demain d’autres s’ajouteront — Proful, Geotab, Monday, … — toutes par le même patron d’entrée : la couche bronze, incarnée par un schéma stg_<source> par source (stg_sofi aujourd’hui ; stg_geotab, stg_profuel, stg_jpl, stg_saaq, stg_locations déjà réservés). Un schéma par source évite toute collision de noms de tables entre sources — deux sources peuvent avoir une table du même nom sans se marcher dessus.
Le résultat ne part pas que vers la BI. La couche servie a deux consommateurs : la BI lit les agrégats (gold) et les faits (fact) ; les apps réutilisent les dimensions conformes (dim : employés, succursales, véhicules…) comme données de référence — par exemple la liste d’employés à la connexion, ou les succursales dans l’inventaire.
adm.| Couche | Schéma | Rôle | Exemple |
|---|---|---|---|
| Bronze | stg_<source> — un par source |
Copie fidèle de la source, sans transformation (rejouable) | stg_sofi.PunchParJour ; stg_geotab, stg_profuel… (réservés) |
| Silver | silver |
Nettoyé, typé, conformé, dédupliqué | silver.maintenance_orders, silver.security_rounds |
| Gold | gold |
Agrégats prêts pour la décision | gold.maintenance_cost_per_vehicle_month |
| Dimensions / faits | dim / fact |
Modèle dimensionnel (étoile) — réutilisé par la BI et les apps | dim.vehicles, dim.branches ; fact.invoices, fact.plans |
gold vs dim/fact — pourquoi les deux ? dim/fact est le socle réutilisable au grain fin : les dimensions (dim) sont les objets — employés, succursales, véhicules, calendrier ; les faits (fact) sont les événements mesurables — factures, plans, punches. C’est cette couche que les apps réutilisent comme référence. gold, lui, ce sont les réponses pré-calculées construites par-dessus dim/fact — agrégats et KPI taillés pour un tableau de bord précis (ex. coût d’entretien par véhicule par mois), destinés à la BI. En une phrase : dim/fact est le socle commun ; gold est ce qu’on en tire pour décider.
3. Isolation tenant — RLS
Section intitulée « 3. Isolation tenant — RLS »Le multi-tenant se défend en profondeur : au-delà du filtrage applicatif (company_id injecté par middleware), les tables tenant portent une politique RLS (Row-Level Security) dont le prédicat sur company_id borne chaque requête à la compagnie courante — fail-closed (aucun contexte → aucune ligne). Même une requête fautive reste confinée.
Le périmètre déployé et actif couvre les deux familles (ADR-056 D6) : les tables tenant OLTP (ug.Users, ug.CompanyBranding, ug.UserCompanyBcRoles, ug.CompanyModules, ug.RoleGrantsLog — politique ug.CompanyFilter, migrations 113/134/140) et les couches analytiques tenant-scopées silver / gold / dim / fact. Le mécanisme est unique : une seule TVF dbo.fn_company_predicate (jamais de prédicat dédié par table), une politique CompanyFilter par schéma — en FILTER (lecture) et BLOCK (insert/update) — et un bypass contrôlé pour le service ETL. Trois tables ug sont exclues par design : ug.Companies (registre global des compagnies), ug.UserCompanyAccess (anti-récursion — le prédicat la lit pour résoudre les accès) et ug.CompanyBrandingAssets. La couche bronze (stg_*) n’est pas couverte : c’est un miroir pré-tenant des sources, accessible au seul service ETL.
4. Connexion & configuration
Section intitulée « 4. Connexion & configuration »Une seule famille de variables : AZURE_SQL_SERVER / AZURE_SQL_DATABASE / AZURE_SQL_USER / AZURE_SQL_PASSWORD / AZURE_SQL_PORT, validée par un schéma Zod central (@gs/config). Aucun nom mort SQL_*. La source SOFI a sa propre famille SOFI_SQL_* (système distinct, ne pas mélanger).
Une base GS_Apps (Standard S1, aucun pool élastique — ADR-094). Les helpers anlQuery, queryWarehouse, queryAudit et les variables AZURE_SQL_ANL_* / OPS_* / WAREHOUSE_* / AUDIT_* sont des coutures vers la même base ou une connexion optionnelle — pas un plan de scission.
En production, l’authentification SQL passe par Managed Identity quand SQL_USE_MANAGED_IDENTITY=true (user/mot de passe alors optionnels). Pas de secret SQL étalé dans les App Settings.
Pourquoi ces choix
Section intitulée « Pourquoi ces choix »| Décision | Pourquoi (le standard) |
|---|---|
Un schéma par domaine (pas de dbo métier) |
Bounded contexts explicites ; permissions, sauvegardes et évolutions cadrées par domaine. |
| OLTP et OLAP sur une base (séparation par schéma) | L’analytique lourde et l’ETL partagent GS_Apps avec le transactionnel ; les domaines sont isolés par schéma et RLS. Si la charge devient un problème mesuré, ADR-094 impose remesure puis décision humaine — jamais une migration automatique. |
Médaillon bronze/silver/gold |
Standard Databricks/Lakehouse : raffinage par couches, rejouable, lignée claire. Une convention, pas trois. |
| RLS tenant-scopée, fail-closed | Défense en profondeur multi-tenant : la base borne, même si une requête applicative se trompe. |
Source unique de config (AZURE_SQL_*) + test de contrat |
Évite la dérive de nommage infra/code ; un seul vocabulaire, audité automatiquement. |
SOFI en lecture seule, isolé (SOFI_SQL_*) |
La source opérationnelle n’est jamais polluée par l’analytique ; frontière nette. |
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Modèle d’accès — identités, rôles, délégation
- Compute & exécution — où s’exécutent les traitements (la sœur de cette page).
- ADR-039 — Architecture de données 2026
- ADR-056 — Architecture médaillon
- ADR-025 — Bounded contexts (monolithes)
- ADR-058 — Harness de validation RLS
- ADR-060 — Permissions BD as code
- ADR-033 — Managed Identity SQL
- ADR-036 — Stratégie BD 2026 (pools, phases)
- ADR-094 — Une seule trajectoire de base
- ADR-019 — Infrastructure BD (SUPERSEDED par ADR-094)
- ADR-065 — Module IaC unique gs-app (contrat config)
- ADR-057 — Storage Managed Identity
- ADR-061 — Stratégie d’accès unifiée 2026