Ce document complete le README.md. Son but est de donner une vue claire, exploitable et durable de:
- l'objectif produit discute (battre NgRx en capacites reelles, avec moins de complexite),
- ce qui a ete implemente concretement,
- ou chaque element vit dans le projet,
- les decisions d'architecture (pourquoi),
- et la suite de travail recommandee.
Construire un state manager:
- aussi capable que NgRx sur les scenarios reels (CRUD, concurence, orchestration),
- plus simple a utiliser (moins de code, moins de concepts),
- multi-framework (Angular aujourd'hui, React/Vue ensuite) grace a
@ngstato/core, - avec RxJS optionnel (integrable, jamais obligatoire).
Message cible:
- State-first par defaut (actions + effects + selectors memoises + helpers Promise-first),
- Stream-first uniquement a la frontiere (websocket, Firebase, router events, RxJS existant) via
fromStream.
Le moteur central est dans:
packages/core/src/store.tspackages/core/src/types.ts
Principes:
createStore()construit le store public,- la logique interne reste dans
StatoStore, - les features avancees s'ajoutent par:
- wrappers d'actions (
helpers/*), - wrappers de config (
withPersist(...)), - connectors runtime (
connectDevTools(...),on(...)).
- wrappers d'actions (
Integre via:
packages/angular/src/create-angular-store.tspackages/angular/src/inject-store.tspackages/angular/src/provide-ngstato.tspackages/angular/src/devtools.component.ts
Raison:
- la logique metier ne doit pas dependre d'Angular,
- Angular mappe le state vers Signals + DI, sans redefinir les regles du moteur.
on(actionFn, handler)pour reactions inter-stores (success/error, duration, args).exclusive()(equiv. exhaustMap sur action async).queued()(equiv. concatMap sur action async).
packages/core/src/action-bus.tspackages/core/src/store.ts(dispatch events + binding action publique)packages/core/src/index.ts(exports)packages/core/src/helpers/exclusive.tspackages/core/src/helpers/queued.tspackages/core/src/__tests__/store.test.tspackages/core/src/__tests__/helpers.test.tspackages/core/README.md
apps/student-demo/src/app/features/students/store/student.store.tsapps/student-demo/src/app/features/students/pages/students-page/students-page.component.tsapps/student-demo/README.md
distinctUntilChanged()(wrapper d'action, anti-execution inutile),forkJoin()(parallel all),race()(first wins),combineLatest()(deps state/effects, sans streams),createEntityAdapter()(collections normalisees ids/entities + CRUD + selectors).
packages/core/src/helpers/distinct-until-changed.tspackages/core/src/helpers/fork-join.tspackages/core/src/helpers/race.tspackages/core/src/helpers/combine-latest.tspackages/core/src/helpers/entity-adapter.tspackages/core/src/index.tspackages/core/src/__tests__/helpers.test.tspackages/core/src/__tests__/entity-adapter.test.tspackages/core/README.md
combineLatestStream()pour combiner des sources.subscribe(...).- Nouveau toolkit composable type RxJS:
pipeStream,mapStream,filterStream,distinctUntilChangedStream,debounceStream,throttleStream,switchMapStream,concatMapStream,exhaustMapStream,mergeMapStream,catchErrorStream,retryStream.
packages/core/src/helpers/combine-latest-stream.tspackages/core/src/helpers/stream-operators.tspackages/core/src/helpers/from-stream.ts(baseStatoObservable)packages/core/src/index.ts(exports)packages/core/src/__tests__/helpers.test.ts(semantiques validates)packages/core/README.md
On garde 2 APIs distinctes:
combineLatest()pour deps state (state-first),combineLatestStream()pour flux externes (stream-first).
Pourquoi:
- semantiques differentes (pas les memes couts/runtime/lifecycle),
- meilleure lisibilite,
- types plus simples,
- moins de confusion pour les equipes.
Avant:
- Core:
createStore()ne garantissait pas toujours un cycle init uniforme selon usage. - Angular:
hooks.onInitetait appele directement dans l'adapter.
Risque:
- divergence de comportement entre Angular et futur React/Vue/Node.
createStore()initialise automatiquement viainit(publicStore).init()est idempotent (onInitexecute une seule fois).- Angular appelle
coreStore.__store__.init(angularStore)au lieu d'appelerhooks.onIniten direct.
packages/core/src/store.tspackages/angular/src/create-angular-store.ts
- comportement coherent quel que soit l'adapter,
- base solide pour extension React/Vue.
Passage demos vers Vitest:
apps/student-demo/package.jsonapps/student-demo/vitest.config.tsapps/student-demo/src/smoke.spec.tsapps/stackblitz-demo/package.jsonapps/stackblitz-demo/vitest.config.tsapps/stackblitz-demo/src/smoke.spec.tspnpm-lock.yaml
packages/core: tests OK (115 tests apres stream operators + entity adapter)packages/angular: tests OK- build monorepo OK (warnings styles/export conditions, non bloquants)
- CRUD + side effects state-first: moins de boilerplate.
- Concurrence action-level:
exclusive,queued,abortable. - Async patterns Promise-first:
forkJoin,race,retryable. - Streams externes integrables sans imposer RxJS.
withEntities()en wrapper de config (au-dessus decreateEntityAdapter) pour ergonomie store-level.- testing utilities dediees (
@ngstato/core/testing/@ngstato/angular/testing). - devtools avances (time-travel, filtres).
Objectif:
- couvrir le coeur "app complexe CRUD" (equivalent avantage NgRx Entity).
Sortie livree:
createEntityAdapter()+ helpers CRUD normalises + selectors.
Objectif:
- couvrir les patterns RxJS reelles les plus utilises, sans reproduire tout RxJS.
Sortie livree:
pipeStream+ operators essentiels avec tests de semantique stricte.
Objectif:
- finaliser l'ergonomie enterprise sans perdre la simplicite.
Sortie attendue:
withEntities()config-wrapper,- testing utilities dediees,
- devtools time-travel / filtres.
Comparer NgRx v21+ vs ngStato sur:
- lignes de code,
- latence action->state,
- throughput updates,
- cout bundle.
- Garder
@ngstato/coresans dependance RxJS obligatoire. - Toute feature doit etre:
- soit wrapper d'action,
- soit wrapper de config,
- soit connector runtime.
- Eviter d'alourdir
createStoreavec des details de domaine. - Ajouter tests de semantique avant doc marketing.
- Adapter Angular/React/Vue = couche fine; le comportement vient du core.
packages/core/src/store.tspackages/core/src/types.tspackages/core/src/index.ts
packages/core/src/helpers/from-stream.tspackages/core/src/helpers/combine-latest.tspackages/core/src/helpers/combine-latest-stream.tspackages/core/src/helpers/stream-operators.tspackages/core/src/helpers/exclusive.tspackages/core/src/helpers/queued.tspackages/core/src/helpers/with-persist.tspackages/core/src/action-bus.ts
packages/angular/src/create-angular-store.tspackages/angular/src/inject-store.tspackages/angular/src/provide-ngstato.tspackages/angular/src/devtools.component.ts
packages/core/src/__tests__/helpers.test.tspackages/core/src/__tests__/store.test.tspackages/angular/src/__tests__/create-angular-store.test.ts
apps/student-demo/src/app/features/students/store/student.store.tsapps/student-demo/src/app/features/students/pages/students-page/students-page.component.tsapps/stackblitz-demo/src/app/todo.store.ts
- Le document d'analyse comparatif local est volontairement non commite:
v0.2-ANALYSIS.md
Il sert de trace de decision et de comparaison evolutive.