create-forgeon 0.3.1 → 0.3.2

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 (32) hide show
  1. package/package.json +1 -1
  2. package/src/integrations/flow.mjs +1 -1
  3. package/src/modules/dependencies.test.mjs +3 -3
  4. package/src/modules/executor.test.mjs +38 -0
  5. package/src/modules/i18n.mjs +45 -0
  6. package/src/modules/jwt-auth.mjs +3 -3
  7. package/src/modules/logger.mjs +3 -0
  8. package/src/modules/rate-limit.mjs +3 -2
  9. package/src/modules/rbac.mjs +6 -0
  10. package/src/modules/registry.mjs +16 -9
  11. package/src/modules/swagger.mjs +3 -0
  12. package/src/modules/sync-integrations.mjs +5 -5
  13. package/templates/base/README.md +1 -1
  14. package/templates/base/docs/AI/ARCHITECTURE.md +1 -1
  15. package/templates/base/scripts/forgeon-sync-integrations.mjs +5 -5
  16. package/templates/module-fragments/i18n/10_overview.md +5 -0
  17. package/templates/module-fragments/i18n/20_scope.md +6 -0
  18. package/templates/module-fragments/i18n/90_status_implemented.md +5 -0
  19. package/templates/module-fragments/jwt-auth/20_scope.md +4 -2
  20. package/templates/module-fragments/jwt-auth/90_status_implemented.md +3 -2
  21. package/templates/module-fragments/logger/10_overview.md +4 -0
  22. package/templates/module-fragments/logger/20_scope.md +5 -0
  23. package/templates/module-fragments/logger/90_status_implemented.md +3 -0
  24. package/templates/module-fragments/rate-limit/20_idea.md +1 -0
  25. package/templates/module-fragments/rate-limit/30_what_it_adds.md +2 -0
  26. package/templates/module-fragments/rate-limit/50_how_to_use.md +2 -0
  27. package/templates/module-fragments/rbac/30_what_it_adds.md +5 -0
  28. package/templates/module-fragments/rbac/40_how_it_works.md +5 -0
  29. package/templates/module-fragments/rbac/50_how_to_use.md +5 -0
  30. package/templates/module-fragments/swagger/10_overview.md +4 -0
  31. package/templates/module-fragments/swagger/20_scope.md +4 -0
  32. package/templates/module-fragments/swagger/90_status_implemented.md +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-forgeon",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Forgeon project generator CLI",
5
5
  "license": "MIT",
6
6
  "author": "Forgeon",
@@ -125,7 +125,7 @@ export function printOptionalIntegrationsWarning(integrations) {
125
125
  for (const integration of integrations) {
126
126
  console.log(`\n${colorize('yellow', 'Warning: optional integration available')}`);
127
127
  console.log(`- ${integration.title}`);
128
- console.log('Modules:');
128
+ console.log('Modules / capabilities:');
129
129
  for (const moduleId of integration.modules ?? []) {
130
130
  console.log(`- ${colorize('cyan', moduleId)}`);
131
131
  }
@@ -44,8 +44,8 @@ const TEST_PRESETS = [
44
44
  {
45
45
  id: 'auth-persistence',
46
46
  title: 'Auth Persistence Integration',
47
- modules: ['jwt-auth', 'db-prisma'],
48
- requires: [{ type: 'module', id: 'db-prisma' }],
47
+ modules: ['jwt-auth', 'db-adapter'],
48
+ requires: [{ type: 'capability', id: 'db-adapter' }],
49
49
  description: ['Persist refresh-token state'],
50
50
  followUpCommands: [
51
51
  'npx create-forgeon@latest add db-prisma',
@@ -130,7 +130,7 @@ describe('module dependency helpers', () => {
130
130
 
131
131
  assert.equal(pending.length, 1);
132
132
  assert.equal(pending[0].id, 'auth-persistence');
133
- assert.equal(pending[0].missing[0].id, 'db-prisma');
133
+ assert.equal(pending[0].missing[0].id, 'db-adapter');
134
134
  } finally {
135
135
  fs.rmSync(targetRoot, { recursive: true, force: true });
136
136
  }
@@ -79,6 +79,8 @@ function assertRateLimitWiring(projectRoot) {
79
79
 
80
80
  const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
81
81
  assert.match(readme, /## Rate Limit Module/);
82
+ assert.match(readme, /installs independently/i);
83
+ assert.match(readme, /no optional integration sync is required/i);
82
84
  }
83
85
 
84
86
  function assertRbacWiring(projectRoot) {
@@ -110,6 +112,8 @@ function assertRbacWiring(projectRoot) {
110
112
 
111
113
  const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
112
114
  assert.match(readme, /## RBAC \/ Permissions Module/);
115
+ assert.match(readme, /installs independently/i);
116
+ assert.match(readme, /jwt-auth.*optional/i);
113
117
  }
114
118
 
115
119
  function assertJwtAuthWiring(projectRoot, withPrismaStore) {
@@ -476,6 +480,13 @@ describe('addModule', () => {
476
480
  assert.match(rootPackage, /"i18n:types"/);
477
481
  assert.match(rootPackage, /"i18n:add"/);
478
482
 
483
+ const rootReadme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
484
+ assert.match(rootReadme, /## I18n Module/);
485
+ assert.match(rootReadme, /installs independently/i);
486
+ assert.match(rootReadme, /multi-package split/i);
487
+ assert.match(rootReadme, /pnpm i18n:sync/);
488
+ assert.match(rootReadme, /pnpm i18n:add <locale>/);
489
+
479
490
  const i18nAddScriptPath = path.join(projectRoot, 'scripts', 'i18n-add.mjs');
480
491
  assert.equal(fs.existsSync(i18nAddScriptPath), true);
481
492
  const syncScriptPath = path.join(projectRoot, 'scripts', 'forgeon-sync-integrations.mjs');
@@ -505,6 +516,11 @@ describe('addModule', () => {
505
516
  assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/core build/);
506
517
  assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/db-prisma build/);
507
518
  assert.match(apiDockerfile, /COPY packages\/db-prisma\/package\.json packages\/db-prisma\/package\.json/);
519
+
520
+ const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
521
+ assert.match(moduleDoc, /I18n/);
522
+ assert.match(moduleDoc, /installs independently/i);
523
+ assert.match(moduleDoc, /helper commands are part of the module surface/i);
508
524
  } finally {
509
525
  fs.rmSync(targetRoot, { recursive: true, force: true });
510
526
  }
@@ -577,6 +593,15 @@ describe('addModule', () => {
577
593
  assert.match(apiEnv, /LOGGER_HTTP_ENABLED=true/);
578
594
  assert.match(apiEnv, /LOGGER_REQUEST_ID_HEADER=x-request-id/);
579
595
 
596
+ const healthController = fs.readFileSync(
597
+ path.join(projectRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'),
598
+ 'utf8',
599
+ );
600
+ assert.doesNotMatch(healthController, /logger/i);
601
+
602
+ const appTsx = fs.readFileSync(path.join(projectRoot, 'apps', 'web', 'src', 'App.tsx'), 'utf8');
603
+ assert.doesNotMatch(appTsx, /Check logger/i);
604
+
580
605
  const dockerEnv = fs.readFileSync(
581
606
  path.join(projectRoot, 'infra', 'docker', '.env.example'),
582
607
  'utf8',
@@ -592,12 +617,16 @@ describe('addModule', () => {
592
617
 
593
618
  const rootReadme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
594
619
  assert.match(rootReadme, /## Logger Module/);
620
+ assert.match(rootReadme, /installs independently/i);
621
+ assert.match(rootReadme, /does not add a dedicated API\/web probe/i);
595
622
  assert.match(rootReadme, /LOGGER_LEVEL=log/);
623
+ assert.match(rootReadme, /stdout\/stderr/i);
596
624
  assert.match(rootReadme, /docker compose logs api/);
597
625
 
598
626
  const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
599
627
  assert.match(moduleDoc, /Logger/);
600
628
  assert.match(moduleDoc, /Status: implemented/);
629
+ assert.match(moduleDoc, /no dedicated probe is added by design/i);
601
630
  } finally {
602
631
  fs.rmSync(targetRoot, { recursive: true, force: true });
603
632
  }
@@ -633,6 +662,8 @@ describe('addModule', () => {
633
662
  const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
634
663
  assert.match(moduleDoc, /## Idea \/ Why/);
635
664
  assert.match(moduleDoc, /## Configuration/);
665
+ assert.match(moduleDoc, /installs independently/i);
666
+ assert.match(moduleDoc, /No follow-up integration sync is required/i);
636
667
  } finally {
637
668
  fs.rmSync(targetRoot, { recursive: true, force: true });
638
669
  }
@@ -756,12 +787,15 @@ describe('addModule', () => {
756
787
 
757
788
  const rootReadme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
758
789
  assert.match(rootReadme, /## Swagger \/ OpenAPI Module/);
790
+ assert.match(rootReadme, /installs independently/i);
791
+ assert.match(rootReadme, /decorators.*manual/i);
759
792
  assert.match(rootReadme, /SWAGGER_ENABLED=false/);
760
793
  assert.match(rootReadme, /localhost:3000\/api\/docs/);
761
794
 
762
795
  const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
763
796
  assert.match(moduleDoc, /Swagger \/ OpenAPI/);
764
797
  assert.match(moduleDoc, /Status: implemented/);
798
+ assert.match(moduleDoc, /feature-specific Swagger decorators remain manual/i);
765
799
  } finally {
766
800
  fs.rmSync(targetRoot, { recursive: true, force: true });
767
801
  }
@@ -1098,10 +1132,13 @@ describe('addModule', () => {
1098
1132
 
1099
1133
  const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
1100
1134
  assert.match(readme, /refresh token persistence: enabled/);
1135
+ assert.match(readme, /db-adapter/);
1136
+ assert.match(readme, /current provider: `db-prisma`/);
1101
1137
  assert.match(readme, /0002_auth_refresh_token_hash/);
1102
1138
 
1103
1139
  const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
1104
1140
  assert.match(moduleDoc, /Status: implemented/);
1141
+ assert.match(moduleDoc, /db-adapter/);
1105
1142
  } finally {
1106
1143
  fs.rmSync(targetRoot, { recursive: true, force: true });
1107
1144
  }
@@ -1142,6 +1179,7 @@ describe('addModule', () => {
1142
1179
 
1143
1180
  const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
1144
1181
  assert.match(readme, /refresh token persistence: disabled/);
1182
+ assert.match(readme, /db-adapter/);
1145
1183
  assert.match(readme, /create-forgeon add db-prisma/);
1146
1184
 
1147
1185
  } finally {
@@ -405,6 +405,50 @@ function patchRootPackage(targetRoot) {
405
405
  writeJson(packagePath, packageJson);
406
406
  }
407
407
 
408
+ function patchReadme(targetRoot) {
409
+ const readmePath = path.join(targetRoot, 'README.md');
410
+ if (!fs.existsSync(readmePath)) {
411
+ return;
412
+ }
413
+
414
+ const marker = '## I18n Module';
415
+ let content = fs.readFileSync(readmePath, 'utf8').replace(/\r\n/g, '\n');
416
+ if (content.includes(marker)) {
417
+ return;
418
+ }
419
+
420
+ const section = `## I18n Module
421
+
422
+ The i18n add-module provides a full backend + frontend localization baseline.
423
+
424
+ It installs independently and uses a multi-package split:
425
+ - \`@forgeon/i18n\` for Nest runtime wiring
426
+ - \`@forgeon/i18n-contracts\` for generated locale/namespace contracts and maintenance scripts
427
+ - \`@forgeon/i18n-web\` for React-side locale helpers
428
+
429
+ Shared dictionaries:
430
+ - stored under \`resources/i18n/<locale>/*.json\`
431
+ - current default locale set: \`en\`
432
+
433
+ Helper commands:
434
+ - \`pnpm i18n:sync\`
435
+ - \`pnpm i18n:check\`
436
+ - \`pnpm i18n:types\`
437
+ - \`pnpm i18n:add <locale>\`
438
+
439
+ Module env:
440
+ - \`I18N_DEFAULT_LANG=en\`
441
+ - \`I18N_FALLBACK_LANG=en\``;
442
+
443
+ if (content.includes('## Prisma In Docker Start')) {
444
+ content = content.replace('## Prisma In Docker Start', `${section}\n\n## Prisma In Docker Start`);
445
+ } else {
446
+ content = `${content.trimEnd()}\n\n${section}\n`;
447
+ }
448
+
449
+ fs.writeFileSync(readmePath, `${content.trimEnd()}\n`, 'utf8');
450
+ }
451
+
408
452
  function restoreKnownWebProbes(targetRoot, previousAppContent) {
409
453
  if (!previousAppContent) {
410
454
  return;
@@ -533,6 +577,7 @@ export function applyI18nModule({ packageRoot, targetRoot }) {
533
577
  patchApiPackage(targetRoot);
534
578
  patchWebPackage(targetRoot);
535
579
  patchRootPackage(targetRoot);
580
+ patchReadme(targetRoot);
536
581
  patchAppModule(targetRoot);
537
582
  patchHealthController(targetRoot);
538
583
  patchApiDockerfile(targetRoot);
@@ -309,10 +309,10 @@ function patchReadme(targetRoot) {
309
309
  }
310
310
 
311
311
  const persistenceSummary =
312
- '- refresh token persistence: disabled by default (stateless mode)';
312
+ '- refresh token persistence: disabled by default (stateless mode; enable it later through a `db-adapter` provider + integration sync)';
313
313
  const dbFollowUp = `- to enable persistence later:
314
- 1. install a DB module first (for now: \`create-forgeon add db-prisma --project .\`);
315
- 2. run \`pnpm forgeon:sync-integrations\` to auto-wire pair integrations.`;
314
+ 1. install a DB adapter provider first (current provider: \`create-forgeon add db-prisma --project .\`);
315
+ 2. run \`pnpm forgeon:sync-integrations\` to wire auth persistence to the active DB adapter implementation.`;
316
316
 
317
317
  const section = `## JWT Auth Module
318
318
 
@@ -181,6 +181,9 @@ The logger add-module provides:
181
181
  - HTTP access logs with method/path/status/duration/ip/requestId
182
182
  - Nest logger integration via \`app.useLogger(...)\`
183
183
 
184
+ It installs independently and intentionally does not add a dedicated API/web probe.
185
+ Its verification path is operational: inspect API stdout/stderr in dev or container logs in Docker.
186
+
184
187
  Configuration (env):
185
188
  - \`LOGGER_LEVEL=log\` (\`error|warn|log|debug|verbose\`)
186
189
  - \`LOGGER_HTTP_ENABLED=true\`
@@ -289,7 +289,7 @@ function patchReadme(targetRoot) {
289
289
 
290
290
  const section = `## Rate Limit Module
291
291
 
292
- The rate-limit add-module provides a simple first-line safeguard against burst traffic, accidental request loops, and brute-force style abuse.
292
+ The rate-limit add-module installs independently and provides a simple first-line safeguard against burst traffic, accidental request loops, and brute-force style abuse.
293
293
 
294
294
  What it adds:
295
295
  - global request throttling for the API
@@ -310,7 +310,8 @@ Configuration (env):
310
310
 
311
311
  Operational notes:
312
312
  - \`THROTTLE_TRUST_PROXY=true\` is recommended behind reverse proxies
313
- - this is an in-memory throttle preset, not a distributed limiter`;
313
+ - this is an in-memory throttle preset, not a distributed limiter
314
+ - no optional integration sync is required for this module in the current scaffold`;
314
315
 
315
316
  if (content.includes('## Prisma In Docker Start')) {
316
317
  content = content.replace('## Prisma In Docker Start', `${section}\n\n## Prisma In Docker Start`);
@@ -282,6 +282,8 @@ function patchReadme(targetRoot) {
282
282
 
283
283
  The rbac add-module provides a minimal authorization layer for role and permission checks.
284
284
 
285
+ It installs independently. \`jwt-auth\` is optional and only extends demo JWT claims through integration sync.
286
+
285
287
  What it adds:
286
288
  - \`@Roles(...)\` and \`@Permissions(...)\` decorators
287
289
  - \`ForgeonRbacGuard\`
@@ -299,6 +301,10 @@ How to verify:
299
301
  - the generated frontend button sends \`x-forgeon-permissions: health.rbac\` and should return \`200\`
300
302
  - the same route without that header should return \`403\`
301
303
 
304
+ Optional integration:
305
+ - if \`jwt-auth\` is installed too, run \`pnpm forgeon:sync-integrations\`
306
+ - that enables demo JWT permissions for the same RBAC probe flow
307
+
302
308
  Current scope:
303
309
  - no policy engine
304
310
  - no database-backed role store
@@ -16,7 +16,8 @@ const MODULE_PRESETS = {
16
16
  label: 'I18n',
17
17
  category: 'localization',
18
18
  implemented: true,
19
- description: 'Backend/frontend i18n wiring with locale contracts and translation resources.',
19
+ description:
20
+ 'Independent backend/frontend i18n wiring with contracts, web helpers, shared translation resources, and locale maintenance scripts.',
20
21
  detectionPaths: ['packages/i18n/package.json'],
21
22
  provides: ['i18n-runtime'],
22
23
  requires: [],
@@ -28,7 +29,8 @@ const MODULE_PRESETS = {
28
29
  label: 'Logger',
29
30
  category: 'observability',
30
31
  implemented: true,
31
- description: 'Structured API logger with request id middleware and HTTP logging interceptor.',
32
+ description:
33
+ 'Independent structured API logger with request id middleware and HTTP logging interceptor; intentionally no dedicated runtime probe.',
32
34
  detectionPaths: ['packages/logger/package.json'],
33
35
  provides: ['logger-runtime'],
34
36
  requires: [],
@@ -40,7 +42,8 @@ const MODULE_PRESETS = {
40
42
  label: 'Swagger / OpenAPI',
41
43
  category: 'api-documentation',
42
44
  implemented: true,
43
- description: 'OpenAPI docs setup with env-based toggle and route path.',
45
+ description:
46
+ 'Independent OpenAPI docs setup with env-based toggle and route path; feature-level Swagger decorators remain manual.',
44
47
  detectionPaths: ['packages/swagger/package.json'],
45
48
  provides: ['openapi-runtime'],
46
49
  requires: [],
@@ -52,7 +55,8 @@ const MODULE_PRESETS = {
52
55
  label: 'JWT Auth',
53
56
  category: 'auth-security',
54
57
  implemented: true,
55
- description: 'JWT auth preset with contracts/api module split, guard+strategy, and DB-aware refresh token storage wiring.',
58
+ description:
59
+ 'JWT auth preset with contracts/api module split, guard+strategy, and optional db-adapter-backed refresh token persistence via integration sync.',
56
60
  detectionPaths: ['packages/auth-api/package.json'],
57
61
  provides: ['auth-runtime'],
58
62
  requires: [],
@@ -60,10 +64,11 @@ const MODULE_PRESETS = {
60
64
  {
61
65
  id: 'auth-persistence',
62
66
  title: 'Auth Persistence Integration',
63
- modules: ['jwt-auth', 'db-prisma'],
64
- requires: [{ type: 'module', id: 'db-prisma' }],
67
+ modules: ['jwt-auth', 'db-adapter'],
68
+ requires: [{ type: 'capability', id: 'db-adapter' }],
65
69
  description: [
66
- 'Persist refresh-token state through the current DB integration',
70
+ 'Persist refresh-token state through the db-adapter capability boundary',
71
+ 'Use the current DB adapter implementation (today: db-prisma) for refresh-token storage',
67
72
  'Enable stronger refresh-token invalidation flows after logout and rotation',
68
73
  ],
69
74
  followUpCommands: [
@@ -93,7 +98,8 @@ const MODULE_PRESETS = {
93
98
  label: 'Rate Limit',
94
99
  category: 'auth-security',
95
100
  implemented: true,
96
- description: 'Request throttling preset with env-based limits, proxy-aware trust, and a runtime probe endpoint.',
101
+ description:
102
+ 'Independent request throttling preset with env-based limits, proxy-aware trust, and a runtime probe endpoint.',
97
103
  detectionPaths: ['packages/rate-limit/package.json'],
98
104
  provides: ['rate-limit-runtime'],
99
105
  requires: [],
@@ -115,7 +121,8 @@ const MODULE_PRESETS = {
115
121
  label: 'RBAC / Permissions',
116
122
  category: 'auth-security',
117
123
  implemented: true,
118
- description: 'Role and permission decorators with a Nest guard and a protected probe endpoint.',
124
+ description:
125
+ 'Role and permission decorators with a Nest guard and a protected probe endpoint; installs independently and optionally integrates with jwt-auth.',
119
126
  detectionPaths: ['packages/rbac/package.json'],
120
127
  provides: ['rbac-runtime'],
121
128
  requires: [],
@@ -181,6 +181,9 @@ function patchReadme(targetRoot) {
181
181
 
182
182
  The swagger add-module provides generated OpenAPI docs for the API.
183
183
 
184
+ It installs independently and only wires the OpenAPI runtime.
185
+ Feature-specific Swagger decorators (for example \`@ApiOperation\`, \`@ApiBody\`, \`@ApiResponse\`) remain manual and are not auto-patched into other modules.
186
+
184
187
  Configuration (env):
185
188
  - \`SWAGGER_ENABLED=false\`
186
189
  - \`SWAGGER_PATH=docs\`
@@ -97,10 +97,10 @@ const INTEGRATION_GROUPS = [
97
97
  title: 'Auth Persistence Integration',
98
98
  modules: ['jwt-auth', 'db-prisma'],
99
99
  description: [
100
- 'Patch AppModule to wire AUTH_REFRESH_TOKEN_STORE with PrismaAuthRefreshTokenStore',
100
+ 'Patch AppModule to wire AUTH_REFRESH_TOKEN_STORE to the current db-adapter implementation (today: PrismaAuthRefreshTokenStore)',
101
101
  'Add apps/api/src/auth/prisma-auth-refresh-token.store.ts',
102
102
  'Extend Prisma User model with refreshTokenHash and add migration 0002_auth_refresh_token_hash',
103
- 'Update JWT auth README note about refresh-token persistence',
103
+ 'Update JWT auth README note to reflect db-adapter-backed refresh-token persistence',
104
104
  ],
105
105
  isAvailable: (detected) => detected.jwtAuth && detected.dbPrisma,
106
106
  isPending: (rootDir) => isAuthPersistencePending(rootDir),
@@ -236,11 +236,11 @@ function syncJwtDbPrisma({ rootDir, packageRoot, changedFiles }) {
236
236
  let readme = fs.readFileSync(readmePath, 'utf8').replace(/\r\n/g, '\n');
237
237
  const originalReadme = readme;
238
238
  readme = readme.replace(
239
- '- refresh token persistence: disabled by default (stateless mode)',
240
- '- refresh token persistence: enabled (`db-prisma` adapter)',
239
+ '- refresh token persistence: disabled by default (stateless mode; enable it later through a `db-adapter` provider + integration sync)',
240
+ '- refresh token persistence: enabled through the `db-adapter` capability (current provider: `db-prisma`)',
241
241
  );
242
242
  readme = readme.replace(
243
- /- to enable persistence later:[\s\S]*?2\. run `pnpm forgeon:sync-integrations` to auto-wire pair integrations\./m,
243
+ /- to enable persistence later:[\s\S]*?2\. run `pnpm forgeon:sync-integrations` to wire auth persistence to the active DB adapter implementation\./m,
244
244
  '- migration: `apps/api/prisma/migrations/0002_auth_refresh_token_hash`',
245
245
  );
246
246
  if (readme !== originalReadme) {
@@ -38,7 +38,7 @@ pnpm forgeon:sync-integrations
38
38
 
39
39
  Current sync coverage:
40
40
  - `jwt-auth + rbac`: extends demo auth tokens with the `health.rbac` permission.
41
- - `jwt-auth + db-prisma`: wires persistent refresh-token storage for auth.
41
+ - `jwt-auth + db-adapter` (current provider: `db-prisma`): wires persistent refresh-token storage for auth.
42
42
 
43
43
  `create-forgeon add <module>` scans for relevant integration groups and can apply them immediately.
44
44
 
@@ -57,7 +57,7 @@ Reference: `docs/AI/MODULE_SPEC.md`.
57
57
  - each add-module patches only itself;
58
58
  - cross-module changes are allowed only in integration sync rules.
59
59
  - Current integration:
60
- - `jwt-auth + db-prisma` (persistent refresh-token store wiring + schema/migration sync).
60
+ - `jwt-auth + db-adapter` (current provider: `db-prisma`; persistent refresh-token store wiring + schema/migration sync).
61
61
  - Pair sync is explicit (opt-in), not automatic after `add`.
62
62
  - Run `pnpm forgeon:sync-integrations` when you want to apply module-pair integrations.
63
63
  - Swagger auth decorators are intentionally not auto-patched.
@@ -162,11 +162,11 @@ function syncJwtDbPrisma({ rootDir, changedFiles }) {
162
162
  let readme = fs.readFileSync(readmePath, 'utf8').replace(/\r\n/g, '\n');
163
163
  const originalReadme = readme;
164
164
  readme = readme.replace(
165
- '- refresh token persistence: disabled by default (stateless mode)',
166
- '- refresh token persistence: enabled (`db-prisma` adapter)',
165
+ '- refresh token persistence: disabled by default (stateless mode; enable it later through a `db-adapter` provider + integration sync)',
166
+ '- refresh token persistence: enabled through the `db-adapter` capability (current provider: `db-prisma`)',
167
167
  );
168
168
  readme = readme.replace(
169
- /- to enable persistence later:[\s\S]*?2\. run `pnpm forgeon:sync-integrations` to auto-wire pair integrations\./m,
169
+ /- to enable persistence later:[\s\S]*?2\. run `pnpm forgeon:sync-integrations` to wire auth persistence to the active DB adapter implementation\./m,
170
170
  '- migration: `apps/api/prisma/migrations/0002_auth_refresh_token_hash`',
171
171
  );
172
172
  if (readme !== originalReadme) {
@@ -293,12 +293,12 @@ function run() {
293
293
 
294
294
  if (detected.jwtAuth && detected.dbPrisma) {
295
295
  summary.push({
296
- feature: 'jwt-auth + db-prisma',
296
+ feature: 'jwt-auth + db-adapter (current provider: db-prisma)',
297
297
  result: syncJwtDbPrisma({ rootDir, changedFiles }),
298
298
  });
299
299
  } else {
300
300
  summary.push({
301
- feature: 'jwt-auth + db-prisma',
301
+ feature: 'jwt-auth + db-adapter (current provider: db-prisma)',
302
302
  result: { applied: false, reason: 'required modules are not both installed' },
303
303
  });
304
304
  }
@@ -10,6 +10,11 @@ Included parts:
10
10
  - shared dictionaries in `resources/i18n/*` (`en` by default) used by both API and web
11
11
  - default namespaces: `common`, `errors`, `validation`, `ui`, `notifications`, `meta`
12
12
 
13
+ Important boundary:
14
+ - this module installs independently
15
+ - it is intentionally split across runtime, contracts, and web helper packages
16
+ - translation maintenance flows are part of the module contract, not ad-hoc project scripts
17
+
13
18
  Utility commands:
14
19
  - `pnpm i18n:sync` - regenerate `I18N_LOCALES` and `I18N_NAMESPACES` from `resources/i18n`.
15
20
  - `pnpm i18n:check` - verify generated contracts, JSON validity, and missing/extra keys vs fallback locale.
@@ -10,3 +10,9 @@
10
10
  - `i18n:sync` for locale/namespace contracts sync from `resources/i18n`
11
11
  - `i18n:check` for contract/json/key consistency checks
12
12
  - `i18n:types` for translation key type generation
13
+ - `i18n:add` for adding a new locale from the command line
14
+
15
+ Operational notes:
16
+
17
+ - this module owns the i18n helper commands
18
+ - it does not use integration sync groups today because its work is self-contained within the localization stack
@@ -1,3 +1,8 @@
1
1
  ## Status
2
2
 
3
3
  Implemented and applied by `create-forgeon add i18n`.
4
+
5
+ Notes:
6
+ - install is independent
7
+ - helper commands are part of the module surface
8
+ - the module is intentionally multi-package (`runtime + contracts + web`)
@@ -10,8 +10,10 @@ Implemented scope:
10
10
  - `JwtStrategy` + `JwtAuthGuard`
11
11
  - `authConfig` + `authEnvSchema` wiring through root `ConfigModule` validator chain
12
12
  3. DB behavior:
13
- - if supported DB adapter is present (`db-prisma`), refresh token hash persistence is auto-wired
14
- - if DB is missing/unsupported, module installs in stateless mode and prints red warning
13
+ - module install stays stateless by default
14
+ - refresh token hash persistence is enabled later through the `db-adapter` capability via `pnpm forgeon:sync-integrations`
15
+ - current DB adapter implementation for this integration is `db-prisma`
16
+ - if no DB adapter is installed, the module stays stateless and prints an optional integration warning with follow-up commands
15
17
  4. Module checks:
16
18
  - API probe endpoint: `GET /api/health/auth`
17
19
  - default web probe button + result block
@@ -3,5 +3,6 @@
3
3
  Status: implemented.
4
4
 
5
5
  Notes:
6
- - DB adapter auto-detection is currently implemented for `db-prisma`.
7
- - Unknown/missing DB adapter falls back to stateless refresh flow with explicit warning.
6
+ - The persistence boundary is `db-adapter`, not a hard dependency on one concrete DB module.
7
+ - The current DB adapter implementation for auth persistence is `db-prisma`.
8
+ - If no DB adapter is installed, jwt-auth stays in stateless refresh mode and surfaces an optional integration warning.
@@ -8,3 +8,7 @@ Included parts:
8
8
  - HTTP logging interceptor for request/response timing
9
9
  - env-driven logger config (`LOGGER_LEVEL`, `LOGGER_HTTP_ENABLED`, `LOGGER_REQUEST_ID_HEADER`)
10
10
 
11
+ Important boundary:
12
+ - this module installs independently
13
+ - it intentionally does not add a dedicated runtime probe
14
+ - verification is done through API process logs
@@ -9,3 +9,8 @@
9
9
  - Adds logger env keys to `apps/api/.env.example` and `infra/docker/.env.example`
10
10
  - Passes logger env keys through `infra/docker/compose.yml`
11
11
 
12
+ Intentional exception:
13
+
14
+ - no API `/api/health/*` probe is added
15
+ - no web diagnostics button is added
16
+ - this module is verified by observing structured logs
@@ -2,3 +2,6 @@
2
2
 
3
3
  Implemented and applied by `create-forgeon add logger`.
4
4
 
5
+ Notes:
6
+ - install is independent
7
+ - no dedicated probe is added by design
@@ -1,6 +1,7 @@
1
1
  ## Idea / Why
2
2
 
3
3
  This module adds a simple first-line request throttle to the API.
4
+ It installs independently and does not require another add-module to provide immediate value.
4
5
 
5
6
  It exists to reduce three common classes of problems:
6
7
 
@@ -7,4 +7,6 @@
7
7
  - `GET /api/health/rate-limit` probe endpoint
8
8
  - frontend probe button on the generated home page
9
9
 
10
+ This module installs independently. In the current scaffold it does not depend on, or require sync with, any other add-module.
11
+
10
12
  This module is API-first. It does not add shared contracts or a web package in v1 because the runtime value is in backend request throttling, not in reusable client-side types.
@@ -7,6 +7,8 @@ npx create-forgeon@latest add rate-limit
7
7
  pnpm install
8
8
  ```
9
9
 
10
+ This module installs independently. No follow-up integration sync is required.
11
+
10
12
  Verify:
11
13
 
12
14
  1. start the project
@@ -9,3 +9,8 @@
9
9
  - a frontend probe button that sends a valid permission header
10
10
 
11
11
  This module is backend-first. It does not include frontend route guards. If frontend access-control helpers are needed later, they should live in a separate module.
12
+
13
+ Optional integration:
14
+
15
+ - `jwt-auth` can extend demo JWT claims with RBAC permissions through `pnpm forgeon:sync-integrations`
16
+ - this module does not require `jwt-auth` to install or work for header-based/manual probe checks
@@ -18,3 +18,8 @@ Failure path:
18
18
 
19
19
  - denied access throws `403`
20
20
  - the existing Forgeon error envelope wraps it as `FORBIDDEN`
21
+
22
+ Integration note:
23
+
24
+ - if `jwt-auth` is also installed, the optional `auth-rbac-claims` integration can expose demo permissions inside JWT payloads
25
+ - that integration is explicit and is applied through `pnpm forgeon:sync-integrations`
@@ -17,3 +17,8 @@ Manual forbidden-path check:
17
17
 
18
18
  1. call `GET /api/health/rbac` without the `x-forgeon-permissions` header
19
19
  2. the request should return `403`
20
+
21
+ Optional follow-up:
22
+
23
+ 1. install `jwt-auth` if you want RBAC claims in demo JWT payloads
24
+ 2. run `pnpm forgeon:sync-integrations`
@@ -8,3 +8,7 @@ Included parts:
8
8
  - configurable docs path/title/version
9
9
  - `setupSwagger(...)` bootstrap helper
10
10
 
11
+ Important boundary:
12
+ - this module installs independently
13
+ - it wires only the OpenAPI runtime and bootstrap setup
14
+ - feature-specific Swagger decorators remain manual
@@ -11,3 +11,7 @@
11
11
  - `infra/docker/.env.example`
12
12
  - `infra/docker/compose.yml` (api service env passthrough)
13
13
 
14
+ Not included:
15
+
16
+ - no auto-patching of Swagger decorators into feature modules
17
+ - no implicit integration with `jwt-auth` or other add-modules
@@ -2,3 +2,6 @@
2
2
 
3
3
  Implemented and applied by `create-forgeon add swagger`.
4
4
 
5
+ Notes:
6
+ - install is independent
7
+ - feature-level decorators stay manual by design