webapp-factory
v0.1.1
Published
webapp-factory — verzamelpackage. De backend-foundation-collectie (domein-loze, herbruikbare backend-kits: config, http, persistence, ...) is bereikbaar onder de subpath `webapp-factory/backend-foundation`.
Readme
webapp-factory
Collectie van domein-loze, herbruikbare backend-kits. Elke kit is een pure TypeScript-module (ports & adapters, geen domeinkennis) die via een namespace of subpath geïmporteerd wordt. Eén package, één versielijn, semver.
// Namespace-import (root):
import { config } from 'webapp-factory/backend-foundation';
const cfg = await config.loadConfig({ schema, env: process.env });
// of subpath-import (laadt alleen die kit):
import { loadConfig } from 'webapp-factory/backend-foundation/config';Installatie
npm install webapp-factory zodzod is een (optionele) peer-dependency voor de kits die schemavalidatie bieden.
Kits
| Kit | Namespace | Subpath | Status |
|-----|-----------|---------|--------|
| config | config | webapp-factory/backend-foundation/config | Integratiegids | ✅ EPIC-01 (US-0101 t/m US-0105) |
| http | http | webapp-factory/backend-foundation/http | Integratiegids | ✅ EPIC-02 (US-0201 t/m US-0207) |
| persistence | persistence | webapp-factory/backend-foundation/persistence | Integratiegids | ✅ EPIC-03 (US-0301 t/m US-0305) |
| auth | auth | webapp-factory/backend-foundation/auth | Integratiegids | ✅ EPIC-04 (US-0401 t/m US-0404) |
| access-control | accessControl | webapp-factory/backend-foundation/access-control | Integratiegids | ✅ EPIC-05 (US-0501 t/m US-0504) |
| rate-limit | rateLimit | webapp-factory/backend-foundation/rate-limit | Integratiegids | ✅ EPIC-06 (US-0601 t/m US-0604) |
| cache | cache | webapp-factory/backend-foundation/cache | Integratiegids | ✅ EPIC-07 (US-0701 t/m US-0704) |
| jobs | jobs | webapp-factory/backend-foundation/jobs | Integratiegids | ✅ EPIC-08 (US-0801 t/m US-0804) |
| audit-log | auditLog | webapp-factory/backend-foundation/audit-log | Integratiegids | ✅ EPIC-10 (US-1001 t/m US-1004) |
| observability | observability | webapp-factory/backend-foundation/observability | Integratiegids | ✅ EPIC-11 (US-1101 t/m US-1104) |
| i18n | i18n | webapp-factory/backend-foundation/i18n | Integratiegids | ✅ EPIC-13 (US-1301 t/m US-1304) |
| mailer | mailer | webapp-factory/backend-foundation/mailer | Integratiegids | ✅ EPIC-09 (US-0901 t/m US-0904) |
| privacy | privacy | webapp-factory/backend-foundation/privacy | Integratiegids | ✅ EPIC-12 (US-1201 t/m US-1205) |
| test-kit | testKit | webapp-factory/backend-foundation/test-kit | Integratiegids | ✅ EPIC-14 (US-1401 t/m US-1404) |
De kolom-kop hierboven is: Kit · Namespace · Subpath · Integratiegids · Status.
Per kit is er een taakgerichte integratiegids in docs/: poorten, wiring,
recepten, testadvies en valkuilen (deze README geeft alleen het API-overzicht).
Een nieuwe kit toevoegen betekent:
src/<kit>/met een eigenindex.ts(pure core + adapters).- een namespace-export in de root-
src/index.ts(export * as <kit> from './<kit>/index.js'). - een subpath in
exports(en/<kit>/nestjsals er een Nest-adapter is). - een integratiegids
docs/<kit>.mdvolgens de vaste opbouw indocs/README.md.
Kit: config
Getypte configuratie- en secret-loading met schemavalidatie, fail-fast start en per-omgeving overrides.
import { z } from 'zod';
import { config } from 'webapp-factory/backend-foundation';
const schema = config.zodSchema(
z.object({
app: z.object({ name: z.string() }),
db: z.object({
host: z.string(),
port: z.coerce.number().int().min(1).max(65535).default(5432),
password: config.zodSecret(), // opgelost + geredigeerd
}),
log: z.object({ level: z.enum(['debug', 'info', 'warn', 'error']).default('info') }),
}),
);
const cfg = await config.loadConfig({
schema,
base: { log: { level: 'info' } },
overrides: { production: { log: { level: 'warn' } } },
environmentKey: 'APP_ENV',
env: process.env, // DB__HOST -> db.host, DB__PORT -> db.port (gecoerced)
resolver: config.compositeSecretResolver(
config.fileSecretResolver(), // file:///run/secrets/...
config.mapSecretResolver('vault', { 'kv/data/db#password': '…' }),
),
reporter: config.consoleReporter(),
onFailure: 'exit', // fail-fast met niet-nul exitcode
});
cfg.db.port; // number, default toegepast
cfg.db.password.reveal(); // pas op het punt van gebruik
JSON.stringify(cfg); // db.password -> "***"Kernconcepten
- Env (US-0101):
DB__HOST→db.host; scheidingsteken__, lowercased; optioneleprefix. Voorrang laag→hoog:base→ per-omgeving override →sources→.env→env. Coercie schema-gedreven (z.coerce.*) of standalone metcoerceByMap. - Secrets (US-0102): referenties (
file://,vault://, custom) worden via deSecretResolver-poort opgelost en in eenSecretgewrapt die zichzelf consequent redigeert (JSON.stringify/inspect/String/spread). Onoplosbaar →SecretResolutionErrorzonder secretwaarde. - Validatie (US-0103):
zodSchema(...)leidt het type af viaz.infer, verzamelt álle overtredingen (pad + reden, geen invoerwaarden) en levert een bevroren object. - Fail-fast (US-0104): geaggregeerd, geredigeerd rapport via de
Reporter-poort;onFailure: 'exit'→ niet-nul exitcode, andersConfigValidationError. - Overrides (US-0105):
base+overrides[<env>]diepe merge (override wint); onbekende omgeving valt terug op de basis; fouten benoemen de omgeving.
Ports (injecteer je eigen adapters)
| Port | Verantwoordelijkheid | Meegeleverde adapters |
|------|----------------------|-----------------------|
| ConfigSchema<T> | valideren + type afleiden | zodSchema, zodSecret |
| SecretResolver | referenties oplossen | fileSecretResolver, mapSecretResolver, functionSecretResolver, compositeSecretResolver |
| Reporter | foutrapport uitschrijven | consoleReporter, collectingReporter |
NestJS
import { ConfigKitModule, CONFIG_KIT } from 'webapp-factory/backend-foundation/config/nestjs';
@Module({ imports: [ConfigKitModule.forRootAsync({ schema, env: process.env })] })
export class AppModule {}
// constructor(@Inject(CONFIG_KIT) private readonly cfg: AppConfig) {}Ontwikkeling
npm install # vanuit de repo-root (npm workspaces) of vanuit deze package
npm run build # tsc -> dist/
npm test # vitest run (324 tests, incl. HTTP-e2e, echte Postgres- en Redis-testcontainer-e2e, auth-flow- en guard-e2e)
npm run typecheckPortabiliteits-contract (per kit)
- Geen domeinkennis — alleen abstracties (schema, resolver, reporter, omgevingen).
- Ports & adapters — de core definieert interfaces; het project levert adapters/config.
- Config-injectie — geen hardcoded waardes of vaste omgevingsnamen.
- Semver — breaking changes aan de publieke API vereisen een major-bump van de collectie.
Bron & conventies: ../../GENERATION-GUIDE.md.
