emilsoftware-utilities 2.0.0-dev.82 → 2.0.0-dev.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/accessi/server/index.d.ts +4 -0
  2. package/dist/accessi/server/index.js +7 -1
  3. package/dist/accessi/server/index.js.map +1 -1
  4. package/dist/accessi/server/tenantRouter.d.ts +35 -0
  5. package/dist/accessi/server/tenantRouter.js +71 -0
  6. package/dist/accessi/server/tenantRouter.js.map +1 -0
  7. package/dist/accessi/server/tenantSupervisor.d.ts +60 -0
  8. package/dist/accessi/server/tenantSupervisor.js +296 -0
  9. package/dist/accessi/server/tenantSupervisor.js.map +1 -0
  10. package/dist/accessi/server/tenants.js +8 -0
  11. package/dist/accessi/server/tenants.js.map +1 -1
  12. package/dist/accessi-module/AccessiModule.js.map +1 -1
  13. package/dist/accessi-module/Console/console.js +1 -1
  14. package/dist/accessi-module/index.d.ts +1 -1
  15. package/dist/accessi-module/index.js +4 -3
  16. package/dist/accessi-module/index.js.map +1 -1
  17. package/dist/accessi-module/observability/metrics.js +13 -4
  18. package/dist/accessi-module/observability/metrics.js.map +1 -1
  19. package/dist/accessi-module/security/audit.d.ts +14 -4
  20. package/dist/accessi-module/security/audit.js +73 -48
  21. package/dist/accessi-module/security/audit.js.map +1 -1
  22. package/dist/accessi-module/tenancy/tenantContext.d.ts +15 -0
  23. package/dist/accessi-module/tenancy/tenantContext.js +26 -0
  24. package/dist/accessi-module/tenancy/tenantContext.js.map +1 -0
  25. package/dist/emilsoftware-utilities-2.0.0-dev.84.tgz +0 -0
  26. package/docs/adr/0002-multi-tenancy.md +9 -7
  27. package/docs/multi-tenancy.md +69 -3
  28. package/package.json +3 -3
  29. package/dist/emilsoftware-utilities-2.0.0-dev.82.tgz +0 -0
@@ -126,8 +126,25 @@ Avvia un processo figlio per ogni tenant abilitato:
126
126
  - non riavvia automaticamente un figlio: un loop su configurazione rotta è
127
127
  peggio di un processo che resta giù; usare systemd/docker/Kubernetes.
128
128
 
129
- Il supervisore legge la cartella all'avvio: **aggiungere o rimuovere un tenant
130
- richiede un riavvio**. Non c'è hot reload (Nest non smonta moduli a caldo).
129
+ Il supervisore legge la cartella all'avvio. Con `--watch` osserva i file
130
+ `*.environment.ts` e riapplica la configurazione:
131
+
132
+ ```bash
133
+ npm run accessi:tenants -- --dir ./tenants --serve --watch
134
+ ```
135
+
136
+ Regole:
137
+
138
+ - un file invalido annulla il reload e lascia attivi i tenant correnti;
139
+ - i tenant invariati non vengono riavviati;
140
+ - un tenant modificato viene riavviato sulla stessa porta (breve interruzione);
141
+ - aggiunte e rimozioni avviano/fermano solo il tenant interessato;
142
+ - il polling è di 1 secondo con debounce di 200 ms (`pollIntervalMs`/
143
+ `debounceMs` nell'API del supervisore).
144
+
145
+ Senza `--watch` un cambiamento richiede il riavvio del supervisore. Non c'è
146
+ montaggio/smontaggio di moduli Nest a caldo: il reload riavvia i processi
147
+ interessati, non l'intero servizio.
131
148
 
132
149
  ### systemd (consigliato in produzione)
133
150
 
@@ -258,6 +275,54 @@ proxy_set_header X-Accessi-Tenant acme;
258
275
  e avviare il router con `allowHeader: true` solo nel servizio che si fida del
259
276
  proxy.
260
277
 
278
+ ## Router in-process (opt-in, fase 4)
279
+
280
+ In alternativa al processo per tenant, un host può montare più app Accessi nello
281
+ stesso processo e usare `createAccessiTenantRouter`:
282
+
283
+ ```ts
284
+ import {
285
+ configureAccessiTenantAudit,
286
+ createAccessiService,
287
+ createAccessiTenantRouter,
288
+ loadAccessiTenants,
289
+ } from 'emilsoftware-utilities/accessi/server';
290
+
291
+ const registry = loadAccessiTenants({ directory: './tenants' });
292
+ const acmeService = await createAccessiService({ accessiOptions: acmeOptions });
293
+ const betaService = await createAccessiService({ accessiOptions: betaOptions });
294
+
295
+ configureAccessiTenantAudit('acme', { store: acmeAuditStore, logger: false });
296
+ configureAccessiTenantAudit('beta', { store: betaAuditStore, logger: false });
297
+
298
+ const router = createAccessiTenantRouter({
299
+ registry,
300
+ handlers: { acme: acmeService.app, beta: betaService.app },
301
+ allowHeader: false,
302
+ });
303
+ app.use('/api/accessi', router);
304
+ ```
305
+
306
+ Comportamento:
307
+
308
+ - risoluzione host → path → header fidato, senza fallback;
309
+ - `req.accessiTenant` contiene il tenant risolto;
310
+ - il handler gira dentro `runWithAccessiTenant`, quindi audit e metriche
311
+ ricevono il label `tenant`;
312
+ - tenant sconosciuto → `404 ACCESSI_TENANT_NOT_FOUND`;
313
+ - tenant senza handler → `501 ACCESSI_TENANT_HANDLER_MISSING`.
314
+
315
+ Limiti importanti:
316
+
317
+ - le app devono essere indipendenti (un `createAccessiService` per tenant);
318
+ - le API globali `authorizeAccessi` e `setAccessiAuthService` usano l'ultima
319
+ istanza inizializzata: in modalità router non sono tenant-aware e vanno
320
+ evitate; usare i guard/middleware dell'app del tenant;
321
+ - audit e metriche di background (fuori da una richiesta) usano la
322
+ configurazione di default del processo;
323
+ - il processo-per-tenant resta il default raccomandato: il router è opt-in e
324
+ non riduce i pool Firebird se le app sono comunque tutte inizializzate.
325
+
261
326
  ## Store Redis condivisi
262
327
 
263
328
  Con Redis condiviso usare l'helper: crea tutti gli store con prefissi
@@ -332,7 +397,8 @@ schema.
332
397
  ## Limiti
333
398
 
334
399
  - Un processo per tenant: più RAM, più pool Firebird, più connessioni SMTP.
335
- - Nessun hot reload: aggiunta/rimozione richiede restart.
400
+ - Il reload con `--watch` riavvia i processi modificati sulla stessa porta: c'è
401
+ una breve interruzione per il singolo tenant, non per gli altri.
336
402
  - Migrazioni e backup per database.
337
403
  - La risoluzione via header è ammessa solo dietro proxy fidato; il client non
338
404
  deve poter scegliere il tenant.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emilsoftware-utilities",
3
- "version": "2.0.0-dev.82",
3
+ "version": "2.0.0-dev.84",
4
4
  "description": "Utilities for EmilSoftware",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -141,8 +141,8 @@
141
141
  "lint": "node scripts/lint.cjs",
142
142
  "check:deploy": "node scripts/check-deploy-templates.cjs",
143
143
  "test": "npm run typecheck && npm run lint && npm run test:unit",
144
- "test:unit": "node --test test/angular-components.cjs test/menus-catalog.mjs test/menu-scopes.cjs test/accessi-regressions.cjs test/password-reset-regressions.cjs test/two-factor.cjs test/accessi-schema.cjs test/utilities-regressions.cjs test/service-token-regressions.cjs test/accessi-email-config.cjs test/accessi-catalog-scripts.cjs test/openapi-config.cjs test/resource-server.cjs test/accessi-security-standards.cjs test/accessi-service.cjs test/refresh-token.cjs test/token-revocation.cjs test/accessi-client.cjs test/accessi-client-scopes.cjs test/openapi-semantic-diff.cjs test/proxy-ip.cjs test/readiness.cjs test/jwt-key-rotation.cjs test/security-headers.cjs test/auth-cookies.cjs test/metrics.cjs test/audit.cjs test/import-entrypoints.cjs test/tenants.cjs test/tenant-stores.cjs test/deploy-templates.cjs",
145
- "test:coverage": "node --experimental-test-coverage --test-coverage-lines=50 --test-coverage-functions=60 --test-coverage-branches=60 --test test/angular-components.cjs test/menus-catalog.mjs test/menu-scopes.cjs test/accessi-regressions.cjs test/password-reset-regressions.cjs test/two-factor.cjs test/accessi-schema.cjs test/utilities-regressions.cjs test/service-token-regressions.cjs test/accessi-email-config.cjs test/accessi-catalog-scripts.cjs test/openapi-config.cjs test/resource-server.cjs test/accessi-security-standards.cjs test/accessi-service.cjs test/refresh-token.cjs test/token-revocation.cjs test/accessi-client.cjs test/accessi-client-scopes.cjs test/openapi-semantic-diff.cjs test/proxy-ip.cjs test/readiness.cjs test/jwt-key-rotation.cjs test/security-headers.cjs test/auth-cookies.cjs test/metrics.cjs test/audit.cjs test/import-entrypoints.cjs test/tenants.cjs test/tenant-stores.cjs test/deploy-templates.cjs",
144
+ "test:unit": "node --test test/angular-components.cjs test/menus-catalog.mjs test/menu-scopes.cjs test/accessi-regressions.cjs test/password-reset-regressions.cjs test/two-factor.cjs test/accessi-schema.cjs test/utilities-regressions.cjs test/service-token-regressions.cjs test/accessi-email-config.cjs test/accessi-catalog-scripts.cjs test/openapi-config.cjs test/resource-server.cjs test/accessi-security-standards.cjs test/accessi-service.cjs test/refresh-token.cjs test/token-revocation.cjs test/accessi-client.cjs test/accessi-client-scopes.cjs test/openapi-semantic-diff.cjs test/proxy-ip.cjs test/readiness.cjs test/jwt-key-rotation.cjs test/security-headers.cjs test/auth-cookies.cjs test/metrics.cjs test/audit.cjs test/import-entrypoints.cjs test/tenants.cjs test/tenant-stores.cjs test/deploy-templates.cjs test/tenant-supervisor.cjs test/tenant-router.cjs",
145
+ "test:coverage": "node --experimental-test-coverage --test-coverage-lines=50 --test-coverage-functions=60 --test-coverage-branches=60 --test test/angular-components.cjs test/menus-catalog.mjs test/menu-scopes.cjs test/accessi-regressions.cjs test/password-reset-regressions.cjs test/two-factor.cjs test/accessi-schema.cjs test/utilities-regressions.cjs test/service-token-regressions.cjs test/accessi-email-config.cjs test/accessi-catalog-scripts.cjs test/openapi-config.cjs test/resource-server.cjs test/accessi-security-standards.cjs test/accessi-service.cjs test/refresh-token.cjs test/token-revocation.cjs test/accessi-client.cjs test/accessi-client-scopes.cjs test/openapi-semantic-diff.cjs test/proxy-ip.cjs test/readiness.cjs test/jwt-key-rotation.cjs test/security-headers.cjs test/auth-cookies.cjs test/metrics.cjs test/audit.cjs test/import-entrypoints.cjs test/tenants.cjs test/tenant-stores.cjs test/deploy-templates.cjs test/tenant-supervisor.cjs test/tenant-router.cjs",
146
146
  "test:accessi": "npm run test:unit",
147
147
  "test:all": "npm test && npm run test:integration && npm run test:integration:redis",
148
148
  "test:integration": "node test/integration/run-firebird.cjs 5",