create-forgeon 0.1.2 → 0.1.6
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/README.md +19 -17
- package/bin/create-forgeon.mjs +22 -22
- package/package.json +1 -1
- package/src/cli/add-help.mjs +12 -12
- package/src/cli/add-options.mjs +54 -54
- package/src/cli/add-options.test.mjs +24 -24
- package/src/cli/help.mjs +20 -20
- package/src/cli/options.mjs +121 -121
- package/src/cli/options.test.mjs +41 -41
- package/src/cli/prompt-select.mjs +94 -94
- package/src/cli/prompt-select.test.mjs +148 -148
- package/src/constants.mjs +13 -13
- package/src/core/docs.mjs +128 -128
- package/src/core/docs.test.mjs +91 -91
- package/src/core/install.mjs +14 -14
- package/src/core/scaffold.mjs +48 -45
- package/src/core/validate.mjs +12 -12
- package/src/core/validate.test.mjs +73 -73
- package/src/databases/index.mjs +26 -26
- package/src/frameworks/index.mjs +32 -32
- package/src/infrastructure/proxy.mjs +12 -12
- package/src/modules/docs.mjs +70 -70
- package/src/modules/executor.mjs +39 -21
- package/src/modules/executor.test.mjs +95 -45
- package/src/modules/i18n.mjs +283 -0
- package/src/modules/registry.mjs +43 -35
- package/src/presets/i18n.mjs +228 -180
- package/src/presets/index.mjs +2 -2
- package/src/presets/proxy.mjs +32 -32
- package/src/run-add-module.mjs +47 -47
- package/src/run-create-forgeon.mjs +72 -72
- package/src/utils/fs.mjs +26 -26
- package/src/utils/values.mjs +20 -20
- package/templates/base/.dockerignore +7 -7
- package/templates/base/.editorconfig +11 -11
- package/templates/base/README.md +46 -46
- package/templates/base/apps/api/Dockerfile +24 -24
- package/templates/base/apps/api/package.json +39 -39
- package/templates/base/apps/api/prisma/migrations/0001_init/migration.sql +11 -11
- package/templates/base/apps/api/prisma/schema.prisma +14 -14
- package/templates/base/apps/api/prisma/seed.ts +19 -19
- package/templates/base/apps/api/src/app.module.ts +32 -32
- package/templates/base/apps/api/src/common/dto/echo-query.dto.ts +5 -5
- package/templates/base/apps/api/src/common/filters/app-exception.filter.ts +129 -129
- package/templates/base/apps/api/src/config/app.config.ts +12 -12
- package/templates/base/apps/api/src/health/health.controller.ts +30 -30
- package/templates/base/apps/api/src/main.ts +25 -25
- package/templates/base/apps/api/src/prisma/prisma.module.ts +8 -8
- package/templates/base/apps/api/src/prisma/prisma.service.ts +26 -26
- package/templates/base/apps/api/tsconfig.build.json +8 -8
- package/templates/base/apps/api/tsconfig.json +8 -8
- package/templates/base/apps/web/Dockerfile +12 -12
- package/templates/base/apps/web/index.html +11 -11
- package/templates/base/apps/web/package.json +21 -21
- package/templates/base/apps/web/src/App.tsx +35 -35
- package/templates/base/apps/web/src/main.tsx +8 -8
- package/templates/base/apps/web/src/styles.css +32 -32
- package/templates/base/apps/web/tsconfig.json +17 -17
- package/templates/base/apps/web/vite.config.ts +14 -14
- package/templates/base/docs/AI/ARCHITECTURE.md +37 -37
- package/templates/base/docs/AI/MODULE_SPEC.md +56 -56
- package/templates/base/docs/AI/PROJECT.md +31 -31
- package/templates/base/docs/AI/TASKS.md +57 -57
- package/templates/base/docs/README.md +6 -6
- package/templates/base/infra/caddy/Caddyfile +15 -15
- package/templates/base/infra/docker/.env.example +9 -9
- package/templates/base/infra/docker/caddy.Dockerfile +15 -15
- package/templates/base/infra/docker/compose.caddy.yml +44 -44
- package/templates/base/infra/docker/compose.nginx.yml +44 -44
- package/templates/base/infra/docker/compose.none.yml +37 -37
- package/templates/base/infra/docker/compose.yml +44 -44
- package/templates/base/infra/docker/nginx.Dockerfile +15 -15
- package/templates/base/infra/nginx/nginx.conf +31 -31
- package/templates/base/package.json +23 -23
- package/templates/base/packages/core/README.md +2 -2
- package/templates/base/packages/core/package.json +13 -13
- package/templates/base/packages/core/tsconfig.json +7 -7
- package/templates/base/packages/i18n/package.json +18 -18
- package/templates/base/packages/i18n/src/forgeon-i18n.module.ts +45 -45
- package/templates/base/packages/i18n/tsconfig.json +8 -8
- package/templates/base/pnpm-workspace.yaml +2 -2
- package/templates/base/resources/i18n/en/common.json +4 -4
- package/templates/base/resources/i18n/en/validation.json +2 -2
- package/templates/base/resources/i18n/uk/common.json +4 -4
- package/templates/base/resources/i18n/uk/validation.json +2 -2
- package/templates/base/tsconfig.base.json +16 -16
- package/templates/docs-fragments/AI_ARCHITECTURE/00_title.md +1 -1
- package/templates/docs-fragments/AI_ARCHITECTURE/10_layout_base.md +6 -6
- package/templates/docs-fragments/AI_ARCHITECTURE/11_layout_infra.md +1 -1
- package/templates/docs-fragments/AI_ARCHITECTURE/12_layout_i18n_resources.md +1 -1
- package/templates/docs-fragments/AI_ARCHITECTURE/20_env_base.md +4 -4
- package/templates/docs-fragments/AI_ARCHITECTURE/21_env_i18n.md +3 -3
- package/templates/docs-fragments/AI_ARCHITECTURE/30_default_db.md +7 -7
- package/templates/docs-fragments/AI_ARCHITECTURE/31_docker_runtime.md +5 -5
- package/templates/docs-fragments/AI_ARCHITECTURE/32_scope_freeze.md +5 -5
- package/templates/docs-fragments/AI_ARCHITECTURE/40_docs_generation.md +9 -9
- package/templates/docs-fragments/AI_ARCHITECTURE/50_extension_points.md +8 -8
- package/templates/docs-fragments/AI_PROJECT/00_title.md +1 -1
- package/templates/docs-fragments/AI_PROJECT/10_what_is.md +3 -3
- package/templates/docs-fragments/AI_PROJECT/20_structure_base.md +5 -5
- package/templates/docs-fragments/AI_PROJECT/21_structure_i18n.md +2 -0
- package/templates/docs-fragments/AI_PROJECT/22_structure_docker.md +1 -1
- package/templates/docs-fragments/AI_PROJECT/23_structure_docs.md +1 -1
- package/templates/docs-fragments/AI_PROJECT/30_run_dev.md +8 -8
- package/templates/docs-fragments/AI_PROJECT/31_run_docker.md +5 -5
- package/templates/docs-fragments/AI_PROJECT/32_proxy_notes.md +5 -5
- package/templates/docs-fragments/AI_PROJECT/32_proxy_notes_none.md +5 -5
- package/templates/docs-fragments/AI_PROJECT/33_i18n_notes.md +2 -0
- package/templates/docs-fragments/AI_PROJECT/40_change_boundaries_base.md +3 -3
- package/templates/docs-fragments/AI_PROJECT/41_change_boundaries_docker.md +1 -1
- package/templates/docs-fragments/README/00_title.md +3 -3
- package/templates/docs-fragments/README/10_stack.md +8 -8
- package/templates/docs-fragments/README/20_quick_start_dev_intro.md +6 -6
- package/templates/docs-fragments/README/21_quick_start_dev_db_docker.md +4 -4
- package/templates/docs-fragments/README/21_quick_start_dev_db_local.md +1 -1
- package/templates/docs-fragments/README/22_quick_start_dev_outro.md +7 -7
- package/templates/docs-fragments/README/30_quick_start_docker.md +7 -7
- package/templates/docs-fragments/README/30_quick_start_docker_none.md +9 -9
- package/templates/docs-fragments/README/31_proxy_preset_caddy.md +9 -9
- package/templates/docs-fragments/README/31_proxy_preset_nginx.md +8 -8
- package/templates/docs-fragments/README/31_proxy_preset_none.md +6 -6
- package/templates/docs-fragments/README/32_prisma_container_start.md +5 -5
- package/templates/docs-fragments/README/40_i18n.md +14 -8
- package/templates/docs-fragments/README/90_next_steps.md +7 -7
- package/templates/module-fragments/i18n/00_title.md +5 -0
- package/templates/module-fragments/i18n/10_overview.md +9 -0
- package/templates/module-fragments/i18n/20_scope.md +7 -0
- package/templates/module-fragments/i18n/90_status_implemented.md +3 -0
- package/templates/module-fragments/jwt-auth/00_title.md +1 -1
- package/templates/module-fragments/jwt-auth/10_overview.md +6 -6
- package/templates/module-fragments/jwt-auth/20_scope.md +7 -7
- package/templates/module-fragments/jwt-auth/90_status_planned.md +3 -3
- package/templates/module-fragments/queue/00_title.md +1 -1
- package/templates/module-fragments/queue/10_overview.md +6 -6
- package/templates/module-fragments/queue/20_scope.md +7 -7
- package/templates/module-fragments/queue/90_status_planned.md +3 -3
- package/templates/module-presets/i18n/apps/web/src/App.tsx +61 -0
- package/templates/module-presets/i18n/packages/i18n-contracts/package.json +14 -0
- package/templates/module-presets/i18n/packages/i18n-contracts/src/index.ts +7 -0
- package/templates/module-presets/i18n/packages/i18n-contracts/tsconfig.json +8 -0
- package/templates/module-presets/i18n/packages/i18n-web/package.json +17 -0
- package/templates/module-presets/i18n/packages/i18n-web/src/index.ts +50 -0
- package/templates/module-presets/i18n/packages/i18n-web/tsconfig.json +8 -0
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import './styles.css';
|
|
3
|
-
|
|
4
|
-
type HealthResponse = {
|
|
5
|
-
status: string;
|
|
6
|
-
message: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export default function App() {
|
|
10
|
-
const [data, setData] = useState<HealthResponse | null>(null);
|
|
11
|
-
const [error, setError] = useState<string | null>(null);
|
|
12
|
-
|
|
13
|
-
const checkApi = async () => {
|
|
14
|
-
setError(null);
|
|
15
|
-
try {
|
|
16
|
-
const response = await fetch('/api/health');
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
throw new Error(`HTTP ${response.status}`);
|
|
19
|
-
}
|
|
20
|
-
const payload = (await response.json()) as HealthResponse;
|
|
21
|
-
setData(payload);
|
|
22
|
-
} catch (err) {
|
|
23
|
-
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<main className="page">
|
|
29
|
-
<h1>Forgeon Fullstack Scaffold</h1>
|
|
30
|
-
<p>Default frontend preset: React + Vite + TypeScript.</p>
|
|
31
|
-
<button onClick={checkApi}>Check API health</button>
|
|
32
|
-
{data ? <pre>{JSON.stringify(data, null, 2)}</pre> : null}
|
|
33
|
-
{error ? <p className="error">{error}</p> : null}
|
|
34
|
-
</main>
|
|
35
|
-
);
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import './styles.css';
|
|
3
|
+
|
|
4
|
+
type HealthResponse = {
|
|
5
|
+
status: string;
|
|
6
|
+
message: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function App() {
|
|
10
|
+
const [data, setData] = useState<HealthResponse | null>(null);
|
|
11
|
+
const [error, setError] = useState<string | null>(null);
|
|
12
|
+
|
|
13
|
+
const checkApi = async () => {
|
|
14
|
+
setError(null);
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetch('/api/health');
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
throw new Error(`HTTP ${response.status}`);
|
|
19
|
+
}
|
|
20
|
+
const payload = (await response.json()) as HealthResponse;
|
|
21
|
+
setData(payload);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<main className="page">
|
|
29
|
+
<h1>Forgeon Fullstack Scaffold</h1>
|
|
30
|
+
<p>Default frontend preset: React + Vite + TypeScript.</p>
|
|
31
|
+
<button onClick={checkApi}>Check API health</button>
|
|
32
|
+
{data ? <pre>{JSON.stringify(data, null, 2)}</pre> : null}
|
|
33
|
+
{error ? <p className="error">{error}</p> : null}
|
|
34
|
+
</main>
|
|
35
|
+
);
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom/client';
|
|
3
|
-
import App from './App';
|
|
4
|
-
|
|
5
|
-
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
6
|
-
<React.StrictMode>
|
|
7
|
-
<App />
|
|
8
|
-
</React.StrictMode>,
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
|
|
5
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
6
|
+
<React.StrictMode>
|
|
7
|
+
<App />
|
|
8
|
+
</React.StrictMode>,
|
|
9
9
|
);
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
body {
|
|
6
|
-
margin: 0;
|
|
7
|
-
background: #f8fafc;
|
|
8
|
-
color: #0f172a;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.page {
|
|
12
|
-
max-width: 720px;
|
|
13
|
-
margin: 3rem auto;
|
|
14
|
-
padding: 0 1rem;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
button {
|
|
18
|
-
padding: 0.6rem 1rem;
|
|
19
|
-
border: 0;
|
|
20
|
-
border-radius: 0.5rem;
|
|
21
|
-
cursor: pointer;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
pre {
|
|
25
|
-
background: #e2e8f0;
|
|
26
|
-
padding: 1rem;
|
|
27
|
-
border-radius: 0.5rem;
|
|
28
|
-
overflow: auto;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.error {
|
|
32
|
-
color: #b91c1c;
|
|
1
|
+
:root {
|
|
2
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
margin: 0;
|
|
7
|
+
background: #f8fafc;
|
|
8
|
+
color: #0f172a;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.page {
|
|
12
|
+
max-width: 720px;
|
|
13
|
+
margin: 3rem auto;
|
|
14
|
+
padding: 0 1rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
button {
|
|
18
|
+
padding: 0.6rem 1rem;
|
|
19
|
+
border: 0;
|
|
20
|
+
border-radius: 0.5rem;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pre {
|
|
25
|
+
background: #e2e8f0;
|
|
26
|
+
padding: 1rem;
|
|
27
|
+
border-radius: 0.5rem;
|
|
28
|
+
overflow: auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.error {
|
|
32
|
+
color: #b91c1c;
|
|
33
33
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
"moduleResolution": "bundler",
|
|
9
|
-
"allowImportingTsExtensions": false,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
"jsx": "react-jsx",
|
|
14
|
-
"strict": true,
|
|
15
|
-
"types": ["vite/client"]
|
|
16
|
-
},
|
|
17
|
-
"include": ["src"]
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": false,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"types": ["vite/client"]
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"]
|
|
18
18
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import react from '@vitejs/plugin-react';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
plugins: [react()],
|
|
6
|
-
server: {
|
|
7
|
-
port: 5173,
|
|
8
|
-
proxy: {
|
|
9
|
-
'/api': {
|
|
10
|
-
target: 'http://localhost:3000',
|
|
11
|
-
changeOrigin: true,
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
},
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
server: {
|
|
7
|
+
port: 5173,
|
|
8
|
+
proxy: {
|
|
9
|
+
'/api': {
|
|
10
|
+
target: 'http://localhost:3000',
|
|
11
|
+
changeOrigin: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
15
|
});
|
|
@@ -1,38 +1,38 @@
|
|
|
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
|
-
## Environment Flags
|
|
11
|
-
|
|
12
|
-
- `PORT` - API port (default 3000)
|
|
13
|
-
- `DATABASE_URL` - Prisma Postgres connection
|
|
14
|
-
- `I18N_ENABLED` - toggles i18n package wiring
|
|
15
|
-
- `I18N_DEFAULT_LANG` - default language
|
|
16
|
-
- `I18N_FALLBACK_LANG` - fallback language
|
|
17
|
-
|
|
18
|
-
## Default DB Stack
|
|
19
|
-
|
|
20
|
-
Current default is Prisma + Postgres.
|
|
21
|
-
|
|
22
|
-
- Prisma schema and migrations live in `apps/api/prisma`
|
|
23
|
-
- DB access is encapsulated via `PrismaModule` (`apps/api/src/prisma`)
|
|
24
|
-
|
|
25
|
-
## Future DB Presets (Not Implemented Yet)
|
|
26
|
-
|
|
27
|
-
A future preset can switch DB by:
|
|
28
|
-
1. Replacing `PrismaModule` with another DB module package (for example Mongo package).
|
|
29
|
-
2. Updating `infra/docker/compose.yml` DB service.
|
|
30
|
-
3. Updating `DATABASE_URL` and related env keys.
|
|
31
|
-
4. Keeping app-level services dependent only on repository/data-access abstractions.
|
|
32
|
-
|
|
33
|
-
## Future Feature Modules
|
|
34
|
-
|
|
35
|
-
Reusable features should be added as workspace packages and imported by apps as needed:
|
|
36
|
-
|
|
37
|
-
- `packages/core` for shared backend primitives
|
|
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
|
+
## Environment Flags
|
|
11
|
+
|
|
12
|
+
- `PORT` - API port (default 3000)
|
|
13
|
+
- `DATABASE_URL` - Prisma Postgres connection
|
|
14
|
+
- `I18N_ENABLED` - toggles i18n package wiring
|
|
15
|
+
- `I18N_DEFAULT_LANG` - default language
|
|
16
|
+
- `I18N_FALLBACK_LANG` - fallback language
|
|
17
|
+
|
|
18
|
+
## Default DB Stack
|
|
19
|
+
|
|
20
|
+
Current default is Prisma + Postgres.
|
|
21
|
+
|
|
22
|
+
- Prisma schema and migrations live in `apps/api/prisma`
|
|
23
|
+
- DB access is encapsulated via `PrismaModule` (`apps/api/src/prisma`)
|
|
24
|
+
|
|
25
|
+
## Future DB Presets (Not Implemented Yet)
|
|
26
|
+
|
|
27
|
+
A future preset can switch DB by:
|
|
28
|
+
1. Replacing `PrismaModule` with another DB module package (for example Mongo package).
|
|
29
|
+
2. Updating `infra/docker/compose.yml` DB service.
|
|
30
|
+
3. Updating `DATABASE_URL` and related env keys.
|
|
31
|
+
4. Keeping app-level services dependent only on repository/data-access abstractions.
|
|
32
|
+
|
|
33
|
+
## Future Feature Modules
|
|
34
|
+
|
|
35
|
+
Reusable features should be added as workspace packages and imported by apps as needed:
|
|
36
|
+
|
|
37
|
+
- `packages/core` for shared backend primitives
|
|
38
38
|
- Additional packages for auth presets, guards, queues, mailers, etc.
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
# MODULE SPEC
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Define one repeatable fullstack pattern for Forgeon add-modules.
|
|
6
|
-
|
|
7
|
-
Each feature module should be split into:
|
|
8
|
-
|
|
9
|
-
1. `@forgeon/<feature>-contracts`
|
|
10
|
-
2. `@forgeon/<feature>-api`
|
|
11
|
-
3. `@forgeon/<feature>-web`
|
|
12
|
-
|
|
13
|
-
## 1) Contracts Package
|
|
14
|
-
|
|
15
|
-
Single source of truth shared by backend and frontend.
|
|
16
|
-
|
|
17
|
-
Must contain:
|
|
18
|
-
|
|
19
|
-
- DTO/request/response types
|
|
20
|
-
- route constants (`API.<feature>.*`)
|
|
21
|
-
- error codes (`<FEATURE>_*`)
|
|
22
|
-
- shared constants (header/cookie names)
|
|
23
|
-
|
|
24
|
-
Should contain:
|
|
25
|
-
|
|
26
|
-
- zod schemas + inferred TS types
|
|
27
|
-
|
|
28
|
-
## 2) API Package
|
|
29
|
-
|
|
30
|
-
NestJS module integrating contracts into backend runtime.
|
|
31
|
-
|
|
32
|
-
Must contain:
|
|
33
|
-
|
|
34
|
-
- module/service/controller
|
|
35
|
-
- guards/strategies (if auth/security related)
|
|
36
|
-
- config keys
|
|
37
|
-
- minimal e2e test path
|
|
38
|
-
- integration with `@forgeon/core` errors/logging
|
|
39
|
-
|
|
40
|
-
## 3) Web Package
|
|
41
|
-
|
|
42
|
-
React integration layer for the same feature.
|
|
43
|
-
|
|
44
|
-
Must contain:
|
|
45
|
-
|
|
46
|
-
- provider/hooks/store
|
|
47
|
-
- route guard (if feature requires auth/access)
|
|
48
|
-
- API client helpers using contracts route constants/types
|
|
49
|
-
- token/header/cookie wiring where relevant
|
|
50
|
-
|
|
51
|
-
## Acceptance Criteria
|
|
52
|
-
|
|
53
|
-
- No duplicate route strings across api/web.
|
|
54
|
-
- No duplicate error-code enums across api/web.
|
|
55
|
-
- Contracts package can be imported from both sides without circular dependencies.
|
|
56
|
-
- Module has docs under `docs/AI/MODULES/<module-id>.md`.
|
|
1
|
+
# MODULE SPEC
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Define one repeatable fullstack pattern for Forgeon add-modules.
|
|
6
|
+
|
|
7
|
+
Each feature module should be split into:
|
|
8
|
+
|
|
9
|
+
1. `@forgeon/<feature>-contracts`
|
|
10
|
+
2. `@forgeon/<feature>-api`
|
|
11
|
+
3. `@forgeon/<feature>-web`
|
|
12
|
+
|
|
13
|
+
## 1) Contracts Package
|
|
14
|
+
|
|
15
|
+
Single source of truth shared by backend and frontend.
|
|
16
|
+
|
|
17
|
+
Must contain:
|
|
18
|
+
|
|
19
|
+
- DTO/request/response types
|
|
20
|
+
- route constants (`API.<feature>.*`)
|
|
21
|
+
- error codes (`<FEATURE>_*`)
|
|
22
|
+
- shared constants (header/cookie names)
|
|
23
|
+
|
|
24
|
+
Should contain:
|
|
25
|
+
|
|
26
|
+
- zod schemas + inferred TS types
|
|
27
|
+
|
|
28
|
+
## 2) API Package
|
|
29
|
+
|
|
30
|
+
NestJS module integrating contracts into backend runtime.
|
|
31
|
+
|
|
32
|
+
Must contain:
|
|
33
|
+
|
|
34
|
+
- module/service/controller
|
|
35
|
+
- guards/strategies (if auth/security related)
|
|
36
|
+
- config keys
|
|
37
|
+
- minimal e2e test path
|
|
38
|
+
- integration with `@forgeon/core` errors/logging
|
|
39
|
+
|
|
40
|
+
## 3) Web Package
|
|
41
|
+
|
|
42
|
+
React integration layer for the same feature.
|
|
43
|
+
|
|
44
|
+
Must contain:
|
|
45
|
+
|
|
46
|
+
- provider/hooks/store
|
|
47
|
+
- route guard (if feature requires auth/access)
|
|
48
|
+
- API client helpers using contracts route constants/types
|
|
49
|
+
- token/header/cookie wiring where relevant
|
|
50
|
+
|
|
51
|
+
## Acceptance Criteria
|
|
52
|
+
|
|
53
|
+
- No duplicate route strings across api/web.
|
|
54
|
+
- No duplicate error-code enums across api/web.
|
|
55
|
+
- Contracts package can be imported from both sides without circular dependencies.
|
|
56
|
+
- Module has docs under `docs/AI/MODULES/<module-id>.md`.
|
|
@@ -1,32 +1,32 @@
|
|
|
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` - frontend scaffold (default React + Vite + TS)
|
|
11
|
-
- `packages/core` - shared backend core placeholder
|
|
12
|
-
- `packages/i18n` - reusable nestjs-i18n integration package
|
|
13
|
-
- `infra` - Docker Compose + reverse proxy preset (nginx/caddy)
|
|
14
|
-
- `resources/i18n` - translation dictionaries
|
|
15
|
-
- `docs` - documentation and AI workflow prompts
|
|
16
|
-
|
|
17
|
-
## Run Modes
|
|
18
|
-
|
|
19
|
-
### Dev mode
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pnpm install
|
|
23
|
-
pnpm dev
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Docker mode
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
docker compose --env-file infra/docker/.env.example -f infra/docker/compose.yml up --build
|
|
30
|
-
```
|
|
31
|
-
|
|
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` - frontend scaffold (default React + Vite + TS)
|
|
11
|
+
- `packages/core` - shared backend core placeholder
|
|
12
|
+
- `packages/i18n` - reusable nestjs-i18n integration package
|
|
13
|
+
- `infra` - Docker Compose + reverse proxy preset (nginx/caddy)
|
|
14
|
+
- `resources/i18n` - translation dictionaries
|
|
15
|
+
- `docs` - documentation and AI workflow prompts
|
|
16
|
+
|
|
17
|
+
## Run Modes
|
|
18
|
+
|
|
19
|
+
### Dev mode
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm install
|
|
23
|
+
pnpm dev
|
|
24
|
+
```
|
|
25
|
+
|
|
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
32
|
The API uses Prisma and expects `DATABASE_URL` from env.
|
|
@@ -1,58 +1,58 @@
|
|
|
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
|
-
- add docs note under docs/AI/MODULES/<module-id>.md
|
|
56
|
-
- keep backward compatibility
|
|
57
|
-
```
|
|
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
|
+
- add docs note under docs/AI/MODULES/<module-id>.md
|
|
56
|
+
- keep backward compatibility
|
|
57
|
+
```
|
|
58
58
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Documentation Index
|
|
2
|
-
|
|
3
|
-
- `AI/PROJECT.md` - project overview and run modes
|
|
4
|
-
- `AI/ARCHITECTURE.md` - monorepo design and extension model
|
|
5
|
-
- `AI/MODULE_SPEC.md` - fullstack module contract (`contracts/api/web`)
|
|
6
|
-
- `AI/TASKS.md` - ready-to-use Codex prompts
|
|
1
|
+
# Documentation Index
|
|
2
|
+
|
|
3
|
+
- `AI/PROJECT.md` - project overview and run modes
|
|
4
|
+
- `AI/ARCHITECTURE.md` - monorepo design and extension model
|
|
5
|
+
- `AI/MODULE_SPEC.md` - fullstack module contract (`contracts/api/web`)
|
|
6
|
+
- `AI/TASKS.md` - ready-to-use Codex prompts
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
:80 {
|
|
2
|
-
encode gzip zstd
|
|
3
|
-
|
|
4
|
-
route {
|
|
5
|
-
handle /api/* {
|
|
6
|
-
reverse_proxy api:3000
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
handle {
|
|
10
|
-
root * /srv
|
|
11
|
-
try_files {path} /index.html
|
|
12
|
-
file_server
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
1
|
+
:80 {
|
|
2
|
+
encode gzip zstd
|
|
3
|
+
|
|
4
|
+
route {
|
|
5
|
+
handle /api/* {
|
|
6
|
+
reverse_proxy api:3000
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
handle {
|
|
10
|
+
root * /srv
|
|
11
|
+
try_files {path} /index.html
|
|
12
|
+
file_server
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
POSTGRES_USER=postgres
|
|
2
|
-
POSTGRES_PASSWORD=postgres
|
|
3
|
-
POSTGRES_DB=app
|
|
4
|
-
|
|
5
|
-
PORT=3000
|
|
6
|
-
DATABASE_URL=postgresql://postgres:postgres@db:5432/app?schema=public
|
|
7
|
-
|
|
8
|
-
I18N_ENABLED=true
|
|
9
|
-
I18N_DEFAULT_LANG=en
|
|
1
|
+
POSTGRES_USER=postgres
|
|
2
|
+
POSTGRES_PASSWORD=postgres
|
|
3
|
+
POSTGRES_DB=app
|
|
4
|
+
|
|
5
|
+
PORT=3000
|
|
6
|
+
DATABASE_URL=postgresql://postgres:postgres@db:5432/app?schema=public
|
|
7
|
+
|
|
8
|
+
I18N_ENABLED=true
|
|
9
|
+
I18N_DEFAULT_LANG=en
|
|
10
10
|
I18N_FALLBACK_LANG=en
|