create-forgeon 0.3.15 → 0.3.16

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 (41) hide show
  1. package/package.json +4 -2
  2. package/src/core/docs.test.mjs +79 -40
  3. package/src/core/scaffold.test.mjs +99 -0
  4. package/src/modules/db-prisma.mjs +23 -55
  5. package/src/modules/executor.test.mjs +132 -36
  6. package/src/modules/files-access.mjs +27 -98
  7. package/src/modules/files-image.mjs +26 -100
  8. package/src/modules/files-quotas.mjs +67 -87
  9. package/src/modules/files.mjs +35 -104
  10. package/src/modules/i18n.mjs +17 -121
  11. package/src/modules/idempotency.test.mjs +174 -0
  12. package/src/modules/jwt-auth.mjs +90 -209
  13. package/src/modules/logger.mjs +0 -9
  14. package/src/modules/probes.test.mjs +202 -0
  15. package/src/modules/queue.mjs +325 -443
  16. package/src/modules/rate-limit.mjs +22 -66
  17. package/src/modules/rbac.mjs +27 -67
  18. package/src/modules/scheduler.mjs +44 -167
  19. package/src/modules/shared/nest-runtime-wiring.mjs +110 -0
  20. package/src/modules/shared/probes.mjs +235 -0
  21. package/src/modules/sync-integrations.mjs +54 -21
  22. package/src/modules/sync-integrations.test.mjs +220 -0
  23. package/src/run-add-module.test.mjs +153 -0
  24. package/templates/base/README.md +7 -55
  25. package/templates/base/apps/web/src/App.tsx +70 -42
  26. package/templates/base/apps/web/src/probes.ts +61 -0
  27. package/templates/base/apps/web/src/styles.css +86 -25
  28. package/templates/base/package.json +21 -15
  29. package/templates/base/scripts/forgeon-sync-integrations.mjs +55 -11
  30. package/templates/module-presets/files-quotas/packages/files-quotas/src/forgeon-files-quotas.module.ts +12 -4
  31. package/templates/module-presets/i18n/apps/web/src/App.tsx +68 -41
  32. package/templates/module-presets/logger/packages/logger/src/index.ts +0 -1
  33. package/templates/base/docs/AI/ARCHITECTURE.md +0 -85
  34. package/templates/base/docs/AI/MODULE_CHECKS.md +0 -28
  35. package/templates/base/docs/AI/MODULE_SPEC.md +0 -77
  36. package/templates/base/docs/AI/PROJECT.md +0 -43
  37. package/templates/base/docs/AI/ROADMAP.md +0 -171
  38. package/templates/base/docs/AI/TASKS.md +0 -60
  39. package/templates/base/docs/AI/VALIDATION.md +0 -31
  40. package/templates/base/docs/README.md +0 -18
  41. package/templates/module-presets/logger/packages/logger/src/http-logging.interceptor.ts +0 -94
@@ -1,11 +1,19 @@
1
- import { Module } from '@nestjs/common';
1
+ import { Module } from '@nestjs/common';
2
2
  import { ForgeonFilesModule } from '@forgeon/files';
3
3
  import { FilesQuotasConfigModule } from './files-quotas-config.module';
4
4
  import { FilesQuotasService } from './files-quotas.service';
5
5
 
6
+ const FORGEON_FILES_UPLOAD_QUOTA_SERVICE = 'FORGEON_FILES_UPLOAD_QUOTA_SERVICE';
7
+
6
8
  @Module({
7
9
  imports: [ForgeonFilesModule, FilesQuotasConfigModule],
8
- providers: [FilesQuotasService],
9
- exports: [FilesQuotasConfigModule, FilesQuotasService],
10
+ providers: [
11
+ FilesQuotasService,
12
+ {
13
+ provide: FORGEON_FILES_UPLOAD_QUOTA_SERVICE,
14
+ useExisting: FilesQuotasService,
15
+ },
16
+ ],
17
+ exports: [FilesQuotasConfigModule, FilesQuotasService, FORGEON_FILES_UPLOAD_QUOTA_SERVICE],
10
18
  })
11
- export class ForgeonFilesQuotasModule {}
19
+ export class ForgeonFilesQuotasModule {}
@@ -1,23 +1,28 @@
1
- import { useState } from 'react';
1
+ import { useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import i18n from './i18n';
4
4
  import * as i18nWeb from '@forgeon/i18n-web';
5
5
  import type { I18nLocale } from '@forgeon/i18n-web';
6
+ import { probeDefinitions, type ProbeDefinition, type ProbeResult } from './probes';
6
7
  import './styles.css';
7
8
 
8
- type ProbeResult = {
9
- statusCode: number;
10
- body: unknown;
9
+ type ProbeState = {
10
+ result: ProbeResult | null;
11
+ error: string | null;
12
+ loading: boolean;
13
+ };
14
+
15
+ const emptyProbeState: ProbeState = {
16
+ result: null,
17
+ error: null,
18
+ loading: false,
11
19
  };
12
20
 
13
21
  export default function App() {
14
22
  const { t } = useTranslation(['ui']);
15
23
  const { I18N_LOCALES, getInitialLocale, persistLocale, toLangQuery } = i18nWeb;
16
24
  const [locale, setLocale] = useState<I18nLocale>(getInitialLocale);
17
- const [healthResult, setHealthResult] = useState<ProbeResult | null>(null);
18
- const [errorProbeResult, setErrorProbeResult] = useState<ProbeResult | null>(null);
19
- const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);
20
- const [networkError, setNetworkError] = useState<string | null>(null);
25
+ const [probeState, setProbeState] = useState<Record<string, ProbeState>>({});
21
26
 
22
27
  const changeLocale = (nextLocale: I18nLocale) => {
23
28
  setLocale(nextLocale);
@@ -25,12 +30,12 @@ export default function App() {
25
30
  void i18n.changeLanguage(nextLocale);
26
31
  };
27
32
 
28
- const requestProbe = async (path: string, init?: RequestInit): Promise<ProbeResult> => {
29
- const response = await fetch(`/api${path}${toLangQuery(locale)}`, {
30
- ...(init ?? {}),
33
+ const requestProbe = async (probe: ProbeDefinition): Promise<ProbeResult> => {
34
+ const response = await fetch(`/api${probe.path}${toLangQuery(locale)}`, {
35
+ ...(probe.request ?? {}),
31
36
  cache: 'no-store',
32
37
  headers: {
33
- ...(init?.headers ?? {}),
38
+ ...(probe.request?.headers ?? {}),
34
39
  'Accept-Language': locale,
35
40
  },
36
41
  });
@@ -48,27 +53,38 @@ export default function App() {
48
53
  };
49
54
  };
50
55
 
51
- const runProbe = async (
52
- setter: (value: ProbeResult | null) => void,
53
- path: string,
54
- init?: RequestInit,
55
- ) => {
56
- setNetworkError(null);
56
+ const runProbe = async (probe: ProbeDefinition) => {
57
+ setProbeState((current) => ({
58
+ ...current,
59
+ [probe.id]: {
60
+ ...(current[probe.id] ?? emptyProbeState),
61
+ error: null,
62
+ loading: true,
63
+ },
64
+ }));
65
+
57
66
  try {
58
- const result = await requestProbe(path, init);
59
- setter(result);
67
+ const result = await requestProbe(probe);
68
+ setProbeState((current) => ({
69
+ ...current,
70
+ [probe.id]: {
71
+ result,
72
+ error: null,
73
+ loading: false,
74
+ },
75
+ }));
60
76
  } catch (err) {
61
- setNetworkError(err instanceof Error ? err.message : 'Unknown error');
77
+ setProbeState((current) => ({
78
+ ...current,
79
+ [probe.id]: {
80
+ result: current[probe.id]?.result ?? null,
81
+ error: err instanceof Error ? err.message : 'Unknown error',
82
+ loading: false,
83
+ },
84
+ }));
62
85
  }
63
86
  };
64
87
 
65
- const renderResult = (title: string, result: ProbeResult | null) => (
66
- <section>
67
- <h3>{title}</h3>
68
- {result ? <pre>{JSON.stringify(result, null, 2)}</pre> : null}
69
- </section>
70
- );
71
-
72
88
  return (
73
89
  <main className="page">
74
90
  <h1>Forgeon Fullstack Scaffold</h1>
@@ -85,19 +101,30 @@ export default function App() {
85
101
  </option>
86
102
  ))}
87
103
  </select>
88
- <div className="actions">
89
- <button onClick={() => runProbe(setHealthResult, '/health')}>Check API health</button>
90
- <button onClick={() => runProbe(setErrorProbeResult, '/health/error')}>
91
- Check error envelope
92
- </button>
93
- <button onClick={() => runProbe(setValidationProbeResult, '/health/validation')}>
94
- Check validation (expect 400)
95
- </button>
104
+ <div id="probes" className="probes">
105
+ {probeDefinitions.map((probe) => {
106
+ const current = probeState[probe.id] ?? emptyProbeState;
107
+
108
+ return (
109
+ <section key={probe.id} className="probe">
110
+ <div className="probe-header">
111
+ <h2>{probe.title}</h2>
112
+ <button type="button" onClick={() => runProbe(probe)} disabled={current.loading}>
113
+ {current.loading ? 'Running...' : probe.buttonLabel}
114
+ </button>
115
+ </div>
116
+ <div className="probe-output">
117
+ <h3>{probe.resultTitle}</h3>
118
+ {current.error ? <p className="error">{current.error}</p> : null}
119
+ {current.result ? <pre>{JSON.stringify(current.result, null, 2)}</pre> : null}
120
+ {!current.error && !current.result ? (
121
+ <p className="placeholder">No probe result yet.</p>
122
+ ) : null}
123
+ </div>
124
+ </section>
125
+ );
126
+ })}
96
127
  </div>
97
- {renderResult('Health response', healthResult)}
98
- {renderResult('Error probe response', errorProbeResult)}
99
- {renderResult('Validation probe response', validationProbeResult)}
100
- {networkError ? <p className="error">{networkError}</p> : null}
101
128
  </main>
102
129
  );
103
- }
130
+ }
@@ -4,6 +4,5 @@ export * from './logger-config.service';
4
4
  export * from './logger-config.module';
5
5
  export * from './forgeon-logger.service';
6
6
  export * from './http-logging.middleware';
7
- export * from './http-logging.interceptor';
8
7
  export * from './request-id.middleware';
9
8
  export * from './forgeon-logger.module';
@@ -1,85 +0,0 @@
1
- # ARCHITECTURE
2
-
3
- ## Monorepo Layout
4
-
5
- - `apps/*` - deployable apps
6
- - `packages/*` - reusable modules/presets
7
- - `infra/*` - runtime infrastructure
8
- - `resources/*` - static assets (translations)
9
-
10
- Canonical stack is fixed in this stage:
11
- - NestJS + React + Prisma/Postgres + Docker
12
- - Proxy preset can be `caddy`, `nginx`, or `none`
13
-
14
- ## Environment Flags
15
-
16
- - `PORT` - API port (default 3000)
17
- - `API_PREFIX` - global API prefix (default `api`)
18
- - `DATABASE_URL` - Prisma Postgres connection
19
- - `I18N_DEFAULT_LANG` - default language
20
- - `I18N_FALLBACK_LANG` - fallback language
21
-
22
- ## Config Strategy
23
-
24
- - `@forgeon/core` owns base runtime config, global error envelope/filter, and validation pipe defaults.
25
- - Core config is validated with Zod and exposed through typed accessors.
26
- - Add-modules own and validate only their module-specific env keys.
27
- - i18n is an add-module; when installed, it uses its own env keys.
28
-
29
- ## Default DB Stack
30
-
31
- Current default is Prisma + Postgres.
32
-
33
- - Prisma schema and migrations live in `apps/api/prisma`
34
- - DB access is encapsulated via `DbPrismaModule` in `@forgeon/db-prisma`
35
- - `db-prisma` is treated as default-applied behavior in scaffold generation.
36
- - Future direction: this default DB layer may be extracted to an explicit add-module/preset and optionally controlled by a CLI flag.
37
- - Additional DB presets are out of scope for the current milestone.
38
-
39
- ## Module Strategy
40
-
41
- Reusable features should be added as fullstack add-modules:
42
-
43
- - `contracts` package (shared DTO/routes/errors)
44
- - `api` package (NestJS integration)
45
- - `web` package (React integration)
46
-
47
- Reference: `docs/AI/MODULE_SPEC.md`.
48
-
49
- ## Integration Sync Strategy
50
-
51
- - Integration orchestration is a default project toolchain command:
52
- - `pnpm forgeon:sync-integrations`
53
- - Purpose:
54
- - keep add-modules composable when installed in arbitrary order;
55
- - apply module-to-module integration patches idempotently.
56
- - Rule:
57
- - each add-module patches only itself;
58
- - cross-module changes are allowed only in integration sync rules.
59
- - Current integration:
60
- - `jwt-auth + db-adapter` (current provider: `db-prisma`; persistent refresh-token store wiring + schema/migration sync).
61
- - Pair sync is explicit (opt-in), not automatic after `add`.
62
- - Run `pnpm forgeon:sync-integrations` when you want to apply module-pair integrations.
63
- - Swagger auth decorators are intentionally not auto-patched.
64
- - Future option: this may return as an explicit optional command (not default automatic behavior).
65
-
66
- ## TypeScript Module Format Policy
67
-
68
- - `apps/api`, `packages/core`, and backend runtime packages use Node-oriented config:
69
- - `tsconfig.base.node.json`
70
- - Frontend-consumed shared packages (especially contracts/web helpers) use ESM config:
71
- - `tsconfig.base.esm.json`
72
- - Contracts packages are ESM-first and imported via package entrypoints only.
73
- - Cross-package imports from `/src/*` are disallowed.
74
-
75
- ## Error Handling Strategy
76
-
77
- - `@forgeon/core` owns the global HTTP error envelope and filter.
78
- - API apps import `CoreErrorsModule` and register `CoreExceptionFilter` globally.
79
- - Envelope fields:
80
- - `error.code`
81
- - `error.message`
82
- - `error.status`
83
- - `error.details` (optional)
84
- - `error.requestId` (optional)
85
- - `error.timestamp`
@@ -1,28 +0,0 @@
1
- # MODULE CHECKS
2
-
3
- ## Purpose
4
-
5
- Define mandatory runtime verification hooks for Forgeon modules.
6
-
7
- If a module can be validated through a safe API call, it must provide:
8
-
9
- 1. A probe endpoint in API (`/api/health/*`).
10
- 2. A probe trigger on default web page (`apps/web/src/App.tsx`).
11
- 3. A visible result block in UI with HTTP status and JSON body.
12
-
13
- ## Current Baseline Probes
14
-
15
- - `core-errors`: `GET /api/health/error` (returns error envelope, expected `409`)
16
- - `core-validation`: `GET /api/health/validation` without `value` (expected `400`)
17
- - `db-prisma` (when installed): `POST /api/health/db` (creates probe user and returns it, expected `201`)
18
-
19
- ## Rules For Future Modules
20
-
21
- - Probe path should be explicit and feature-scoped (`/api/health/<feature>`).
22
- - Probe must be deterministic and documented (expected status + payload shape).
23
- - If probe writes data, it must use clearly marked probe/test records.
24
- - Probe should not require hidden setup beyond documented env/dependencies.
25
- - `create-forgeon add <module>` must wire both API probe and web probe UI when feasible.
26
- - Web probes should be appended to the existing probe UI structure in `apps/web/src/App.tsx`:
27
- - add new action button at the end of `<div className="actions">`
28
- - add new result block before the `networkError` render block
@@ -1,77 +0,0 @@
1
- # MODULE SPEC
2
-
3
- ## Goal
4
-
5
- Define one repeatable fullstack pattern for Forgeon add-modules.
6
-
7
- Most feature modules should be split into:
8
-
9
- 1. `@forgeon/<feature>-contracts`
10
- 2. `@forgeon/<feature>-api`
11
- 3. `@forgeon/<feature>-web`
12
-
13
- Exception:
14
-
15
- - backend-only infrastructure or security modules may use a single runtime package (`@forgeon/<feature>`) when shared contracts and a dedicated web package add no real value.
16
-
17
- ## 1) Contracts Package
18
-
19
- Single source of truth shared by backend and frontend.
20
-
21
- Must contain:
22
-
23
- - DTO/request/response types
24
- - route constants (`API.<feature>.*`)
25
- - error codes (`<FEATURE>_*`)
26
- - shared constants (header/cookie names)
27
- - package entrypoint exports only (`@forgeon/<feature>-contracts`)
28
-
29
- Should contain:
30
-
31
- - zod schemas + inferred TS types
32
-
33
- Build/runtime rules:
34
-
35
- - ESM-first package (`"type": "module"`, `module: "ESNext"`)
36
- - extends `tsconfig.base.esm.json`
37
- - no NestJS or browser-only runtime dependencies
38
- - no imports from sibling package `/src/*` paths
39
-
40
- ## 2) API Package
41
-
42
- NestJS module integrating contracts into backend runtime.
43
-
44
- Must contain:
45
-
46
- - module/service/controller
47
- - guards/strategies (if auth/security related)
48
- - config keys
49
- - minimal e2e test path
50
- - integration with `@forgeon/core` errors/logging
51
-
52
- ## 3) Web Package
53
-
54
- React integration layer for the same feature.
55
-
56
- Must contain:
57
-
58
- - provider/hooks/store
59
- - route guard (if feature requires auth/access)
60
- - API client helpers using contracts route constants/types
61
- - token/header/cookie wiring where relevant
62
-
63
- ## Acceptance Criteria
64
-
65
- - No duplicate route strings across api/web.
66
- - No duplicate error-code enums across api/web.
67
- - Contracts package can be imported from both sides without circular dependencies.
68
- - Contracts package exports are stable from `dist/index` entrypoint.
69
- - Module has docs under `docs/AI/MODULES/<module-id>.md`.
70
- - Module docs must explain: why it exists, what it adds, how it works, how to use it, how to configure it, and current operational limits.
71
- - If module behavior can be runtime-checked, it also includes API+Web probe hooks (see `docs/AI/MODULE_CHECKS.md`).
72
- - If i18n is enabled, module-specific namespaces must be created and wired for both API and web.
73
- - If module is added before i18n, namespace templates must still be prepared and applied when i18n is installed later.
74
- - Module integration with other modules must be represented as idempotent sync rules and runnable via `pnpm forgeon:sync-integrations`.
75
- - `create-forgeon add <module-id>` does not auto-apply pair integrations.
76
- - Pair integrations are applied explicitly via `pnpm forgeon:sync-integrations`.
77
- - Modules must not assume `db-prisma` is present unless they explicitly require it; DB integrations should be optional and synced when DB is added later.
@@ -1,43 +0,0 @@
1
- # PROJECT
2
-
3
- ## What This Repository Is
4
-
5
- A canonical fullstack monorepo scaffold intended to be reused as a project starter.
6
-
7
- ## Structure
8
-
9
- - `apps/api` - NestJS backend
10
- - `apps/web` - React frontend (fixed stack)
11
- - `packages/core` - shared backend core package (`core-config`, `core-errors`, `core-validation`)
12
- - `packages/db-prisma` - reusable Prisma/Postgres module (`DbPrismaModule`, `PrismaService`, config)
13
- - `packages/i18n` - reusable nestjs-i18n integration package
14
- - `infra` - Docker Compose + proxy preset (`caddy|nginx|none`)
15
- - `resources/i18n` - translation dictionaries
16
- - `docs` - documentation, AI prompts, and module contracts
17
-
18
- ## Run Modes
19
-
20
- ### Dev mode
21
-
22
- ```bash
23
- pnpm install
24
- pnpm dev
25
- ```
26
-
27
- ### Docker mode
28
-
29
- ```bash
30
- docker compose --env-file infra/docker/.env.example -f infra/docker/compose.yml up --build
31
- ```
32
-
33
- The API uses Prisma and expects `DATABASE_URL` from env.
34
-
35
- If proxy preset is `none`, API is directly available on `localhost:3000`.
36
-
37
- ## Error Handling
38
-
39
- `core-errors` is enabled by default.
40
-
41
- - `CoreErrorsModule` is imported in `apps/api/src/app.module.ts`.
42
- - `CoreExceptionFilter` is registered globally in `apps/api/src/main.ts`.
43
- - Throw standard Nest exceptions from controllers/services; the filter converts them to a stable envelope.
@@ -1,171 +0,0 @@
1
- # ROADMAP
2
-
3
- This is a living plan. Scope and priorities may change.
4
-
5
- ## Current Foundation (Implemented)
6
-
7
- - [x] Canonical scaffold: NestJS API + React web + Docker (+ default-on `db-prisma` module)
8
- - [x] Proxy preset selection: `caddy | nginx | none`
9
- - [x] `@forgeon/core`:
10
- - [x] `core-config` (typed env config + validation)
11
- - [x] `core-errors` (global envelope + exception filter)
12
- - [x] `core-validation` (global validation pipe)
13
- - [x] `@forgeon/db-prisma` as default-applied DB module
14
- - [x] i18n add-module baseline:
15
- - [x] `@forgeon/i18n`, `@forgeon/i18n-contracts`, `@forgeon/i18n-web`
16
- - [x] shared dictionaries in `resources/i18n/*`
17
- - [x] tooling: `i18n:sync`, `i18n:check`, `i18n:types`, `i18n:add`
18
- - [x] module diagnostics probes pattern (`/api/health/*` + web test buttons)
19
-
20
- ## Standards (Accepted)
21
-
22
- - [x] `*-contracts` and `*-web` packages are ESM-first
23
- - [x] API runtime modules use Node-oriented TS config
24
- - [x] no cross-package imports via `/src/*`; only package entrypoints
25
-
26
- ## Updated Priority Backlog
27
-
28
- ### P0 (Immediate Must-Have)
29
-
30
- - [ ] `logger`
31
- - [ ] canonical logger module
32
- - [ ] requestId / correlationId propagation
33
- - [ ] structured log conventions
34
-
35
- - [ ] `openapi / swagger`
36
- - [ ] env toggle: `SWAGGER_ENABLED`
37
- - [ ] standard setup
38
- - [ ] bearer integration hook for jwt-auth
39
- - [ ] `/docs` route
40
-
41
- - [ ] `jwt-auth`
42
- - [ ] module split: contracts/api/web
43
- - [ ] access + refresh baseline
44
- - [ ] guards/strategy integration
45
-
46
- - [ ] `rbac / permissions`
47
- - [ ] decorators: `@Roles()`, `@Permissions()`
48
- - [ ] guard + policy helper
49
- - [ ] contracts: `Role`, `Permission`
50
- - [ ] integration with jwt-auth claims
51
-
52
- - [ ] `redis/queue foundation`
53
- - [ ] base Redis config/service
54
- - [ ] queue baseline (BullMQ or equivalent)
55
- - [ ] retry and dead-letter conventions
56
-
57
- - [ ] `rate-limit`
58
- - [ ] Nest Throttler add-module
59
- - [ ] policies: route / user / ip
60
- - [ ] error code: `TOO_MANY_REQUESTS`
61
- - [ ] reverse-proxy-aware mode (`trust proxy`)
62
-
63
- - [ ] `files` (upload + storage)
64
- - [ ] upload endpoints + DTO + guards
65
- - [ ] storage presets: local + S3-compatible (MinIO/R2)
66
- - [ ] MIME/size validation
67
- - [ ] optional image processing subpackage (`sharp`)
68
- - [ ] error codes: `UPLOAD_INVALID_TYPE`, `UPLOAD_TOO_LARGE`, `UPLOAD_QUOTA`
69
-
70
- ### P1 (Strongly Recommended)
71
-
72
- - [ ] `testing baseline`
73
- - [ ] unit + e2e presets
74
- - [ ] test helpers for add-modules
75
- - [ ] smoke test template for generated project
76
-
77
- - [ ] `CI quality gates`
78
- - [ ] `typecheck`, `lint`, `test`, docker build smoke
79
- - [ ] release gate checklist
80
-
81
- - [ ] `cache` (Redis)
82
- - [ ] CacheModule preset
83
- - [ ] key naming conventions
84
- - [ ] shared wrapper/service
85
-
86
- - [ ] `scheduler`
87
- - [ ] `@nestjs/schedule` integration
88
- - [ ] task template
89
- - [ ] optional distributed lock (Redis)
90
-
91
- - [ ] `mail`
92
- - [ ] at least one provider preset (SMTP/Resend/SendGrid)
93
- - [ ] templates: verify email, reset password
94
- - [ ] optional outbox with queue
95
-
96
- - [ ] workspace `eslint/prettier` config package
97
-
98
- ### P2 (Later)
99
-
100
- - [ ] frontend `http-client` module
101
- - [ ] frontend UI kit package
102
- - [ ] migrate reusable parts from `eso-dt` (when available)
103
- - [ ] extend missing primitives
104
- - [ ] `realtime` (ws)
105
- - [ ] gateway baseline
106
- - [ ] jwt auth for ws
107
- - [ ] rooms + basic events
108
- - [ ] `webhooks` module (subject to scope validation)
109
- - [ ] signed inbound verify (HMAC)
110
- - [ ] signed outbound sender
111
- - [ ] replay protection (timestamp/nonce)
112
-
113
- ## Execution Plan (3 Sprints)
114
-
115
- ### Sprint 1: Platform Baseline and Security Start
116
-
117
- Scope:
118
- - `logger`
119
- - `openapi/swagger`
120
- - `jwt-auth`
121
- - `testing baseline`
122
- - `CI quality gates`
123
-
124
- Definition of Done:
125
- - add-modules install cleanly via `create-forgeon add <module>`
126
- - local dev (`pnpm dev`) and docker build both pass on fresh generated project
127
- - each module has probe endpoint and web probe UI hook when applicable
128
- - docs updated in both root and template docs
129
-
130
- ### Sprint 2: Authorization and Traffic Control
131
-
132
- Scope:
133
- - `rbac/permissions`
134
- - `redis/queue foundation`
135
- - `rate-limit`
136
- - `files`
137
- - `cache`
138
-
139
- Definition of Done:
140
- - claims/roles/permissions flow validated end-to-end (api + web contracts)
141
- - rate-limit and files include standardized error codes and envelope mapping
142
- - Redis-backed modules run in docker profile with documented env keys
143
- - at least one e2e happy-path per module
144
-
145
- ### Sprint 3: Async Integrations and Frontend Foundation
146
-
147
- Scope:
148
- - `scheduler`
149
- - `mail`
150
- - workspace `eslint/prettier` config package
151
- - frontend `http-client`
152
-
153
- Definition of Done:
154
- - queue/scheduler/mail basic scenarios work in local + docker
155
- - frontend http-client consumes api contracts with typed errors
156
- - lint/typecheck/test/build pass through CI gate preset
157
- - docs include migration notes and extension points
158
-
159
- ## Explicit Dependencies and Order Constraints
160
-
161
- - `rbac` depends on `jwt-auth`
162
- - `rate-limit` should follow Redis/queue foundation for scalable mode
163
- - `mail` should reuse queue foundation where possible
164
- - `openapi` is most useful before/with `jwt-auth` and `http-client`
165
- - `realtime` and `webhooks` stay post-MVP unless a concrete use-case appears
166
-
167
- ## i18n Policy For Add-Modules
168
-
169
- - [ ] each add-module that introduces user-facing text defines its own namespace templates
170
- - [ ] if i18n is already enabled, namespace files are added during module installation
171
- - [ ] if module is installed first and i18n later, namespaces are merged during i18n installation
@@ -1,60 +0,0 @@
1
- # TASKS
2
-
3
- ## Feature Discovery Matrix
4
-
5
- ```text
6
- Scan this monorepo and build a backend feature matrix by app/package.
7
- Use only evidence from code and dependencies.
8
- Output:
9
- 1) taxonomy by category
10
- 2) feature comparison table
11
- 3) common core
12
- 4) unique features
13
- 5) architectural inconsistencies
14
- Include file references for every feature.
15
- ```
16
-
17
- ## Add Module Package
18
-
19
- ```text
20
- Create a new reusable package under packages/ for <feature-name>.
21
- Requirements:
22
- - minimal API
23
- - NestJS-compatible module
24
- - docs in package README
25
- - wire into apps/api conditionally via env flag
26
- - keep backward compatibility
27
- ```
28
-
29
- ## Refactor Core
30
-
31
- ```text
32
- Move shared backend logic from apps/api into packages/core.
33
- Do not change behavior.
34
- Update imports, package dependencies, and docs.
35
- Run build checks and show changed files.
36
- ```
37
-
38
- ## Generate Preset
39
-
40
- ```text
41
- Create or update create-forgeon preset flow:
42
- - keep canonical stack fixed: NestJS + React + Prisma/Postgres + Docker
43
- - allow only runtime proxy choice: caddy/nginx/none
44
- - update generated docs fragments
45
- - update docs/AI/ARCHITECTURE.md and docs/AI/MODULE_SPEC.md when scope changes
46
- ```
47
-
48
- ## Add Fullstack Module
49
-
50
- ```text
51
- Implement `create-forgeon add <module-id>` for a fullstack feature.
52
- Requirements:
53
- - split module into contracts/api/web packages
54
- - contracts is source of truth for routes, DTOs, errors
55
- - if feasible, add module probe hooks in API (`/api/health/*`) and web diagnostics UI
56
- - if i18n is enabled, add module namespace files and wire them for both API and web
57
- - add docs note under docs/AI/MODULES/<module-id>.md
58
- - keep backward compatibility
59
- ```
60
-
@@ -1,31 +0,0 @@
1
- # VALIDATION
2
-
3
- ## Backend DTO Validation Standard
4
-
5
- - Use `class-validator` decorators on DTO classes.
6
- - Global validation is centralized in `@forgeon/core` via `createValidationPipe()`.
7
- - Current defaults:
8
- - `whitelist: true`
9
- - `transform: true`
10
- - `validationError.target: false`
11
- - `validationError.value: false`
12
- - Keep DTO validation messages stable and explicit.
13
- - For required values, use a consistent key or message pattern.
14
-
15
- ## Config Validation Standard
16
-
17
- - Use Zod for env/config validation.
18
- - Core env is validated by `@forgeon/core` (`core-config`).
19
- - Each add-module validates only its own env keys with its own Zod schema.
20
- - Avoid one global env schema for all modules; keep schemas modular.
21
-
22
- ## Error Details for Validation
23
-
24
- - Error envelope stays consistent:
25
- - `error.code`
26
- - `error.message`
27
- - `error.status`
28
- - optional `error.details`
29
- - Validation details should be structured (not `any`).
30
- - `core-validation` formats validation details as:
31
- - `{ field?: string, message: string }[]`