Aller au contenu

Vue d'ensemble architecturale

Logmis est construit sur trois principes non-négociables qui contraignent l’ensemble du code :

  1. Architecture hexagonale stricte — le domaine n’importe aucun framework. NestJS, Drizzle, pg, NATS, Temporal, Redis sont confinés dans les couches infrastructure et composition. Le domaine ne dépend que de ports (interfaces).

  2. Result<T, DomainError> no-throw — aucune erreur métier ne lève d’exception. Chaque use-case retourne ok(value) ou fail(origin, code, message). Les switch discriminants utilisent assertNever pour l’exhaustivité.

  3. DB remplaçable — toute requête base de données transite par le port neutre Executor / Transactional<Executor>. Ni pg ni drizzle ne sont jamais importés dans modules/*/domain/ ou modules/*/application/. La fitness function lint:arch bloque même les import type de ces modules dans le domaine.

/data/PMS/
├── apps/
│ ├── api/ Backend NestJS 11 + Fastify
│ ├── admin/ Console control-plane (Angular 20, port 4301)
│ ├── tenant/ Cockpit property-manager (Angular 20, port 4302)
│ ├── reception/ Front-desk (Angular 20, port 4303)
│ ├── mobile-staff/ Personnel terrain (Capacitor 6, port 4300)
│ ├── tenant-mobile/ Gestionnaire nomade (Capacitor 6, port 4304)
│ └── docs/ Ce site (Astro + Starlight, port 4400)
├── packages/
│ ├── shared-kernel/ Primitives pures zéro-dépendance
│ ├── events-proto/ Schemas Protobuf + Envelope HMAC
│ ├── api-client/ Client typé OpenAPI (v1, 128 paths)
│ ├── api-client-admin/ Client typé API admin (9 paths)
│ ├── api-client-internal/ Client interne (généré, non consommé en V1)
│ └── ui/ Design system Osmose (@pms/ui 0.1.0)
├── docker-compose.dev.yml
├── pnpm-workspace.yaml
└── CLAUDE.md
apps/api/src/
├── modules/ 36 bounded contexts
│ └── <bc>/
│ ├── domain/ Agrégats, VOs, ports, use-cases (pur TS)
│ ├── application/ Use-cases (orchestrent le domaine)
│ └── infrastructure/ Repositories, adapters, migrations
├── interface/http/ Couche HTTP centralisée (controllers, guards, pipes)
│ ├── v1/ Endpoints /v1/** (141 opérations)
│ └── admin/ Endpoints /admin/** (9 opérations)
├── composition/ Seul lieu croisant plusieurs modules
│ ├── *.orchestrator.ts Golden paths cross-BC
│ ├── consumer-worker.ts 17 consumers NATS
│ └── saga/ Accès Temporal (interdit aux modules)
└── platform/ Infrastructure transversale
├── persistence/ Pool, Executor, withTenantTransaction
├── config/ Validation Zod des env vars
├── crypto/ SecretStorePort KMS-agnostique
├── temporal/ 6 workflows
└── messaging/ NATS JetStream
domain/ ←── application/ ←── infrastructure/
composition/
interface/http/

composition/ est le seul endroit qui peut importer plusieurs modules simultanément. Un module A ne doit jamais importer de module B directement — toujours passer par composition/.

Chaque règle est vérifiée à chaque CI sur push et PR :

CommandeRègle vérifiée
lint:archHexagonal strict + no-cross-BC + C1 (dependency-cruiser, tsPreCompilationDeps:true — bloque aussi les import type)
lint:jsonbZéro JSONB en base (ADR-0014) — attributs en EAV typé relationnel
lint:rlsAnti current_setting(...,true) fail-open (ADR-D08)
lint:payment-pciZéro donnée carte (PAN/CVV/CVC/track/card_number) — PCI SAQ A
lint:orgZéro ltree direct
lint:auditPiste d’audit inaltérable — zéro UPDATE/DELETE sur les tables append-only (T13)
lint:distributionDéfinition unique de la disponibilité stock (INV-6b-2)
lint:pos-bridgeIsolation ACL OsmoVente (ADR-D23)
lint:openapiNon-régression contrat OpenAPI (oasdiff)
lint:fiscal-accountsZéro numéro de compte comptable 4xx/7xx en dur dans le domaine

5 jobs en parallèle avec concurrency cancel-in-progress :

  1. security — gitleaks + pnpm audit --audit-level=high
  2. lint-unit — build packages → typecheck -r → 10 fitness → buf lint → oasdiff → unit tests → coverage unit
  3. integration — services réels (Postgres 17, Redis, NATS, Temporal) → migrations → tests d’intégration
  4. coverage-gate — merge unit+int → seuil ≥ 90 % sur money/fiscal/audit
  5. e2e-fronts — matrice 5 apps Angular → Playwright + axe-core (violations critical/serious bloquantes)
  • Imports relatifs en .js (NodeNext resolution) — import './foo.js' même si le fichier source est foo.ts
  • import type obligatoire partout (verbatimModuleSyntax)
  • reflect-metadata importé en premier dans main.ts (DI NestJS)
  • Build les packages avant les apps : pnpm -r run build respecte l’ordre topologique

Primitives pures, zéro dépendance framework, partagées domaine + fronts :

  • Money — bigint centimes, devise-safe, opérations add/sub/mul (entier uniquement), half-up basis-points
  • Result<T, E>ok(value) / fail(origin, code, message)
  • IDs brandés — TenantId, ReservationId, FolioId… (nominal typing, pas de confusion accidentelle)
  • BusinessDate — date métier distincte du temps système
  • OrgPath — chemin d’organisation (comparaison par préfixe pour le RBAC)
  • MoneyRatioapplyBasisPoints/applyBasisPointsCeil/decomposeFromTtc
  • CancellationPolicy — snapshot inaltérable à la confirmation
  • MandateEstablishmentReader — port pour lire le mandat/établissement