proteum 2.0.0 → 2.1.0

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 (94) hide show
  1. package/AGENTS.md +13 -1
  2. package/README.md +375 -0
  3. package/agents/framework/AGENTS.md +917 -0
  4. package/agents/project/AGENTS.md +138 -0
  5. package/agents/{codex → project}/CODING_STYLE.md +3 -2
  6. package/agents/project/client/AGENTS.md +108 -0
  7. package/agents/{codex → project}/client/pages/AGENTS.md +8 -8
  8. package/agents/{codex → project}/server/routes/AGENTS.md +2 -1
  9. package/agents/project/server/services/AGENTS.md +170 -0
  10. package/agents/{codex → project}/tests/AGENTS.md +1 -0
  11. package/cli/app/config.ts +3 -2
  12. package/cli/app/index.ts +6 -66
  13. package/cli/bin.js +7 -2
  14. package/cli/commands/build.ts +94 -27
  15. package/cli/commands/check.ts +15 -1
  16. package/cli/commands/dev.ts +288 -132
  17. package/cli/commands/doctor.ts +108 -0
  18. package/cli/commands/explain.ts +226 -0
  19. package/cli/commands/init.ts +76 -70
  20. package/cli/commands/lint.ts +18 -1
  21. package/cli/commands/refresh.ts +16 -6
  22. package/cli/commands/typecheck.ts +14 -1
  23. package/cli/compiler/artifacts/controllers.ts +150 -0
  24. package/cli/compiler/artifacts/discovery.ts +132 -0
  25. package/cli/compiler/artifacts/manifest.ts +267 -0
  26. package/cli/compiler/artifacts/routing.ts +315 -0
  27. package/cli/compiler/artifacts/services.ts +480 -0
  28. package/cli/compiler/artifacts/shared.ts +12 -0
  29. package/cli/compiler/client/identite.ts +2 -1
  30. package/cli/compiler/client/index.ts +13 -3
  31. package/cli/compiler/common/controllers.ts +23 -28
  32. package/cli/compiler/common/files/style.ts +3 -4
  33. package/cli/compiler/common/generatedRouteModules.ts +333 -19
  34. package/cli/compiler/common/proteumManifest.ts +133 -0
  35. package/cli/compiler/index.ts +33 -896
  36. package/cli/compiler/server/index.ts +21 -4
  37. package/cli/context.ts +71 -0
  38. package/cli/index.ts +39 -181
  39. package/cli/presentation/commands.ts +208 -0
  40. package/cli/presentation/compileReporter.ts +65 -0
  41. package/cli/presentation/devSession.ts +70 -0
  42. package/cli/presentation/help.ts +193 -0
  43. package/cli/presentation/ink.ts +69 -0
  44. package/cli/presentation/layout.ts +83 -0
  45. package/cli/runtime/argv.ts +49 -0
  46. package/cli/runtime/command.ts +25 -0
  47. package/cli/runtime/commands.ts +221 -0
  48. package/cli/runtime/importEsm.ts +7 -0
  49. package/cli/runtime/verbose.ts +15 -0
  50. package/cli/utils/agents.ts +5 -4
  51. package/cli/utils/keyboard.ts +12 -6
  52. package/client/app/index.ts +0 -6
  53. package/client/services/router/index.tsx +1 -1
  54. package/client/services/router/response/index.tsx +2 -2
  55. package/common/dev/serverHotReload.ts +12 -0
  56. package/common/router/index.ts +3 -2
  57. package/common/router/layouts.ts +1 -1
  58. package/common/router/pageSetup.ts +1 -0
  59. package/package.json +10 -8
  60. package/prettier/router-registration-plugin.cjs +52 -0
  61. package/prettier.config.cjs +1 -0
  62. package/scripts/cleanup-generated-controllers.ts +2 -2
  63. package/scripts/fix-reference-app-typing.ts +2 -2
  64. package/scripts/format-router-registrations.ts +119 -0
  65. package/scripts/migrate-explicit-controllers-and-request.ts +423 -0
  66. package/scripts/refactor-server-controllers.ts +19 -18
  67. package/scripts/refactor-server-runtime-aliases.ts +1 -1
  68. package/server/app/commands.ts +309 -25
  69. package/server/app/container/config.ts +1 -1
  70. package/server/app/container/index.ts +2 -2
  71. package/server/app/controller/index.ts +13 -4
  72. package/server/app/index.ts +53 -37
  73. package/server/app/service/container.ts +26 -28
  74. package/server/app/service/index.ts +10 -20
  75. package/server/app.tsconfig.json +9 -2
  76. package/server/index.ts +32 -1
  77. package/server/services/auth/index.ts +234 -15
  78. package/server/services/auth/router/index.ts +39 -7
  79. package/server/services/auth/router/request.ts +40 -8
  80. package/server/services/disks/index.ts +1 -1
  81. package/server/services/prisma/Facet.ts +2 -2
  82. package/server/services/prisma/index.ts +22 -5
  83. package/server/services/prisma/mariadb.ts +47 -0
  84. package/server/services/router/http/index.ts +9 -1
  85. package/server/services/router/index.ts +10 -4
  86. package/server/services/router/response/index.ts +26 -6
  87. package/types/auth-check-rules.test.ts +51 -0
  88. package/types/controller-request-context.test.ts +55 -0
  89. package/types/service-config.test.ts +39 -0
  90. package/agents/codex/AGENTS.md +0 -95
  91. package/agents/codex/client/AGENTS.md +0 -102
  92. package/agents/codex/server/services/AGENTS.md +0 -137
  93. package/server/services/models.7z +0 -0
  94. /package/agents/{codex → project}/agents.md.zip +0 -0
@@ -0,0 +1,138 @@
1
+ # Architecture
2
+
3
+ This is a full stack monolith project using Typescript, NodeJS, Preact, and Proteum.
4
+
5
+ `/client`: frontend
6
+ `/assets`: CSS, images and other frontend assets
7
+ `/catalogs`: client-only catalogs and registries
8
+ `/components`: reusable components
9
+ `/pages`: page route files and page-local UI
10
+ `/hooks`
11
+ `/common`: shared functions, constants, typings, and cross-runtime catalogs
12
+ `/server`: backend
13
+ `/catalogs`: server-only catalogs and registries
14
+ `/config`: service configuration
15
+ `/services`: backend services and controllers
16
+ `/routes`: explicit non-controller routes
17
+ `/lib`: helper functions
18
+ `/tests`
19
+
20
+ # Coding style
21
+
22
+ See `CODING_STYLE.md`.
23
+ This file is the source of truth for formatting, section-comment structure, and general coding style.
24
+
25
+ # Framework contract
26
+
27
+ For Proteum-wide project scaffolding, routing, SSR, controller, service, generated-code, and maintenance rules, use the
28
+ framework guide in the Proteum repository at `agents/framework/AGENTS.md`.
29
+ From a normal Proteum project install, read it at `./node_modules/proteum/agents/framework/AGENTS.md`.
30
+
31
+ Start framework inspection with:
32
+
33
+ - `./.proteum/manifest.json`
34
+ - `npx proteum explain`
35
+ - `npx proteum doctor`
36
+
37
+ Generated files live under `./.proteum` and should not be edited by hand.
38
+ Project code should use the generated aliases `@generated/client/*`, `@generated/common/*`, and `@generated/server/*`.
39
+ Client context is typically imported from `@/client/context`.
40
+ Prefer type inference from the explicit application class in `./server/index.ts` whenever possible. Treat it as the
41
+ canonical type root for app services, router services, router context, and models instead of duplicating manual type
42
+ declarations.
43
+
44
+ # Files organization
45
+
46
+ - Always keep one class / React component per file
47
+ - Prefer a deep tree structure that groups files by business concern instead of long file names
48
+ - The default `*.ts` / `*.tsx` file is the normal implementation; use `*.ssr.ts` / `*.ssr.tsx` only when the project
49
+ needs an SSR-specific variant
50
+
51
+ ## Centralize feature catalogs (Single Source of Truth)
52
+
53
+ When implementing a feature that relies on a **curated list of items**, keep **one canonical catalog/registry file** and make all other code import it.
54
+
55
+ - Client-only catalogs live in `/client/catalogs/**`
56
+ - Server-only catalogs live in `/server/catalogs/**`
57
+ - Shared catalogs used by both runtimes live in `/common/catalogs/**`
58
+ - Organize those root catalog trees by business concern (mirror the feature path when useful)
59
+ - Do not create nested `catalogs/` folders inside `/client/pages/**`, `/client/components/**`, `/server/services/**`, or similar feature folders
60
+
61
+ ## Runtime access rules
62
+
63
+ - `@models/types`: Prisma typings only. Can be imported anywhere.
64
+ - Never use runtime value imports from `@request` or `@models`.
65
+ - Never expose request-scoped state through imports.
66
+ - Keep app services, router services, router context, and model contracts inferred from `./server/index.ts` whenever
67
+ possible instead of recreating parallel type maps.
68
+
69
+ ## Client runtime access
70
+
71
+ - Page route files use `Router.page(...)`.
72
+ - `Router.page(path, render)` for pages without SSR setup.
73
+ - `Router.page(path, setup, render)` for pages with SSR config/data.
74
+ - `setup` receives the normal page context plus the generated controller tree spread into it.
75
+ - `render` receives the normal page context plus the resolved setup data and the same controller tree spread into it.
76
+ - Components and hooks use the app client context hook, usually imported from `@/client/context`.
77
+ - For UI primitives, prefer the project's shared Shadcn-based components whenever they already exist and fit the need before creating bespoke buttons, inputs, dialogs, or similar building blocks.
78
+
79
+ ## Server runtime access
80
+
81
+ - Normal business logic lives in `/server/services/**/index.ts` classes that extend `Service`.
82
+ - Route entrypoints live in `/server/controllers/**/*.ts` classes that extend `Controller`.
83
+ - Only controller files are indexed as callable API endpoints.
84
+ - Controller methods validate input with `this.input(schema)` and access request scope through `this.request`.
85
+ - Service classes access other services via `this.services` and prisma models via `this.models`.
86
+ - App service types should be inferred from the explicit application graph rooted at `./server/index.ts`.
87
+ - Router services and request/context values such as `user`, `auth`, and similar request-scoped contracts should come
88
+ from inferred request and app types, not ad hoc casts.
89
+ - Models should be inferred from the app/model registry rooted at `./server/index.ts` and exposed through the generated
90
+ server app shim, not from duplicated manual model maps.
91
+ - Never use request-scoped state directly inside normal service methods.
92
+ - Controllers should resolve auth and request-derived values, then pass plain typed arguments into services.
93
+ - When referencing an app service, a router service, or a model, expose it in the current block scope first by
94
+ destructuring from `this.request`, `this.app`, `this.models`, or the generated app/model accessors where applicable,
95
+ then call methods on that local binding. The service, router value, or model should be the first element of the callee
96
+ chain.
97
+
98
+ # Agent behavior
99
+
100
+ **Make sure the code you generate integrates perfectly with the current codebase by avoiding repetition and centralizing each purpose.**
101
+
102
+ ## Typings
103
+
104
+ - Keep strong, consistent TypeScript typings across the whole project.
105
+ - Do not introduce `any` or `unknown`, including through casts, helper aliases, or fallback generic defaults.
106
+ - Fix typing issues only on the code you wrote.
107
+ - Never cast with `as any` or `as unknown`; fix the type contract or introduce an explicit typed adapter instead. If you find no other solution, tell me in the output.
108
+
109
+ ## Workflow
110
+
111
+ - Every time I input error messages without any instructions, don't implement fixes.
112
+ Instead, investigate the potential causes of the errors, and for each:
113
+ 1. Evaluate / quantify the probabilities
114
+ 2. Give why and
115
+ 3. Suggest how to fix it
116
+ - When you have finished your work, summarize in one top-level short sentence the changes you made since the beginning of the conversation. Output as "Commit message".
117
+
118
+ ## High-impact files
119
+
120
+ - Do not edit generated files under `.proteum` by hand.
121
+ - Treat `tsconfig*.json`, `env*.yaml`, Prisma-generated files, and symbolic links as high-impact.
122
+ - Edit them only when the task actually requires it, and keep those changes minimal and explicit.
123
+
124
+ If a high-impact file change is not required for the task, leave it alone.
125
+
126
+ ## Don't run any of these commands
127
+
128
+ ```
129
+ git restore
130
+ git reset
131
+ prisma *
132
+ And any git command in the write mode.
133
+ ```
134
+
135
+ # Copy and UX
136
+
137
+ Before making UX/copy decisions, read `docs/PERSONAS.md`, `docs/PRODUCT.md`, `docs/MARKETING.md`.
138
+ When implementing UI, prefer existing Shadcn components or local wrappers around them whenever they can satisfy the requirement cleanly.
@@ -7,7 +7,7 @@ This file is the source of truth for codex coding style instructions in Proteum-
7
7
  - **The code should be at the highest level of industry, as the product will be used by GAFAMs and will be maintained by a team of 10 developers.**
8
8
  - Write clean, consistent, readable code with a tab size of 4.
9
9
  - Keep functions and methods short.
10
- - Everytime possible, create reusable functions and components instead of repeating.
10
+ - Every time possible, create reusable functions and components instead of repeating.
11
11
 
12
12
  ## Formatting
13
13
 
@@ -16,10 +16,11 @@ This file is the source of truth for codex coding style instructions in Proteum-
16
16
  - Keep short arrow functions and short returned object literals compact when they are easy to scan.
17
17
  - Keep JSX multiline only when it is clearly more readable; otherwise keep short JSX compact.
18
18
  - Avoid staircase formatting and unnecessary blank lines inside short callbacks.
19
+ - Keep `Router.page(...)` and `Router.error(...)` registrations in the compact inline-call shape when possible, for example `Router.page('/path', setup, render);`.
19
20
 
20
21
  ## File organization
21
22
 
22
- - Always keep one class or react component per file.
23
+ - Always keep one class or React component per file.
23
24
  - Prefer a deep tree structure that groups files by business concern instead of long file names.
24
25
  - The default `*.ts` / `*.tsx` file is the browser implementation; use `*.ssr.ts` / `*.ssr.tsx` only for SSR-safe fallbacks.
25
26
  - When implementing a feature that relies on a curated list of items, keep one canonical catalog or registry file and make all other code import it.
@@ -0,0 +1,108 @@
1
+ # Frontend
2
+
3
+ UI components are defined in `/client/pages` and `/client/components`.
4
+ Client-only catalogs and registries live in `/client/catalogs/**`.
5
+
6
+ ## Stack
7
+
8
+ - Typescript strict
9
+ - Preact with SSR
10
+ - Follow the UI stack already used in the touched area.
11
+ - Many Proteum apps use Tailwind and `@/client/components/Motion`, but those are app conventions, not framework guarantees.
12
+ - When the project already exposes Shadcn components or `client/components/ui/**` primitives derived from them, prefer those components for standard UI instead of rebuilding the same primitives locally.
13
+
14
+ Don't add `React` imports just for JSX.
15
+ Use `React` only when a React or Preact API is actually needed.
16
+ Don't use `React.useCallback` unless strictly necessary or already common in the touched area.
17
+
18
+ ## Communicate with the server
19
+
20
+ ### Pages
21
+
22
+ Pages use `Router.page(...)`.
23
+
24
+ Use `Router.page(path, render)` when there is no SSR setup.
25
+
26
+ Use `Router.page(path, setup, render)` when the page needs SSR config or SSR data:
27
+
28
+ ```typescript
29
+ Router.page('/dashboard/example', ({ Feature }) => ({
30
+ _auth: 'USER',
31
+ dataKey: Feature.loadExample(),
32
+ }), ({ dataKey }) => <Page data={dataKey} />);
33
+ ```
34
+
35
+ - Keep the route registration compact instead of exploding the whole call into a staircase layout.
36
+ - `setup` returns one flat object
37
+ - keys like `_auth`, `_layout`, `_priority` are route config
38
+ - all other keys are SSR data fetchers
39
+ - never use `api.fetch(...)` in page files
40
+
41
+ ### Components and hooks
42
+
43
+ Components and hooks access controllers through the app client context hook, typically `useContext()` from `@/client/context`:
44
+
45
+ ```typescript
46
+ const { Auth, Domains } = useContext();
47
+ ```
48
+
49
+ Then call controller methods directly:
50
+
51
+ ```typescript
52
+ Auth.signUp(data).then((result) => {
53
+ ...
54
+ });
55
+ ```
56
+
57
+ ### Async calls
58
+
59
+ - Prefer direct controller calls from the context or page render args
60
+ - Follow the controller naming and hierarchy already used in the touched feature instead of inventing a new one
61
+ - The thrown errors will automatically be displayed to the user, so don't silence them
62
+ - Never depend on legacy `@app` imports on the client
63
+
64
+ ## Errors handling
65
+
66
+ Errors caught from controller calls should never be silenced.
67
+ If a catch is needed, rethrow or surface the failure clearly.
68
+
69
+ ## Design
70
+
71
+ - Follow the existing design language of the app or feature area.
72
+ - Keep layouts responsive and accessible.
73
+ - Add motion only when the area already uses it or when it materially improves UX.
74
+ - Reuse Shadcn-based shared primitives first for common controls like buttons, inputs, dialogs, dropdowns, tabs, tables, and forms when they cover the requirement.
75
+ - Create custom UI primitives only when the existing Shadcn layer cannot express the interaction or visual requirement cleanly.
76
+
77
+ ## Rules
78
+
79
+ - Don't add `React` imports unless the file actually uses a React or Preact API.
80
+ - Don't use any component from `@client/components` unless the codebase already does in that area, except for established shared primitives such as the project's Shadcn-based `client/components/ui/**` layer
81
+ - To create a link / button, always use the `Link` component when the codebase expects navigation links
82
+
83
+ ## Keep the code organized
84
+
85
+ - Split big components (more than 1000 lines) into smaller components
86
+ - Always use one component per file
87
+ - Every time possible, load data and define action handlers in the directly concerned component instead of passing everything from the parent
88
+ - Put curated lists, option registries, UI copy catalogs, and similar SSOT data under `/client/catalogs/**`, not inside page or component folders
89
+
90
+ ## Split the page by sections via comments
91
+
92
+ Use:
93
+
94
+ ```typescript
95
+ /*----------------------------------
96
+ - SECTION NAME
97
+ ----------------------------------*/
98
+ ```
99
+
100
+ File sections:
101
+ - DEPENDENCIES
102
+ - TYPES
103
+ - COMPONENT / PAGE
104
+
105
+ Component / page sections:
106
+ - INIT
107
+ - ACTIONS
108
+ - RENDER
@@ -7,26 +7,26 @@ Page files are located in `/client/pages/**/*.tsx`.
7
7
  Use one of these forms:
8
8
 
9
9
  ```typescript
10
- Router.page('/path', ({ request, ServiceName }) => {
11
- return <Page />;
12
- });
10
+ Router.page('/path', ({ request, Feature }) => <Page />);
13
11
  ```
14
12
 
15
13
  ```typescript
16
- Router.page('/path', ({ ServiceName }) => ({
14
+ Router.page('/path', ({ Feature }) => ({
17
15
  _auth: 'USER',
18
- dataKey: ServiceName.MethodName({ param1: 'value' }),
19
- }), ({ request, dataKey, ServiceName }) => {
20
- return <Page data={dataKey} />;
21
- });
16
+ dataKey: Feature.loadData({ param1: 'value' }),
17
+ }), ({ request, dataKey, Feature }) => <Page data={dataKey} />);
22
18
  ```
23
19
 
20
+ - Keep the `Router.page(...)` call itself compact instead of expanding each argument onto its own outer line.
24
21
  - `setup` is the second `Router.page` argument
25
22
  - `render` is the last `Router.page` argument
26
23
  - `setup` receives the page context plus generated controller instances
27
24
  - `render` receives the page context, resolved setup data, and generated controller instances
25
+ - Prefer the generated page arguments or the app context hook; do not import `.proteum` files directly.
28
26
  - Never use `api.fetch(...)` in page files
29
27
  - Never import client service values from `@app`
28
+ - Compose page UI from shared Shadcn-based components when the project already provides them instead of redefining common controls inline in the page file
29
+ - Keep page-local curated copy, option sets, and registries in `/client/catalogs/**`; do not create `catalogs/` folders under `client/pages/**`
30
30
 
31
31
  ## Typings
32
32
 
@@ -2,8 +2,9 @@
2
2
 
3
3
  Use `/server/routes/**` only for explicit custom routes that should not be generated from controllers.
4
4
 
5
- - Callable app APIs belong in `*.controller.ts` files under `/server/services`
5
+ - Callable app APIs belong in `/server/controllers/**/*.ts`
6
6
  - `/server/routes/**` is for manual `Router.get/post/...` routes, redirects, resources, OAuth callbacks, etc.
7
+ - If a route needs a curated list or registry, keep server-only data in `/server/catalogs/**` and shared data in `/common/catalogs/**`
7
8
 
8
9
  ## Generate absolute urls
9
10
 
@@ -0,0 +1,170 @@
1
+ # Server Services
2
+
3
+ Stack:
4
+ - Typescript with strict mode
5
+ - NodeJS
6
+ - Prisma 7 ORM
7
+
8
+ ## Catalog placement
9
+
10
+ - Server-only catalogs and registries live in `/server/catalogs/**`
11
+ - Shared cross-runtime catalogs live in `/common/catalogs/**`
12
+ - Do not create nested `catalogs/` folders under `/server/services/**`
13
+ - Services should import curated lists from those root catalog locations instead of redefining them locally
14
+
15
+ ## 1. Create the service file in `/server/services/<service name>/index.ts`
16
+
17
+ Template:
18
+
19
+ ```typescript
20
+ /*----------------------------------
21
+ - DEPENDANCE
22
+ ----------------------------------*/
23
+
24
+ // Core libs
25
+ import Service from '@server/app/service';
26
+
27
+ /*----------------------------------
28
+ - TYPES
29
+ ----------------------------------*/
30
+
31
+ export type Config = Record<string, never>;
32
+
33
+ /*----------------------------------
34
+ - SERVICE
35
+ ----------------------------------*/
36
+
37
+ export default class ServiceName extends Service<Config, {}, AppType, ParentServiceType> {
38
+
39
+ public async methodName(data: { param1: string }) {
40
+ return this.services.OtherService.otherMethod(data);
41
+ }
42
+ }
43
+ ```
44
+
45
+ Replace `AppType` and `ParentServiceType` with the local app types used by neighboring services.
46
+ If the service receives config from a project config file, replace `Config` with the real config shape and expose a typed
47
+ config export with `Services.config(ServiceName, { ... })` from `server/config/*.ts`.
48
+
49
+ ## 2. Create the controller file in `/server/controllers/...`
50
+
51
+ Template:
52
+
53
+ ```typescript
54
+ import Controller, { schema } from '@server/app/controller';
55
+
56
+ const MethodInput = schema.object({
57
+ param1: schema.string(),
58
+ });
59
+
60
+ export default class ServiceNameController extends Controller<AppType> {
61
+
62
+ public async methodName() {
63
+ const input = this.input(MethodInput);
64
+ const currentUser = this.request.auth.check('USER', null);
65
+
66
+ return this.services.ServiceName.methodName({
67
+ ...input,
68
+ currentUser,
69
+ });
70
+ }
71
+ }
72
+ ```
73
+
74
+ Replace `AppType` with the local app type if the surrounding controllers use a generic.
75
+ Place the controller under the path that should drive the public API shape, for example `/server/controllers/ServiceName.ts` or `/server/controllers/ServiceName/subFeature.ts`.
76
+
77
+ Rules:
78
+ - Only files under `/server/controllers/**/*.ts` are indexed as callable API endpoints
79
+ - Route path is derived from the controller file path and the method name
80
+ - `this.input(schema)` is the only validation entrypoint
81
+ - Call `this.input(...)` at most once per controller method
82
+ - Request-scoped state exists only on `this.request`
83
+ - Keep controllers thin and push business logic into services
84
+ - Extract auth and request-derived values in the controller and pass explicit typed arguments into services
85
+
86
+ ## 3. Create the service metas file in `/server/services/<service name>/service.json`
87
+
88
+ ```json
89
+ {
90
+ "id": "<AppIdentifier>/ServiceName",
91
+ "name": "ServiceName",
92
+ "parent": "app",
93
+ "dependences": []
94
+ }
95
+ ```
96
+
97
+ Use the same id namespace and naming convention as neighboring services in the project.
98
+
99
+ ## 4. Add a typed config export in `/server/config/*.ts` and instantiate the service in `/server/index.ts`
100
+
101
+ ```typescript
102
+ // server/config/feature.ts
103
+ import { Services } from '@server/app';
104
+ import ServiceName from '@/server/services/ServiceName';
105
+
106
+ export const serviceNameConfig = Services.config(ServiceName, {});
107
+ ```
108
+
109
+ ```typescript
110
+ // server/index.ts
111
+ import { Application } from '@server/app';
112
+ import ServiceName from '@/server/services/ServiceName';
113
+ import * as featureConfig from '@/server/config/feature';
114
+
115
+ export default class MyApp extends Application {
116
+ public ServiceName = new ServiceName(this, featureConfig.serviceNameConfig, this);
117
+ }
118
+ ```
119
+
120
+ Match the existing config-grouping and namespace-import convention in the project instead of inventing a new bootstrap shape.
121
+
122
+ ## 5. Keep classes clean
123
+
124
+ If the class grows too large, split business concerns into subservices.
125
+
126
+ ## 6. Use request-aware features only in controllers
127
+
128
+ Use:
129
+
130
+ ```typescript
131
+ const { auth, request, user, response } = this.request;
132
+ ```
133
+
134
+ - Never import runtime request state from `@request`
135
+ - Never access request-scoped state inside normal service methods
136
+ - If a service needs user identity, locale, cookies, or another request-derived value, compute it in the controller and pass only that value
137
+
138
+ ## 7. Fetch and return data from the database
139
+
140
+ Use runtime models through `this.models`:
141
+
142
+ ```typescript
143
+ const users = await this.models.user.findMany({
144
+ select: {
145
+ id: true,
146
+ },
147
+ });
148
+ ```
149
+
150
+ Use prisma typings through `@models/types` only:
151
+
152
+ ```typescript
153
+ import type * as Models from '@models/types';
154
+ ```
155
+
156
+ Rules:
157
+ - Never edit prisma files, except the schema
158
+ - Never use runtime `@models` imports
159
+ - If you need generated runtime Prisma enums or helpers already emitted by Proteum, follow the local `@generated/server/models` import pattern
160
+ - In all queries and joins, always specify what fields to select
161
+
162
+ ## DTO and typing rules
163
+
164
+ - Prefer inferred return types:
165
+ `export type TResult = Awaited<ReturnType<MyService["MethodName"]>>;`
166
+ - Never create manual DTO types when the exact return type can be inferred
167
+
168
+ ## Errors handling
169
+
170
+ Never silence caught errors. Throw `Anomaly` with enough detail and the original error when needed.
@@ -6,3 +6,4 @@
6
6
  - Add `data-testid` where needed
7
7
  - Keep test files clean, organized and structured
8
8
  - Test the current controller/page runtime model, not legacy `@Route` or `api.fetch` behavior
9
+ - Reuse root catalog files from `/client/catalogs/**`, `/server/catalogs/**`, or `/common/catalogs/**` instead of duplicating catalog constants inside tests
package/cli/app/config.ts CHANGED
@@ -16,6 +16,7 @@ import yaml from 'yaml';
16
16
 
17
17
  // Types
18
18
  import type { TEnvConfig } from '../../server/app/container/config';
19
+ import { logVerbose } from '../runtime/verbose';
19
20
 
20
21
  /*----------------------------------
21
22
  - LOADE
@@ -28,7 +29,7 @@ export default class ConfigParser {
28
29
  ) {}
29
30
 
30
31
  private loadYaml(filepath: string) {
31
- console.info(`Loading config ${filepath}`);
32
+ logVerbose(`Loading config ${filepath}`);
32
33
  const rawConfig = fs.readFileSync(filepath, 'utf-8');
33
34
  return yaml.parse(rawConfig);
34
35
  }
@@ -36,7 +37,7 @@ export default class ConfigParser {
36
37
  public env(): TEnvConfig {
37
38
  // We assume that when we run 5htp dev, we're in local
38
39
  // Otherwise, we're in production environment (docker)
39
- console.log('[app] Using environment:', process.env.NODE_ENV);
40
+ logVerbose('[app] Using environment:', process.env.NODE_ENV);
40
41
  const envFileName = this.appDir + '/env.yaml';
41
42
  const envFile = this.loadYaml(envFileName);
42
43
  return {
package/cli/app/index.ts CHANGED
@@ -20,12 +20,6 @@ import type { TEnvConfig } from '../../server/app/container/config';
20
20
 
21
21
  export type TAppSide = 'server' | 'client';
22
22
 
23
- type TServiceSetup = { id: string; name: string; config: {}; subservices: TServiceSubservices; type: 'service.setup' };
24
-
25
- type TServiceRef = { refTo: string; type: 'service.ref' };
26
-
27
- type TServiceSubservices = { [key: string]: TServiceSetup | TServiceRef };
28
-
29
23
  const parseRouterPortOverride = (rawPort: string | boolean | string[] | undefined): number | undefined => {
30
24
  if (rawPort === undefined || rawPort === '') return undefined;
31
25
 
@@ -65,13 +59,14 @@ export class App {
65
59
  public: path.join(cli.paths.appRoot, 'public'),
66
60
  pages: path.join(cli.paths.appRoot, 'client', 'pages'),
67
61
  cache: path.join(cli.paths.appRoot, '.cache'),
62
+ proteum: path.join(cli.paths.appRoot, '.proteum'),
68
63
 
69
- client: { generated: path.join(cli.paths.appRoot, 'client', '.generated') },
64
+ client: { generated: path.join(cli.paths.appRoot, '.proteum', 'client') },
70
65
  server: {
71
- generated: path.join(cli.paths.appRoot, 'server', '.generated'),
72
- configs: path.join(cli.paths.appRoot, 'server', 'app'),
66
+ entry: path.join(cli.paths.appRoot, 'server', 'index.ts'),
67
+ generated: path.join(cli.paths.appRoot, '.proteum', 'server'),
73
68
  },
74
- common: { generated: path.join(cli.paths.appRoot, 'common', '.generated') },
69
+ common: { generated: path.join(cli.paths.appRoot, '.proteum', 'common') },
75
70
 
76
71
  withAlias: (filename: string, side: TAppSide) => this.aliases[side].apply(filename),
77
72
 
@@ -122,63 +117,8 @@ export class App {
122
117
  return fs.readJSONSync(this.paths.root + '/package.json');
123
118
  }
124
119
 
125
- /*----------------------------------
126
- - WARMUP (Services awareness)
127
- ----------------------------------*/
128
-
129
- public registered = {};
130
-
131
- public use(referenceName: string): TServiceRef {
132
- // We don't check because all service are not regstered when we register subservices
133
- /*if (this.registered[referenceName] === undefined) {
134
- throw new Error(`Service ${referenceName} is not registered`);
135
- }*/
136
-
137
- return { refTo: referenceName, type: 'service.ref' };
138
- }
139
-
140
- public setup(
141
- ...args:
142
- | [
143
- // { user: app.setup('Core/User') }
144
- servicePath: string,
145
- serviceConfig?: {},
146
- ]
147
- | [
148
- // app.setup('User', 'Core/User')
149
- serviceName: string,
150
- servicePath: string,
151
- serviceConfig?: {},
152
- ]
153
- ): TServiceSetup {
154
- // Registration to app root
155
- if (typeof args[1] === 'string') {
156
- const [name, id, config] = args;
157
-
158
- const service = { id, name, config, type: 'service.setup' } as TServiceSetup;
159
-
160
- this.registered[name] = service;
161
-
162
- return service;
163
-
164
- // Scoped to a parent service
165
- } else {
166
- const [id, config] = args;
167
-
168
- const service = { id, config, type: 'service.setup' } as TServiceSetup;
169
-
170
- return service;
171
- }
172
- }
173
-
174
120
  public async warmup() {
175
- // Require all config files in @/server/config
176
- const configDir = path.resolve(cli.paths.appRoot, 'server', 'config');
177
- const configFiles = fs.readdirSync(configDir);
178
- for (const configFile of configFiles) {
179
- console.log('Loading config file:', configFile);
180
- require(path.resolve(configDir, configFile));
181
- }
121
+ return Promise.resolve();
182
122
  }
183
123
  }
184
124
 
package/cli/bin.js CHANGED
@@ -21,7 +21,7 @@ const path = require('path');
21
21
  if (!process.env.TS_NODE_IGNORE) {
22
22
  process.env.TS_NODE_IGNORE = [
23
23
  // Default ts-node ignore rule (works when deps are nested under `../node_modules/...`)
24
- '(node_modules\/(?!proteum\/))|(\.generated\/)|(\.cache\/)',
24
+ '(node_modules\/(?!proteum\/))|(\.generated\/)|(\.cache\/)|(\.proteum\/)',
25
25
  // Extra rule for deps hoisted next to Proteum (ex: `../../tailwindcss/...`)
26
26
  '^\\.\\./\\.\\./(?!\\./|\\.\\./)[^/]+/',
27
27
  ].join(',');
@@ -32,4 +32,9 @@ process.env.TS_NODE_TRANSPILE_ONLY = '1';
32
32
 
33
33
  require('ts-node/register/transpile-only');
34
34
 
35
- require('./index.ts');
35
+ const { runCli } = require('./index.ts');
36
+
37
+ Promise.resolve(runCli()).catch((error) => {
38
+ console.error(error);
39
+ process.exit(1);
40
+ });