Contexte / Context
La migration apps/server â apps/server-nestjs mappe les syncs de plugins via des Ă©vĂ©nements :
apps/server (legacy) : fire hook.zone.upsert / hook.zone.delete directement dans business.ts sur les routes zone.
apps/server-nestjs : Ă©met via AppEventsService.emit*(...) â EventEmitter2 â consommateurs @OnEvent.
ProblĂšme / Problem
VaultService écoute sur @OnEvent('zone.upsert') et @OnEvent('zone.delete') (vault.service.ts:87, 101), mais :
AppEventsService n'expose AUCUNE mĂ©thode d'Ă©mission pour zone.* â ni emitZoneEvent, ni de type ZoneEventName. La seule API publique est emitProjectEvent / emitProjectMemberEvent / emitRepositoryEvent (app-events.service.ts:72-109).
- Aucun service nestjs n'émet
zone.upsert / zone.delete â le grep emitProjectEvent|emitProjectMemberEvent|emitRepositoryEvent|eventEmitter.emit ne trouve aucune rĂ©fĂ©rence zone (hors logs).
- Le module
zone n'existe pas encore dans server-nestjs â la route zone est toujours propriĂ©taire de apps/server (legacy).
Impact
Ce n'est pas un bug LIVE aujourd'hui (la route zone reste sur legacy, qui fire les hooks directement). C'est un rĂ©gression silencieuse au cutover : dĂšs que la route zone migrera vers server-nestjs sans brancher un emitZoneEvent, les listeners @OnEvent('zone.*') de Vault deviendront morts â le mount/policy/approle Vault des zones ne seront plus provisionnĂ©s/suprimĂ©s.
Cf. migration-parity-checklist : « if the migrated service emits eventEmitter.emitAsync('<entity>.<verb>', ...) but NO @OnEvent('<entity>.<verb>') handler exists anywhere » â ici c'est l'inverse (listener sans Ă©metteur), mĂȘme classe de rĂ©gression silencieuse.
Preuves / Evidence
- Baseline unitaire : 578 passé / 59 skipped (2026-08-25, Node 24).
- Seed unitaire validé :
app-events.service.spec.ts ajoute une assertion de paritĂ© zone.* (listener sans Ă©metteur) â 12/12 vert.
vault.service.spec.ts : 4 specs nouveaux scellent la surface externe upsertZone/deleteZone (mount + policy + approle + tech-readonly) â 8/8 vert.
- E2E
vault.e2e-spec.ts : case zone ajoutée (gated E2E=1), émet zone.upsert/zone.delete directement via EventEmitter2 pour couvrir le contrat externe Vault (runnable sur host connecté / CI).
Definition du fini / Done
Contexte / Context
La migration
apps/serverâapps/server-nestjsmappe les syncs de plugins via des Ă©vĂ©nements :apps/server(legacy) : firehook.zone.upsert/hook.zone.deletedirectement dansbusiness.tssur les routes zone.apps/server-nestjs: Ă©met viaAppEventsService.emit*(...)âEventEmitter2â consommateurs@OnEvent.ProblĂšme / Problem
VaultServiceĂ©coute sur@OnEvent('zone.upsert')et@OnEvent('zone.delete')(vault.service.ts:87, 101), mais :AppEventsServicen'expose AUCUNE mĂ©thode d'Ă©mission pourzone.*â niemitZoneEvent, ni de typeZoneEventName. La seule API publique estemitProjectEvent/emitProjectMemberEvent/emitRepositoryEvent(app-events.service.ts:72-109).zone.upsert/zone.deleteâ le grepemitProjectEvent|emitProjectMemberEvent|emitRepositoryEvent|eventEmitter.emitne trouve aucune rĂ©fĂ©rence zone (hors logs).zonen'existe pas encore dans server-nestjs â la route zone est toujours propriĂ©taire deapps/server(legacy).Impact
Ce n'est pas un bug LIVE aujourd'hui (la route zone reste sur legacy, qui fire les hooks directement). C'est un régression silencieuse au cutover : dÚs que la route zone migrera vers server-nestjs sans brancher un
emitZoneEvent, les listeners@OnEvent('zone.*')de Vault deviendront morts â le mount/policy/approle Vault des zones ne seront plus provisionnĂ©s/suprimĂ©s.Cf. migration-parity-checklist : « if the migrated service emits
eventEmitter.emitAsync('<entity>.<verb>', ...)but NO@OnEvent('<entity>.<verb>')handler exists anywhere » â ici c'est l'inverse (listener sans Ă©metteur), mĂȘme classe de rĂ©gression silencieuse.Preuves / Evidence
app-events.service.spec.tsajoute une assertion de paritĂ©zone.*(listener sans Ă©metteur) â 12/12 vert.vault.service.spec.ts: 4 specs nouveaux scellent la surface externeupsertZone/deleteZone(mount + policy + approle + tech-readonly) â 8/8 vert.vault.e2e-spec.ts: case zone ajoutĂ©e (gatedE2E=1), Ă©metzone.upsert/zone.deletedirectement viaEventEmitter2pour couvrir le contrat externe Vault (runnable sur host connectĂ© / CI).Definition du fini / Done
zonedans server-nestjs avec un Ă©metteurzone.upsert/zone.deleteviaAppEventsServiceâ OU garder la route sur legacy jusqu'Ă ce que l'Ă©metteur existe.