lightweight-sdk/spec/architecture.md
Nicolas 10bc209038
Some checks failed
CI / build-lint-test (pull_request) Failing after 29s
Ajouter @lightweight-sdk/service-registry (packages/common)
Registre de services en singleton avec injection par decorateurs :
- ServiceRepository : singleton central, uid genere automatiquement
  (crypto.randomUUID) a l'enregistrement, une seule instance partagee
  par service.
- @RegisterService() : decorateur de classe, instancie et enregistre
  automatiquement la classe decoree (constructeur sans argument).
- @Service(target) : decorateur de propriete, injection paresseuse et
  memoisee par reference de classe (resolution au premier acces, pas
  a la decoration - insensible a l'ordre d'evaluation des modules).

Fix connexe dans tsconfig.base.json : useDefineForClassFields desactive
(target ES2022 l'active par defaut), sinon un champ de classe sans
initialiseur est reinitialise a undefined sur l'instance a la
construction et masque l'accesseur pose sur le prototype par un
decorateur de propriete - touche @Service ici et @LinkToDom dans
web-component. Documente dans spec/architecture.md.

Fix connexe dans scripts/create-package.mjs : execFileSync('pnpm', ...)
ne resout pas le shim .cmd de pnpm sous Windows sans shell: true
(trouve en re-testant le script sur ce package).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 13:59:58 +02:00

43 lines
4 KiB
Markdown

# Architecture
## Objectif
`lightweight-sdk` est un monorepo pnpm destiné à héberger, au fil du temps, des packages TypeScript réutilisables développés par l'auteur pour ses projets personnels. Chaque package est publié indépendamment sur le registre npm privé hébergé sur l'instance Forgejo personnelle (`git.dev.kyuno.fr`), sous le scope `@lightweight-sdk`.
## Organisation des packages
Les packages sont répartis en trois catégories sous `packages/`, qui reflètent la distinction Frontend/Backend du [CLAUDE.md](../CLAUDE.md) du projet :
- **`client/`** — packages destinés au navigateur (DOM, composants UI). Peuvent dépendre de `lib: DOM` dans leur `tsconfig.json`.
- **`common/`** — code isomorphe partagé entre `client` et `server` (types, utilitaires purs, constantes). Convention : ne doit dépendre d'aucune API exclusivement DOM ou exclusivement Node, pour rester portable des deux côtés.
- **`server/`** — packages Node/backend. Chaque package doit être structuré comme un service modulaire autonome exposant sa propre API (règle "Architecture Backend" du CLAUDE.md).
Le nom npm d'un package ne reprend pas le préfixe de catégorie (`@lightweight-sdk/web-component`, pas `@lightweight-sdk/client-web-component`) — la catégorie est une convention d'organisation du dépôt, pas une convention de nommage public.
Un nouveau package se crée avec `pnpm create-package <client|common|server> <nom>` (voir `scripts/create-package.mjs`).
## Choix d'outillage
| Aspect | Choix | Pourquoi |
|---|---|---|
| Gestionnaire de packages | pnpm workspaces + `catalog:` | Centralise les versions des devDependencies partagées dans `pnpm-workspace.yaml` |
| Orchestrateur de build | Aucun (pas de Turborepo/Nx) | Un seul package réel au démarrage ; à reconsidérer si le temps de build devient un problème |
| Build | `tsc -b` (project references), pas de bundler | Les packages sont consommés via pnpm par d'autres projets Node/TS de l'auteur ; pas besoin de bundle |
| Modules | **CommonJS**, résolution `Node10` | Décision explicite : pas d'extension `.js` requise dans les imports relatifs, et le code migré depuis l'ancien repo `web-component` compile sans modification |
| Lint + format | [Biome.js](https://biomejs.dev/) | Imposé par le CLAUDE.md du projet |
| Documentation de code | [TypeDoc](https://typedoc.org/) en mode validation | Génère la doc API et fait échouer la CI si un export n'a pas de TSDoc (voir `conventions.md`) |
| Tests | [Vitest](https://vitest.dev/) | ESM natif, bon support monorepo |
| Versioning/publish | [Changesets](https://github.com/changesets/changesets) | Gère des versions indépendantes par package + changelogs, comprend nativement `workspace:*` |
| Node cible | 24 (Active LTS) en CI, `engines: ">=22"` | Node 20 est end-of-life depuis avril 2026 |
## Décorateurs et `useDefineForClassFields`
`tsconfig.base.json` force `"useDefineForClassFields": false`, bien que la cible soit `ES2022` (où ce flag vaut `true` par défaut). Sans ça, un champ de classe déclaré sans initialiseur (`logger!: LoggerService;`) est réinitialisé à `undefined` **sur l'instance** au moment de la construction, ce qui masque silencieusement tout accesseur posé sur le prototype par un décorateur de propriété (`@Service` de `@lightweight-sdk/service-registry`, `@LinkToDom` de `web-component`). C'est une interaction connue entre `useDefineForClassFields` et les décorateurs legacy (`experimentalDecorators`) — désactiver ce flag restaure la sémantique classique où un champ sans initialiseur n'émet aucun code, laissant l'accesseur du prototype pleinement fonctionner.
## Dépendances entre packages
Les dépendances internes entre packages du monorepo utilisent le protocole `workspace:*` (résolu localement par pnpm, jamais via le registre distant). Le registre npm privé n'est utilisé que pour la publication et pour la consommation depuis des projets *externes* à ce monorepo.
## Registre npm privé
`https://git.dev.kyuno.fr/api/packages/kyuno/npm/` — voir `ci-cd.md` pour le détail de la publication et de l'authentification.