create-forgeon 0.1.24 → 0.1.26
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.
- package/package.json +1 -1
- package/src/core/docs.test.mjs +8 -6
- package/src/modules/executor.test.mjs +8 -0
- package/src/modules/i18n.mjs +19 -1
- package/src/presets/i18n.mjs +76 -34
- package/templates/base/apps/api/Dockerfile +7 -4
- package/templates/base/apps/api/package.json +3 -2
- package/templates/base/apps/api/src/app.module.ts +4 -4
- package/templates/base/apps/api/src/health/health.controller.ts +41 -8
- package/templates/base/apps/api/src/main.ts +6 -8
- package/templates/base/apps/web/src/App.tsx +76 -35
- package/templates/base/apps/web/src/styles.css +29 -17
- package/templates/base/docs/AI/ARCHITECTURE.md +48 -32
- package/templates/base/docs/AI/MODULE_CHECKS.md +25 -0
- package/templates/base/docs/AI/MODULE_SPEC.md +1 -0
- package/templates/base/docs/AI/PROJECT.md +27 -16
- package/templates/base/docs/AI/TASKS.md +8 -7
- package/templates/base/docs/AI/VALIDATION.md +6 -1
- package/templates/base/docs/README.md +1 -0
- package/templates/base/packages/core/README.md +1 -0
- package/templates/base/packages/core/src/errors/core-exception.filter.ts +11 -3
- package/templates/base/packages/core/src/index.ts +1 -0
- package/templates/base/packages/core/src/validation/core-validation.pipe.ts +56 -0
- package/templates/base/packages/core/src/validation/index.ts +1 -0
- package/templates/base/packages/db-prisma/README.md +9 -0
- package/templates/base/packages/db-prisma/package.json +20 -0
- package/templates/base/packages/db-prisma/src/db-prisma-config.loader.ts +18 -0
- package/templates/base/packages/db-prisma/src/db-prisma-config.service.ts +12 -0
- package/templates/base/packages/db-prisma/src/db-prisma-env.schema.ts +17 -0
- package/templates/base/packages/db-prisma/src/db-prisma.module.ts +13 -0
- package/templates/base/packages/db-prisma/src/index.ts +5 -0
- package/templates/base/{apps/api/src/prisma → packages/db-prisma/src}/prisma.service.ts +24 -27
- package/templates/base/packages/db-prisma/tsconfig.json +9 -0
- package/templates/base/resources/i18n/en/common.json +3 -0
- package/templates/base/resources/i18n/uk/common.json +3 -0
- package/templates/docs-fragments/AI_ARCHITECTURE/20_env_base.md +1 -1
- package/templates/docs-fragments/AI_ARCHITECTURE/30_default_db.md +9 -7
- package/templates/docs-fragments/AI_ARCHITECTURE/32_scope_freeze.md +6 -5
- package/templates/docs-fragments/AI_PROJECT/20_structure_base.md +2 -1
- package/templates/module-presets/i18n/apps/web/src/App.tsx +63 -22
- package/templates/base/apps/api/src/prisma/prisma.module.ts +0 -9
|
@@ -1,11 +1,15 @@
|
|
|
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)
|
|
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`
|
|
9
13
|
|
|
10
14
|
## Environment Flags
|
|
11
15
|
|
|
@@ -17,36 +21,48 @@
|
|
|
17
21
|
|
|
18
22
|
## Config Strategy
|
|
19
23
|
|
|
20
|
-
- `@forgeon/core` owns base runtime config
|
|
24
|
+
- `@forgeon/core` owns base runtime config, global error envelope/filter, and validation pipe defaults.
|
|
21
25
|
- Core config is validated with Zod and exposed through typed accessors.
|
|
22
26
|
- Add-modules own and validate only their module-specific env keys.
|
|
23
27
|
- i18n is an add-module; when installed, it uses its own env keys.
|
|
24
|
-
|
|
25
|
-
## Default DB Stack
|
|
26
|
-
|
|
27
|
-
Current default is Prisma + Postgres.
|
|
28
|
-
|
|
29
|
-
- Prisma schema and migrations live in `apps/api/prisma`
|
|
30
|
-
- DB access is encapsulated via `PrismaModule` (`apps/api/src/prisma`)
|
|
31
|
-
|
|
32
|
-
## Future DB Presets (Not Implemented Yet)
|
|
33
|
-
|
|
34
|
-
A future preset can switch DB by:
|
|
35
|
-
1. Replacing `PrismaModule` with another DB module package (for example Mongo package).
|
|
36
|
-
2. Updating `infra/docker/compose.yml` DB service.
|
|
37
|
-
3. Updating `DATABASE_URL` and related env keys.
|
|
38
|
-
4. Keeping app-level services dependent only on repository/data-access abstractions.
|
|
39
|
-
|
|
40
|
-
## Future Feature Modules
|
|
41
28
|
|
|
42
|
-
|
|
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
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
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`.
|
|
46
48
|
|
|
47
49
|
## TypeScript Module Format Policy
|
|
48
50
|
|
|
49
|
-
- `apps/api`, `packages/core`, and backend runtime packages use
|
|
50
|
-
-
|
|
51
|
-
-
|
|
51
|
+
- `apps/api`, `packages/core`, and backend runtime packages use Node-oriented config:
|
|
52
|
+
- `tsconfig.base.node.json`
|
|
53
|
+
- Frontend-consumed shared packages (especially contracts/web helpers) use ESM config:
|
|
54
|
+
- `tsconfig.base.esm.json`
|
|
55
|
+
- Contracts packages are ESM-first and imported via package entrypoints only.
|
|
52
56
|
- Cross-package imports from `/src/*` are disallowed.
|
|
57
|
+
|
|
58
|
+
## Error Handling Strategy
|
|
59
|
+
|
|
60
|
+
- `@forgeon/core` owns the global HTTP error envelope and filter.
|
|
61
|
+
- API apps import `CoreErrorsModule` and register `CoreExceptionFilter` globally.
|
|
62
|
+
- Envelope fields:
|
|
63
|
+
- `error.code`
|
|
64
|
+
- `error.message`
|
|
65
|
+
- `error.status`
|
|
66
|
+
- `error.details` (optional)
|
|
67
|
+
- `error.requestId` (optional)
|
|
68
|
+
- `error.timestamp`
|
|
@@ -0,0 +1,25 @@
|
|
|
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`: `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.
|
|
@@ -63,3 +63,4 @@ Must contain:
|
|
|
63
63
|
- Contracts package can be imported from both sides without circular dependencies.
|
|
64
64
|
- Contracts package exports are stable from `dist/index` entrypoint.
|
|
65
65
|
- Module has docs under `docs/AI/MODULES/<module-id>.md`.
|
|
66
|
+
- If module behavior can be runtime-checked, it also includes API+Web probe hooks (see `docs/AI/MODULE_CHECKS.md`).
|
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
A canonical fullstack monorepo scaffold intended to be reused as a project starter.
|
|
6
6
|
|
|
7
|
-
## Structure
|
|
8
|
-
|
|
9
|
-
- `apps/api` - NestJS backend
|
|
10
|
-
- `apps/web` - frontend
|
|
11
|
-
- `packages/core` - shared backend core package
|
|
12
|
-
- `packages/
|
|
13
|
-
- `
|
|
14
|
-
- `
|
|
15
|
-
- `
|
|
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
|
|
16
17
|
|
|
17
18
|
## Run Modes
|
|
18
19
|
|
|
@@ -23,10 +24,20 @@ pnpm install
|
|
|
23
24
|
pnpm dev
|
|
24
25
|
```
|
|
25
26
|
|
|
26
|
-
### Docker mode
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
docker compose --env-file infra/docker/.env.example -f infra/docker/compose.yml up --build
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
The API uses Prisma and expects `DATABASE_URL` from env.
|
|
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.
|
|
@@ -48,11 +48,12 @@ Create or update create-forgeon preset flow:
|
|
|
48
48
|
## Add Fullstack Module
|
|
49
49
|
|
|
50
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
|
-
- add
|
|
56
|
-
-
|
|
57
|
-
|
|
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
|
+
- add docs note under docs/AI/MODULES/<module-id>.md
|
|
57
|
+
- keep backward compatibility
|
|
58
|
+
```
|
|
58
59
|
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
## Backend DTO Validation Standard
|
|
4
4
|
|
|
5
5
|
- Use `class-validator` decorators on DTO classes.
|
|
6
|
-
- Global validation is
|
|
6
|
+
- Global validation is centralized in `@forgeon/core` via `createValidationPipe()`.
|
|
7
|
+
- Current defaults:
|
|
7
8
|
- `whitelist: true`
|
|
8
9
|
- `transform: true`
|
|
10
|
+
- `validationError.target: false`
|
|
11
|
+
- `validationError.value: false`
|
|
9
12
|
- Keep DTO validation messages stable and explicit.
|
|
10
13
|
- For required values, use a consistent key or message pattern.
|
|
11
14
|
|
|
@@ -24,3 +27,5 @@
|
|
|
24
27
|
- `error.status`
|
|
25
28
|
- optional `error.details`
|
|
26
29
|
- Validation details should be structured (not `any`).
|
|
30
|
+
- `core-validation` formats validation details as:
|
|
31
|
+
- `{ field?: string, message: string }[]`
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
- `AI/PROJECT.md` - project overview and run modes
|
|
4
4
|
- `AI/ARCHITECTURE.md` - monorepo design and extension model
|
|
5
5
|
- `AI/MODULE_SPEC.md` - fullstack module contract (`contracts/api/web`)
|
|
6
|
+
- `AI/MODULE_CHECKS.md` - required runtime probe hooks for modules
|
|
6
7
|
- `AI/VALIDATION.md` - DTO/env validation standards
|
|
7
8
|
- `AI/TASKS.md` - ready-to-use Codex prompts
|
|
@@ -88,15 +88,23 @@ export class CoreExceptionFilter implements ExceptionFilter {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
private resolveDetails(payload: unknown, status: number): AppErrorDetails | undefined {
|
|
91
|
-
if (
|
|
91
|
+
if (typeof payload !== 'object' || payload === null) {
|
|
92
92
|
return undefined;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
const obj = payload as { message?: unknown; details?: unknown };
|
|
96
|
+
|
|
97
|
+
if (Array.isArray(obj.details)) {
|
|
98
|
+
return obj.details as AppErrorDetails;
|
|
99
|
+
}
|
|
100
|
+
if (obj.details && typeof obj.details === 'object') {
|
|
101
|
+
return obj.details as AppErrorDetails;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (status !== HttpStatus.BAD_REQUEST) {
|
|
96
105
|
return undefined;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
const obj = payload as { message?: unknown };
|
|
100
108
|
const messages = Array.isArray(obj.message)
|
|
101
109
|
? obj.message.filter((item): item is string => typeof item === 'string')
|
|
102
110
|
: typeof obj.message === 'string'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BadRequestException, ValidationPipe } from '@nestjs/common';
|
|
2
|
+
import type { ValidationErrorDetail } from '../errors';
|
|
3
|
+
|
|
4
|
+
type ValidationNode = {
|
|
5
|
+
property?: string;
|
|
6
|
+
constraints?: Record<string, string>;
|
|
7
|
+
children?: ValidationNode[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function toPath(parentPath: string, property: string | undefined): string {
|
|
11
|
+
if (!property || property.length === 0) {
|
|
12
|
+
return parentPath;
|
|
13
|
+
}
|
|
14
|
+
return parentPath.length > 0 ? `${parentPath}.${property}` : property;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function collectValidationDetails(
|
|
18
|
+
errors: ValidationNode[],
|
|
19
|
+
parentPath = '',
|
|
20
|
+
): ValidationErrorDetail[] {
|
|
21
|
+
const details: ValidationErrorDetail[] = [];
|
|
22
|
+
|
|
23
|
+
for (const error of errors) {
|
|
24
|
+
const field = toPath(parentPath, error.property);
|
|
25
|
+
const constraints = error.constraints ? Object.values(error.constraints) : [];
|
|
26
|
+
|
|
27
|
+
for (const message of constraints) {
|
|
28
|
+
details.push(field.length > 0 ? { field, message } : { message });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (Array.isArray(error.children) && error.children.length > 0) {
|
|
32
|
+
details.push(...collectValidationDetails(error.children, field));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return details;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createValidationPipe(): ValidationPipe {
|
|
40
|
+
return new ValidationPipe({
|
|
41
|
+
whitelist: true,
|
|
42
|
+
transform: true,
|
|
43
|
+
validationError: {
|
|
44
|
+
target: false,
|
|
45
|
+
value: false,
|
|
46
|
+
},
|
|
47
|
+
exceptionFactory: (errors) => {
|
|
48
|
+
const details = collectValidationDetails(errors as ValidationNode[]);
|
|
49
|
+
const firstMessage = details[0]?.message ?? 'Validation failed';
|
|
50
|
+
return new BadRequestException({
|
|
51
|
+
message: firstMessage,
|
|
52
|
+
details,
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './core-validation.pipe';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeon/db-prisma",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@nestjs/common": "^11.0.1",
|
|
12
|
+
"@nestjs/config": "^4.0.2",
|
|
13
|
+
"@prisma/client": "^6.18.0",
|
|
14
|
+
"zod": "^3.23.8"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^22.10.7",
|
|
18
|
+
"typescript": "^5.7.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
import { parseDbPrismaEnv } from './db-prisma-env.schema';
|
|
3
|
+
|
|
4
|
+
export const DB_PRISMA_CONFIG_NAMESPACE = 'dbPrisma';
|
|
5
|
+
|
|
6
|
+
export interface DbPrismaConfigValues {
|
|
7
|
+
databaseUrl: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const dbPrismaConfig = registerAs(
|
|
11
|
+
DB_PRISMA_CONFIG_NAMESPACE,
|
|
12
|
+
(): DbPrismaConfigValues => {
|
|
13
|
+
const env = parseDbPrismaEnv(process.env);
|
|
14
|
+
return {
|
|
15
|
+
databaseUrl: env.DATABASE_URL,
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import { DB_PRISMA_CONFIG_NAMESPACE } from './db-prisma-config.loader';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class DbPrismaConfigService {
|
|
7
|
+
constructor(private readonly configService: ConfigService) {}
|
|
8
|
+
|
|
9
|
+
get databaseUrl(): string {
|
|
10
|
+
return this.configService.getOrThrow<string>(`${DB_PRISMA_CONFIG_NAMESPACE}.databaseUrl`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const dbPrismaEnvSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
DATABASE_URL: z
|
|
6
|
+
.string()
|
|
7
|
+
.trim()
|
|
8
|
+
.min(1)
|
|
9
|
+
.default('postgresql://postgres:postgres@localhost:5432/app?schema=public'),
|
|
10
|
+
})
|
|
11
|
+
.passthrough();
|
|
12
|
+
|
|
13
|
+
export type DbPrismaEnv = z.infer<typeof dbPrismaEnvSchema>;
|
|
14
|
+
|
|
15
|
+
export function parseDbPrismaEnv(input: Record<string, unknown>): DbPrismaEnv {
|
|
16
|
+
return dbPrismaEnvSchema.parse(input);
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Global, Module } from '@nestjs/common';
|
|
2
|
+
import { ConfigModule } from '@nestjs/config';
|
|
3
|
+
import { dbPrismaConfig } from './db-prisma-config.loader';
|
|
4
|
+
import { DbPrismaConfigService } from './db-prisma-config.service';
|
|
5
|
+
import { PrismaService } from './prisma.service';
|
|
6
|
+
|
|
7
|
+
@Global()
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [ConfigModule.forFeature(dbPrismaConfig)],
|
|
10
|
+
providers: [DbPrismaConfigService, PrismaService],
|
|
11
|
+
exports: [DbPrismaConfigService, PrismaService],
|
|
12
|
+
})
|
|
13
|
+
export class DbPrismaModule {}
|
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
|
-
import { PrismaClient } from '@prisma/client';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await this.$disconnect();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { DbPrismaConfigService } from './db-prisma-config.service';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
7
|
+
constructor(configService: DbPrismaConfigService) {
|
|
8
|
+
super({
|
|
9
|
+
datasources: {
|
|
10
|
+
db: {
|
|
11
|
+
url: configService.databaseUrl,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async onModuleInit(): Promise<void> {
|
|
18
|
+
await this.$connect();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async onModuleDestroy(): Promise<void> {
|
|
22
|
+
await this.$disconnect();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"ok": "OK",
|
|
3
3
|
"checkApiHealth": "Check API health",
|
|
4
|
+
"checkErrorEnvelope": "Check error envelope",
|
|
5
|
+
"checkValidation": "Check validation (expect 400)",
|
|
6
|
+
"checkDatabase": "Check database (create user)",
|
|
4
7
|
"language": "Language",
|
|
5
8
|
"languages": {
|
|
6
9
|
"english": "English",
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"ok": "OK",
|
|
3
3
|
"checkApiHealth": "Перевірити API health",
|
|
4
|
+
"checkErrorEnvelope": "Перевірити error envelope",
|
|
5
|
+
"checkValidation": "Перевірити валідацію (очікуємо 400)",
|
|
6
|
+
"checkDatabase": "Перевірити базу даних (створити користувача)",
|
|
4
7
|
"language": "Мова",
|
|
5
8
|
"languages": {
|
|
6
9
|
"english": "Англійська",
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
## Config Strategy
|
|
8
8
|
|
|
9
|
-
- `@forgeon/core` owns base runtime config
|
|
9
|
+
- `@forgeon/core` owns base runtime config, global error envelope/filter, and validation pipe defaults.
|
|
10
10
|
- Core config is validated with Zod and exposed through typed accessors.
|
|
11
11
|
- Add-modules own and validate only their module-specific env keys.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
## Default DB Stack
|
|
2
|
-
|
|
3
|
-
Current default stack is `{{DB_LABEL}}`.
|
|
4
|
-
|
|
5
|
-
- Prisma schema and migrations live in `apps/api/prisma`
|
|
6
|
-
- DB access is encapsulated via `
|
|
7
|
-
-
|
|
1
|
+
## Default DB Stack
|
|
2
|
+
|
|
3
|
+
Current default stack is `{{DB_LABEL}}`.
|
|
4
|
+
|
|
5
|
+
- Prisma schema and migrations live in `apps/api/prisma`
|
|
6
|
+
- DB access is encapsulated via `DbPrismaModule` in `@forgeon/db-prisma`
|
|
7
|
+
- `db-prisma` is currently default-applied during scaffold generation.
|
|
8
|
+
- Future direction: this DB layer may be extracted into an explicit add-module/preset and optionally exposed via CLI flag(s).
|
|
9
|
+
- Additional DB presets are intentionally out of scope for the current milestone.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
## Scope Freeze (Current)
|
|
2
|
-
|
|
3
|
-
- Frontend preset selection is disabled (React is fixed).
|
|
4
|
-
- DB preset selection is disabled (Prisma/Postgres is fixed).
|
|
5
|
-
- Docker is always generated; runtime proxy is selectable (`caddy|nginx|none`).
|
|
1
|
+
## Scope Freeze (Current)
|
|
2
|
+
|
|
3
|
+
- Frontend preset selection is disabled (React is fixed).
|
|
4
|
+
- DB preset selection is disabled (Prisma/Postgres is fixed).
|
|
5
|
+
- Docker is always generated; runtime proxy is selectable (`caddy|nginx|none`).
|
|
6
|
+
- DB preset flags may return in a future milestone after `db-prisma` is separated into an explicit preset/module flow.
|
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
- `apps/api` - NestJS backend
|
|
4
4
|
- `apps/web` - React frontend (`{{FRONTEND_LABEL}}`, fixed)
|
|
5
|
-
- `packages/core` - shared backend core package (`core-config`
|
|
5
|
+
- `packages/core` - shared backend core package (`core-config`, `core-errors`, `core-validation`)
|
|
6
|
+
- `packages/db-prisma` - default DB module (`DbPrismaModule`, Prisma service + config)
|