proteum 2.1.0-2 → 2.1.0-3

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 (37) hide show
  1. package/AGENTS.md +51 -93
  2. package/README.md +44 -1
  3. package/agents/framework/AGENTS.md +155 -788
  4. package/agents/project/AGENTS.md +81 -110
  5. package/agents/project/client/AGENTS.md +22 -93
  6. package/agents/project/client/pages/AGENTS.md +24 -26
  7. package/agents/project/server/routes/AGENTS.md +10 -8
  8. package/agents/project/server/services/AGENTS.md +22 -159
  9. package/agents/project/tests/AGENTS.md +11 -8
  10. package/cli/commands/dev.ts +1 -0
  11. package/cli/commands/trace.ts +210 -0
  12. package/cli/compiler/client/index.ts +30 -8
  13. package/cli/compiler/server/index.ts +28 -6
  14. package/cli/paths.ts +16 -1
  15. package/cli/presentation/commands.ts +23 -1
  16. package/cli/presentation/devSession.ts +5 -0
  17. package/cli/runtime/commands.ts +31 -0
  18. package/common/dev/requestTrace.ts +81 -0
  19. package/docs/request-tracing.md +115 -0
  20. package/package.json +1 -1
  21. package/server/app/container/config.ts +15 -0
  22. package/server/app/container/index.ts +3 -0
  23. package/server/app/container/trace/index.ts +284 -0
  24. package/server/services/prisma/index.ts +61 -5
  25. package/server/services/router/http/index.ts +40 -0
  26. package/server/services/router/index.ts +159 -6
  27. package/server/services/router/response/index.ts +80 -7
  28. package/server/services/router/response/page/document.tsx +16 -0
  29. package/server/services/router/response/page/index.tsx +27 -1
  30. package/Rte.zip +0 -0
  31. package/agents/project/agents.md.zip +0 -0
  32. package/doc/TODO.md +0 -71
  33. package/doc/front/router.md +0 -27
  34. package/doc/workspace/workspace.png +0 -0
  35. package/doc/workspace/workspace2.png +0 -0
  36. package/doc/workspace/workspace_26.01.22.png +0 -0
  37. package/server/services/router/http/session.ts.old +0 -40
@@ -1,487 +1,118 @@
1
- # Proteum Framework Guide
1
+ # Proteum App Contract
2
2
 
3
- This document is the framework-level contract for building and maintaining a Proteum project.
3
+ This is the canonical framework contract for Proteum-based projects.
4
4
 
5
- It is based on the current Proteum core plus the two real apps used as the reference surface:
5
+ Local project `AGENTS.md` files should only add project-specific deltas. They should not restate the framework contract.
6
6
 
7
- - `crosspath/platform`
8
- - `unique.domains/website`
7
+ ## Fast Start
9
8
 
10
- Use this guide for new work. Treat older patterns in the apps as legacy unless they are explicitly described here as still-supported.
9
+ When you enter a Proteum app, inspect it in this order:
11
10
 
12
- # What Proteum is
11
+ 1. Run `npx proteum explain --json` or read `./.proteum/manifest.json`.
12
+ 2. Inspect `./server/index.ts` and `./server/config/*.ts`.
13
+ 3. Inspect the touched `./server/controllers/**/*.ts`, `./server/services/**`, `./server/routes/**`, and `./client/pages/**` files.
14
+ 4. Run `npx proteum doctor` if routing or generation looks suspicious.
15
+ 5. For request-time issues in dev, use `npx proteum trace` before adding temporary logs.
13
16
 
14
- Proteum is a server-first SSR framework with:
17
+ ## Non-Negotiable Rules
15
18
 
16
- - explicit `Router.page(...)` client page registration
17
- - explicit `server/controllers/**/*.ts` server API entrypoints
18
- - service classes for business logic
19
- - generated controller trees and generated route modules
20
- - request-scoped server context
21
- - strong bias toward SEO-friendly SSR HTML and minimal client runtime assumptions
22
-
23
- The main rule for new work is:
24
-
25
- - keep routing, data loading, validation, request access, and service boundaries explicit
26
-
27
- # Non-negotiable rules
28
-
29
- - Client pages live in `client/pages/**` and register routes with `Router.page(...)` or `Router.error(...)`.
19
+ - Client pages live in `client/pages/**` and register routes with top-level `Router.page(...)` or `Router.error(...)` calls.
30
20
  - Page URLs come from the explicit `Router.page('/path', ...)` call, not from the file path.
31
- - Server business logic lives in service classes that extend `Service`.
32
- - Callable API entrypoints live only in `server/controllers/**/*.ts` files that extend `Controller`.
21
+ - Callable app APIs live only in `server/controllers/**/*.ts` files that extend `Controller`.
22
+ - Manual HTTP endpoints live in `server/routes/**`.
33
23
  - Controllers validate input with `this.input(schema)` inside the method body.
34
24
  - Call `this.input(...)` at most once per controller method.
35
- - Controller methods are exposed to the client under `/api/...` and are always called as `POST` fetchers.
36
- - Manual server routes belong in `server/routes/**` and use `Router.get/post/put/patch/delete(...)`.
37
- - Import Prisma types from `@models/types`.
25
+ - Request-scoped state exists only on `this.request` and router/manual-route context objects.
26
+ - SSR page data belongs in the page `setup` return object, not in `api.fetch(...)`.
27
+ - Normal service methods do not read request state directly.
38
28
  - Do not import runtime values from `@models`.
39
29
  - Do not use `@request` runtime globals.
40
30
  - Do not use `@app` on the client.
41
- - Do not use `api.fetch(...)` inside page route files for SSR data loading.
42
31
  - Do not edit generated files under `.proteum` by hand.
32
+ - Prefer type inference rooted in the explicit application graph in `server/index.ts`.
43
33
 
44
- # Source Of Truth Files
34
+ ## Source Of Truth
45
35
 
46
- The framework actually reads these files and folders:
36
+ Proteum reads these source files directly:
47
37
 
48
- - `package.json`: CLI scripts and dependency entrypoint
49
- - `identity.yaml`: app identity and web metadata
50
- - `env.yaml`: runtime environment config that Proteum loads directly
51
- - `server/config/*.ts`: plain typed config exports consumed by the explicit app bootstrap
52
- - `server/index.ts`: default-exported `Application` subclass that instantiates root services and router plugins
53
- - `server/services/**/service.json`: root service or router-plugin metadata
54
- - `server/controllers/**/*.ts`: generated API surface
55
- - `server/routes/**/*.ts`: manual server routes
56
- - `client/pages/**/*.ts(x)`: page and error registration
57
- - `client/pages/**/_layout/index.tsx`: generated layouts
58
- - `public/**`: copied or symlinked to dev/build output
38
+ - `package.json`
39
+ - `identity.yaml`
40
+ - `env.yaml`
41
+ - `server/config/*.ts`
42
+ - `server/index.ts`
43
+ - `server/services/**/service.json`
44
+ - `server/controllers/**/*.ts`
45
+ - `server/routes/**/*.ts`
46
+ - `client/pages/**/*.ts(x)`
47
+ - `client/pages/**/_layout/index.tsx`
48
+ - `public/**`
59
49
 
60
- Files Proteum generates and owns:
50
+ Proteum generates and owns:
61
51
 
62
52
  - `.proteum/manifest.json`
63
- - `.proteum/client/routes*`
64
- - `.proteum/client/layouts*`
65
- - `.proteum/client/context.ts`
66
- - `.proteum/client/models.ts`
67
- - `.proteum/client/services.d.ts`
68
- - `.proteum/common/controllers.ts`
69
- - `.proteum/common/models.ts`
70
- - `.proteum/server/routes*`
71
- - `.proteum/server/models.ts`
72
-
73
- The `.proteum` directory should be ignored by git.
74
-
75
- Generated files now live physically under `.proteum/client/*`, `.proteum/common/*`, and `.proteum/server/*`.
76
- Project code should reference the generated surface through `@generated/client/*`, `@generated/common/*`, and `@generated/server/*`.
77
- Keep `@/client/context` mapped to `.proteum/client/context.ts`.
78
- The legacy `@/client/.generated/*`, `@/common/.generated/*`, and `@/server/.generated/*` aliases may exist temporarily as migration shims, but new code should not use them.
79
-
80
- # Project Structure
81
-
82
- Use this shape for real work:
83
-
84
- - `client/pages`: route files and page-local UI
85
- - `client/components`: reusable UI
86
- - `client/hooks` or local hooks near the feature
87
- - `common`: shared types, catalogs, utilities safe across client/server
88
- - `server/config`: typed service config exports used by `server/index.ts`
89
- - `server/index.ts`: explicit app bootstrap and root service graph
90
- - `server/services`: business services
91
- - `server/controllers`: callable API entrypoints
92
- - `server/routes`: manual HTTP routes that should not be generated from controllers
93
- - `public`: static assets
94
- - `prisma`: schema and Prisma assets
95
- - `tests/e2e`: end-to-end tests
96
-
97
- The two reference apps both follow this split even when their internal feature folders differ.
98
-
99
- # Project Creation Today
100
-
101
- What the code says today:
102
-
103
- - Proteum exposes `proteum init`.
104
- - The current `init` command expects a `cli/skeleton` directory.
105
- - This repository currently does not contain that `cli/skeleton` directory.
106
-
107
- Practical consequence:
108
-
109
- - In this checkout, the reliable way to start a new app is to copy a working Proteum project structure from an existing app, then replace the identity, env, config, services, pages, and Prisma schema.
110
-
111
- If `proteum init` is restored later, re-check the skeleton before relying on it.
112
-
113
- # Required Root Files
114
-
115
- ## `package.json`
116
-
117
- The reference apps use these Proteum commands:
118
-
119
- - `proteum dev`
120
- - `npx proteum build prod`
121
- - `npx proteum refresh`
122
- - `npx proteum doctor`
123
- - `npx proteum explain`
124
- - `npx proteum typecheck`
125
- - `npx proteum lint`
126
- - `npx proteum check`
127
-
128
- ## `proteum explain`
129
-
130
- Proteum now generates a machine-readable manifest at `.proteum/manifest.json` during refresh/build/dev/explain flows.
131
-
132
- Use `proteum explain` as the first inspection command when an agent needs to understand a project without re-deriving framework conventions from source.
133
-
134
- Useful commands:
135
-
136
- - `npx proteum explain`
137
- - `npx proteum explain --json`
138
- - `npx proteum explain routes --json`
139
- - `npx proteum explain services`
140
- - `npx proteum explain controllers`
141
- - `npx proteum explain env`
142
-
143
- What the manifest exposes:
144
-
145
- - app root and installed Proteum root
146
- - identity file path and identity summary
147
- - env file path plus loaded and required top-level keys
148
- - top-level services and router plugins with source file ownership and scope
149
- - generated controller endpoints with client accessor and HTTP path
150
- - client pages, error pages, and manual server routes with explicit route expressions
151
- - route and controller source locations
152
- - static route-target resolution state: literal, statically-resolved expression, or dynamic expression
153
- - client layout ownership and chunk ids
154
- - manifest-backed diagnostics for duplicate routes, invalid option keys, and controller/server-route collisions
155
-
156
- ## `proteum doctor`
157
-
158
- Use `npx proteum doctor` to inspect manifest diagnostics in a human-readable form.
159
-
160
- Use:
161
-
162
- - `npx proteum doctor`
163
- - `npx proteum doctor --json`
164
- - `npx proteum doctor --strict`
165
-
166
- Current strict-mode behavior:
167
-
168
- - exits non-zero if any manifest warning or error exists
169
- - intended for CI and agent guardrails
170
-
171
- ## `identity.yaml`
172
-
173
- Proteum loads `identity.yaml` directly. It must define:
174
-
175
- - `name`
176
- - `identifier`
177
- - `description`
178
- - `author`
179
- - `language`
180
- - optional `locale`
181
- - `maincolor`
182
- - optional `iconsPack`
183
- - `web.title`
184
- - `web.titleSuffix`
185
- - `web.fullTitle`
186
- - `web.description`
187
- - `web.version`
188
- - optional `web.metas`
189
- - optional `web.jsonld`
190
-
191
- The generated app type uses `identifier`.
192
-
193
- ## `env.yaml`
194
-
195
- Proteum currently loads `env.yaml` directly through `ConfigParser`.
196
-
197
- The core parser expects at least:
198
-
199
- - `name`
200
- - `profile`
201
- - `router.port`
202
- - `router.domains`
203
- - `console`
204
-
205
- Observed reality:
206
-
207
- - the apps also keep files like `env.prod.yaml` and `env.testing.yaml`
208
- - the current core parser shown here does not automatically merge those files
209
-
210
- So for framework-level correctness:
211
-
212
- - treat `env.yaml` as the authoritative runtime config file unless you also own a custom deploy flow around it
213
-
214
- # App Bootstrap
215
-
216
- Bootstrap is explicit.
217
-
218
- Use `server/config/*.ts` for typed config exports and `server/index.ts` for the application class that wires services together.
219
-
220
- Example config module:
221
-
222
- ```ts
223
- import { Services, type ServiceConfig } from '@server/app';
224
- import AppContainer from '@server/app/container';
225
- import Router from '@server/services/router';
226
- import Users from '@/server/services/Users';
227
-
228
- type RouterBaseConfig = Omit<ServiceConfig<typeof Router>, 'plugins'>;
229
-
230
- export const usersConfig = Services.config(Users, {});
231
-
232
- export const routerBaseConfig = {
233
- domains: AppContainer.Environment.router.domains,
234
- http: {
235
- domain: 'example.com',
236
- port: AppContainer.Environment.router.port,
237
- ssl: true,
238
- upload: { maxSize: '10mb' },
239
- },
240
- context: () => ({}),
241
- } satisfies RouterBaseConfig;
242
- ```
243
-
244
- Example app bootstrap:
245
-
246
- ```ts
247
- import { Application } from '@server/app';
248
- import Router from '@server/services/router';
249
- import SchemaRouter from '@server/services/schema/router';
250
- import Users from '@/server/services/Users';
251
- import * as userConfig from '@/server/config/user';
252
-
253
- export default class MyApp extends Application {
254
- public Users = new Users(this, userConfig.usersConfig, this);
255
- public Router = new Router(this, {
256
- ...userConfig.routerBaseConfig,
257
- plugins: {
258
- schema: new SchemaRouter({}, this),
259
- },
260
- }, this);
261
- }
262
- ```
263
-
264
- Important bootstrap rules:
53
+ - `.proteum/client/*`
54
+ - `.proteum/common/*`
55
+ - `.proteum/server/*`
265
56
 
266
- - `server/index.ts` must default-export the app `Application` subclass.
267
- - Each root service is a public class field instantiated with `new ServiceClass(this, config, this)`.
268
- - `server/config/*.ts` should export plain typed constants with `Services.config(ServiceClass, { ... })`.
269
- - Router base config can use `Omit<ServiceConfig<typeof Router>, 'plugins'>` so router plugins are instantiated explicitly in `server/index.ts`.
270
- - Router plugins are configured inside the `Router` config `plugins` object as explicit `new PluginClass(config, this)` instances.
271
- - Router `context(request, app)` returns SSR-safe values exposed to both page setup/render and the client runtime.
272
- - Both reference apps expose a SSR-safe `user` object through `Router.context(...)`.
273
- - Generated service typings and manifests are derived from `server/index.ts` plus `server/services/**/service.json`.
57
+ Project code should use:
274
58
 
275
- # Services
59
+ - `@generated/client/*`
60
+ - `@generated/common/*`
61
+ - `@generated/server/*`
62
+ - `@/client/context` for the generated client context entrypoint
276
63
 
277
- ## Root service contract
64
+ Use the structured CLI surfaces instead of re-deriving framework facts from source whenever possible:
278
65
 
279
- Each root app service normally has:
66
+ - `npx proteum explain --json`: app structure, services, controllers, routes, layouts, diagnostics
67
+ - `npx proteum doctor --json`: manifest-backed diagnostics
68
+ - `npx proteum trace ...`: live dev-only request traces
280
69
 
281
- - `server/services/<Feature>/index.ts`
282
- - `server/services/<Feature>/service.json`
70
+ ## App Bootstrap And Services
283
71
 
284
- Example `service.json`:
285
-
286
- ```json
287
- {
288
- "id": "UniqueDomains/Founder",
289
- "name": "UniqueDomainsFounder",
290
- "parent": "app",
291
- "dependences": []
292
- }
293
- ```
72
+ `server/index.ts` is the canonical type root and the explicit application graph.
294
73
 
295
74
  Rules:
296
75
 
297
- - `parent` is `"app"` for normal root services.
298
- - `id` is the service identifier declared in `service.json` and used by manifests plus `Service.use('Service/Id')`.
299
- - `name` is metadata for generated registration.
300
- - `priority` is optional and used by some services.
301
-
302
- ## Service class contract
303
-
304
- Service classes extend `Service<Config, Hooks, App, Parent>`.
305
-
306
- Use services for:
307
-
308
- - database reads and writes
309
- - orchestration
310
- - feature logic
311
- - subservice composition
312
- - startup work in `ready()`
313
-
314
- Available on a service instance:
315
-
316
- - `this.app`: application instance
317
- - `this.services`: same application instance as a service registry
318
- - `this.models`: runtime Prisma client, if `Models` is registered
319
-
320
- Example:
321
-
322
- ```ts
323
- import Service from '@server/app/service';
324
-
325
- export type Config = {
326
- pageSize: number;
327
- };
328
-
329
- export default class FounderService extends Service<Config, {}, MyApp, MyApp> {
330
- public async ListProjects(input: { userId: number }) {
331
- return this.models.project.findMany({
332
- where: { userId: input.userId },
333
- select: {
334
- id: true,
335
- name: true,
336
- },
337
- });
338
- }
339
- }
340
- ```
76
+ - `server/index.ts` must default-export the app `Application` subclass
77
+ - root services are public class fields instantiated with `new ServiceClass(this, config, this)`
78
+ - typed root-service config lives in `server/config/*.ts` via `Services.config(ServiceClass, { ... })`
79
+ - router plugins are instantiated explicitly inside the `Router` config `plugins` object
80
+ - `server/services/**/service.json` plus `server/index.ts` drive generated service typings and manifest service entries
341
81
 
342
82
  Service rules:
343
83
 
344
- - Prefer `this.services.OtherService` over hidden globals.
345
- - Prefer `this.models` or `this.app.Models.client` for Prisma runtime access.
346
- - Keep auth, input parsing, and request handling in controllers.
347
- - Pass explicit typed values into services instead of reading request state inside services.
348
- - Prefer service inputs that are easy to test without a live request context.
349
-
350
- ## Subservices
351
-
352
- Both reference apps use service-owned subservices heavily.
353
-
354
- Example:
355
-
356
- ```ts
357
- export default class DomainsService extends Service<Config, {}, UniqueDomains, UniqueDomains> {
358
- public search = new DomainsSearchService(this, this.config, this.app);
359
- public radar = new DomainsRadarService(this, null, this.app);
360
- }
361
- ```
362
-
363
- Use subservices when:
364
-
365
- - a feature has multiple coherent domains
366
- - you want controller paths like `Domains.search.*` or `Founder.projects.*`
367
- - you want smaller files and explicit ownership
368
-
369
- # Controllers
370
-
371
- ## File contract
372
-
373
- Controller files must:
374
-
375
- - live under `server/controllers/**/*.ts`
376
- - default-export a class extending `Controller`
377
-
378
- Example:
379
-
380
- ```ts
381
- import Controller, { schema } from '@server/app/controller';
382
-
383
- export default class FounderProjectsController extends Controller<MyApp> {
384
- public async createProject() {
385
- const { Founder } = this.services;
386
-
387
- const data = this.input(
388
- schema.object({
389
- name: schema.string(),
390
- }),
391
- );
392
-
393
- return Founder.projects.createProject(data);
394
- }
395
- }
396
- ```
397
-
398
- ## Validation contract
399
-
400
- Use `this.input(...)` exactly once per controller method.
401
-
402
- Supported forms:
403
-
404
- - `this.input(zodSchema)`
405
- - `this.input({ ...shape })`
406
-
407
- Do not:
408
-
409
- - validate in decorators
410
- - call `this.input(...)` twice
411
- - parse request data manually unless you are in a manual `server/routes` handler
412
-
413
- ## Request contract
414
-
415
- Controllers receive request scope through `this.request`.
416
-
417
- Typical values:
418
-
419
- - `this.request.request`: raw request object wrapper
420
- - `this.request.response`
421
- - `this.request.user`
422
- - `this.request.auth`
423
- - `this.request.schema`
424
- - `this.request.metrics`
425
- - `this.request.request.data`
426
-
427
- The exact plugin fields depend on the router plugins configured in `server/index.ts`.
428
-
429
- ## Route generation
430
-
431
- Proteum generates controller endpoints automatically.
432
-
433
- Key facts:
434
-
435
- - Only `server/controllers/**/*.ts` files are indexed.
436
- - Only class methods with bodies become routes.
437
- - The client-facing route is always prefixed with `/api/`.
438
- - Generated client calls use `POST`, even for read methods such as `Get`, `List`, or `Search`.
439
-
440
- Route path derivation:
441
-
442
- - base path comes from the controller file path
443
- - method name becomes the final route segment
444
- - `export const controllerPath = 'Custom/path'` overrides the base path
445
-
446
- Examples from the reference apps:
84
+ - business logic lives in classes that extend `Service`
85
+ - use `this.services`, `this.models`, and `this.app`
86
+ - keep auth, input parsing, locale, cookies, and request-derived values in controllers, then pass explicit typed arguments into services
87
+ - use subservices when a feature has multiple coherent domains and the root class is growing
447
88
 
448
- - `server/controllers/Auth.ts#Session()` becomes `Auth.Session()` on the client and maps to `/api/Auth/Session`
449
- - `server/controllers/Domains/search.ts#Search()` becomes `Domains.search.Search()`
450
- - `server/controllers/Companies/Persons.ts` can override the base path with `controllerPath = 'Companies/Persons'`
89
+ ## Controllers
451
90
 
452
- Naming rule:
91
+ Controller rules:
453
92
 
454
- - method names become public API names
455
- - choose method names deliberately because client code will call them directly
93
+ - files live under `server/controllers/**/*.ts`
94
+ - each file default-exports a class extending `Controller`
95
+ - methods with bodies become generated client-callable endpoints
96
+ - route path comes from the controller file path plus the method name
97
+ - `export const controllerPath = 'Custom/path'` can override the base path when needed
98
+ - generated client calls use `POST`
456
99
 
457
- # Client Pages
100
+ Controller workflow:
458
101
 
459
- ## File contract
102
+ 1. destructure the service or router helper you need
103
+ 2. validate once with `this.input(schema)`
104
+ 3. resolve auth and other request-derived values from `this.request`
105
+ 4. pass explicit typed values into a service method
460
106
 
461
- Client pages live in `client/pages/**`.
107
+ ## Client Pages
462
108
 
463
- Proteum scans page files for top-level `Router.page(...)` and `Router.error(...)` calls.
464
-
465
- Important compiler rule:
109
+ Compiler rules:
466
110
 
111
+ - Proteum scans page files for top-level `Router.page(...)` and `Router.error(...)` calls
467
112
  - the file path controls chunk identity and layout discovery
468
- - the URL comes from the explicit route path string in `Router.page(...)`
469
-
470
- Do not hide route registration inside helper abstractions that remove the direct top-level `Router.page(...)` call.
471
-
472
- ## Import contract
473
-
474
- Use:
475
-
476
- ```ts
477
- import Router from '@/client/router';
478
- ```
113
+ - the route path comes from the explicit string in `Router.page(...)`
479
114
 
480
- Do not use `@app` on the client.
481
-
482
- ## Supported signatures
483
-
484
- Proteum supports these `Router.page(...)` signatures:
115
+ Supported signatures:
485
116
 
486
117
  ```ts
487
118
  Router.page('/path', render);
@@ -490,262 +121,75 @@ Router.page('/path', options, render);
490
121
  Router.page('/path', options, setup, render);
491
122
  ```
492
123
 
493
- New work should usually prefer:
124
+ For new work, prefer:
494
125
 
495
126
  ```ts
496
127
  Router.page('/path', setup, render);
497
- ```
498
-
499
- or:
500
-
501
- ```ts
502
128
  Router.page('/path', options, setup, render);
503
129
  ```
504
130
 
505
- ## Setup function
506
-
507
- `setup` is the SSR contract. It receives:
508
-
509
- - router context
510
- - generated controller tree
511
- - custom router context values like `user`
512
- - request query/path params in `data`
513
-
514
- Return one flat object.
515
-
516
- Proteum splits that object into:
517
-
518
- - route options
519
- - SSR data providers
520
-
521
- Supported route option keys are:
522
-
523
- - `_priority`
524
- - `_preload`
525
- - `_domain`
526
- - `_accept`
527
- - `_raw`
528
- - `_auth`
529
- - `_redirectLogged`
530
- - `_static`
531
- - `_whenStatic`
532
- - `_canonicalParams`
533
- - `_layout`
534
- - `_TESTING`
535
- - `_logging`
536
-
537
- The underscore is optional in the framework code, but both reference apps use the underscore form and new work should do the same.
538
-
539
- Everything else returned from `setup` is treated as page data.
540
-
541
- Example:
542
-
543
- ```ts
544
- Router.page('/pricing', ({ Plans }) => ({
545
- _auth: false,
546
- _layout: false,
547
- plans: Plans.getPlans(),
548
- }), ({ plans }) => <PricingPage plans={plans} />);
549
- ```
550
-
551
- ## Data loading rules
552
-
553
- Use page `setup` for SSR data.
554
-
555
- Good:
556
-
557
- ```ts
558
- Router.page('/app/projects/:projectId', ({ Founder }) => ({
559
- _auth: 'USER',
560
- projectsResponse: Founder.projects.getProjects(),
561
- }), ({ projectsResponse }) => <ProjectsPage projects={projectsResponse.projects} />);
562
- ```
563
-
564
- Bad:
565
-
566
- - calling `api.fetch(...)` inside the page file to preload SSR data
567
- - moving SSR data fetching into random effects when the page can know it up front
568
-
569
- How setup data works:
131
+ `setup` rules:
570
132
 
133
+ - return one flat object
134
+ - keys like `_auth`, `_layout`, `_static`, `_redirectLogged`, and other reserved setup keys are route options
135
+ - every other key is SSR data
571
136
  - controller fetchers and promises are resolved before render
572
- - SSR fetchers are batched through a single `/api` request internally
573
- - plain values can also be returned from `setup`
574
-
575
- ## Render function
576
-
577
- `render` receives:
578
-
579
- - the same router context
580
- - resolved setup data
581
- - the generated controller tree
582
- - `page`
583
- - `request`
584
- - `api`
585
- - custom router context like `user`
586
-
587
- Use it for:
588
-
589
- - page-local React/Preact state
590
- - calling controller methods on interaction
591
- - assigning page metadata on `page`
592
-
593
- Example:
594
-
595
- ```ts
596
- ({ request, page, Founder }) => {
597
- page.metas.robots = 'noindex';
137
+ - plain values may also be returned
598
138
 
599
- return <Page />;
600
- }
601
- ```
139
+ `render` rules:
602
140
 
603
- ## Error pages
141
+ - consume resolved setup data there
142
+ - use generated controller methods from the render args or `@/client/context`
143
+ - use `api.reload(...)` or `api.set(...)` only when intentionally mutating active page setup state
604
144
 
605
- Use `Router.error(code, options, render)` in `client/pages/_messages/**`.
145
+ Error pages:
606
146
 
607
- Example:
147
+ - use `Router.error(code, options, render)` in `client/pages/_messages/**`
608
148
 
609
- ```ts
610
- Router.error(404, { layout: false }, ({ data }) => <ErrorScreen code={404} data={data} />);
611
- ```
149
+ ## Client Context And Controller Calls
612
150
 
613
- # Client Context And Controller Calls
614
-
615
- Proteum generates a client context and controller tree.
616
-
617
- Use:
151
+ Use the generated client context entrypoint:
618
152
 
619
153
  ```ts
620
154
  import useContext from '@/client/context';
621
-
622
- const { Founder, user, Router, api } = useContext();
623
155
  ```
624
156
 
625
- Generated controller methods are promise-like fetchers:
626
-
627
- - `then`
628
- - `catch`
629
- - `finally`
630
- - `run()`
631
-
632
- So all of these are valid:
157
+ Then call generated controllers directly:
633
158
 
634
159
  ```ts
635
- Founder.projects.getProjects().then(...);
160
+ const { Founder } = useContext();
636
161
  await Founder.projects.updateProject(payload);
637
- await Founder.projects.updateProject(payload).run();
638
162
  ```
639
163
 
640
- Modern usage in both apps is mostly direct `await` or `.then(...)`.
641
-
642
- Use `api.reload(...)` and `api.set(...)` only when you intentionally want to refresh or mutate page setup data that already belongs to the active page response.
643
-
644
- # Layouts
645
-
646
- Layouts come from `client/pages/**/_layout/index.tsx`.
647
-
648
- How Proteum resolves them:
649
-
650
- - if `_layout: false`, no layout is used
651
- - if `_layout: 'convert'`, a named generated layout with id `convert` is used
652
- - otherwise Proteum picks the nearest matching `_layout` folder by file chunk identity
653
- - if no generated layout matches, the internal root layout is used
164
+ Use direct controller calls for interactions. Do not recreate fake runtime imports or client-side `@app` access.
654
165
 
655
- Observed patterns:
166
+ ## Manual Server Routes
656
167
 
657
- - CrossPath has root, `convert`, and `employer` layouts
658
- - Unique Domains mostly uses the internal/root layout and sets `_layout: false` for public landing pages
168
+ Use `server/routes/**` only for explicit HTTP behavior that should not be a generated controller action.
659
169
 
660
- Practical rule:
661
-
662
- - use `_layout: false` for standalone landing or embed-like pages
663
- - use a named layout only when a matching `_layout` folder exists
664
-
665
- # Manual Server Routes
666
-
667
- Use `server/routes/**` for routes that should stay explicit HTTP endpoints rather than generated controller actions.
668
-
669
- Typical uses from the reference apps:
170
+ Good fits:
670
171
 
671
172
  - redirects
672
- - webhook-like endpoints
673
- - sitemap and RSS
674
- - landing-page tracking
675
- - public API endpoints with custom semantics
173
+ - sitemap or RSS
676
174
  - OAuth callbacks
175
+ - webhooks
176
+ - public resources with custom semantics
677
177
 
678
- Example:
679
-
680
- ```ts
681
- import { Router, Navigation } from '@app';
682
-
683
- Router.get('/sitemap.xml', async ({ response }) => {
684
- return response.xml(await Navigation.Sitemap());
685
- });
686
- ```
687
-
688
- Manual route rules:
689
-
690
- - import server services from `@app`
691
- - use route handler context for request/response and router-plugin services
692
- - validate with `schema.validate(...)` when the schema router plugin is installed
693
- - return `response.redirect(...)`, `response.json(...)`, `response.xml(...)`, `response.html(...)`, `response.file(...)`, or raw serializable data
694
-
695
- Route handler context includes:
696
-
697
- - `request`
698
- - `response`
699
- - `Router`
700
- - app services
701
- - generated controller tree
702
- - router plugin request services such as `auth`, `schema`, `metrics`
703
- - custom router context values from `Router.context(...)`
704
-
705
- # Router Plugins
706
-
707
- Router plugins are special services attached under `Router.config.plugins`.
708
-
709
- They extend `RouterService`.
710
-
711
- Use them for:
712
-
713
- - authentication
714
- - validation helpers
715
- - metrics/tracking
716
- - other request-scoped helpers
717
-
718
- A router plugin usually has:
719
-
720
- - `server/services/<Feature>/router/index.ts`
721
- - optional `server/services/<Feature>/router/request.ts`
722
- - `service.json` with `"parent": "router"`
723
-
724
- Example `service.json`:
725
-
726
- ```json
727
- {
728
- "id": "UniqueDomains/Users/Metrics/Router",
729
- "name": "Metrics",
730
- "parent": "router",
731
- "dependences": []
732
- }
733
- ```
734
-
735
- Router plugin rules:
178
+ Rules:
736
179
 
737
- - implement `requestService(request)` to expose a request-scoped helper to route/controller context
738
- - use `this.parent.on('request' | 'resolved' | 'render', ...)` inside `ready()` when you need router lifecycle hooks
180
+ - import server-side app services from `@app`
181
+ - use route handler context for `request`, `response`, router plugins, and custom router context
182
+ - if the route is just a normal app API, prefer a controller instead
739
183
 
740
- # Models And Prisma
184
+ ## Models And Aliases
741
185
 
742
- For typings:
186
+ Use Prisma typings from:
743
187
 
744
188
  ```ts
745
189
  import type * as Models from '@models/types';
746
190
  ```
747
191
 
748
- For runtime access:
192
+ Use runtime models through:
749
193
 
750
194
  - `this.models`
751
195
  - `this.app.Models.client`
@@ -753,165 +197,88 @@ For runtime access:
753
197
  Rules:
754
198
 
755
199
  - do not import runtime values from `@models`
756
- - keep Prisma model access inside services
200
+ - keep Prisma runtime access inside services when possible
757
201
  - prefer explicit `select` or narrow `include`
758
202
  - do not edit generated Prisma client files
759
203
 
760
- Both apps instantiate `Models` explicitly in `server/index.ts` with config imported from `server/config/*.ts`.
761
-
762
- # Aliases
204
+ Relevant aliases:
763
205
 
764
- These aliases matter in real projects:
765
-
766
- - `@/client/...`: app client code
767
- - `@/server/...`: app server code
768
- - `@/common/...`: app shared code
206
+ - `@/client/...`, `@/server/...`, `@/common/...`: app code
769
207
  - `@client/...`, `@server/...`, `@common/...`: Proteum core modules
770
- - `@app`: server-side application services for manual routes
771
- - `@models/types`: Prisma typings only
772
-
773
- Import rules:
774
-
775
- - client pages: use `@/client/router`, `@/client/context`, app-local components, and generated controller tree from context
776
- - controllers/services: use `@server/app/controller`, `@server/app/service`, app-local services, and `@models/types`
777
- - manual server routes: use `@app` plus app-local utilities
208
+ - `@app`: server-side application services for manual routes only
209
+ - `@generated/*`: generated app surfaces
778
210
 
779
- # SEO And Static Output
211
+ ## Task Playbooks
780
212
 
781
- Proteum is built for SSR and crawlable HTML.
213
+ ### Add A New App API
782
214
 
783
- Observed patterns in the apps:
215
+ 1. Add or extend a root service under `server/services/<Feature>/index.ts`.
216
+ 2. Add or update `server/services/<Feature>/service.json`.
217
+ 3. Add a controller under `server/controllers/**`.
218
+ 4. Validate once with `this.input(schema)`.
219
+ 5. Resolve auth and request-derived values in the controller.
220
+ 6. Call the service from the client through the generated controller tree.
784
221
 
785
- - public landing pages use `Router.page(..., { _layout: false, ... })`
786
- - sitemap is produced explicitly through a service, then exposed with `Router.get('/sitemap.xml', ...)`
787
- - canonical behavior is available through `_canonicalParams`
788
- - static caching exists through `_static`
789
- - manual routes can opt into running even for static pages with `whenStatic: true`
222
+ ### Add A New SSR Page
790
223
 
791
- Use these rules:
792
-
793
- - prefer SSR page setup for crawlable content
794
- - keep metadata and structured output on the server-rendered path
795
- - use manual routes for sitemap, RSS, redirects, and resource endpoints
796
-
797
- # Generated Code Mental Model
798
-
799
- Proteum is not magic, but it is generation-heavy.
800
-
801
- When you change source files, Proteum regenerates:
802
-
803
- - route wrapper modules for client pages and server routes
804
- - layout registries
805
- - controller client tree
806
- - typed server app shim
807
-
808
- Source-to-generated mapping:
809
-
810
- - `client/pages/**` -> generated route modules and layout modules
811
- - `server/routes/**` -> generated server route modules
812
- - `server/controllers/**/*.ts` -> `.proteum/common/controllers.ts` and server controller registry
813
- - `server/services/**/service.json` + `server/index.ts` -> generated service typings and manifest service entries
814
-
815
- LLM rule:
816
-
817
- - edit source files only
818
- - never patch generated output directly
819
-
820
- # Maintenance Workflow For New Features
224
+ 1. Create or update `client/pages/.../index.tsx`.
225
+ 2. Register `Router.page('/real-url', setup, render)`.
226
+ 3. Return `_auth`, `_layout`, and SSR data from `setup`.
227
+ 4. Read resolved data in `render`.
228
+ 5. Use `@/client/context` or render args only for interactive follow-up actions.
821
229
 
822
- When adding a feature, follow this order:
230
+ ### Add A New Manual Route
823
231
 
824
- 1. Add or extend a root service under `server/services/<Feature>`.
825
- 2. Add or extend subservices if the feature has distinct concerns.
826
- 3. Add `server/controllers/**/*.ts` entrypoints for callable app APIs.
827
- 4. Add or extend typed config exports in `server/config/*.ts`, then instantiate the root service in `server/index.ts`.
828
- 5. Add or update `client/pages/**` routes that consume the feature.
829
- 6. Load SSR data in page `setup`.
830
- 7. Use generated controller methods from page args or `useContext()` for interactions.
831
- 8. Add manual `server/routes/**` only if you need explicit HTTP behavior that should not be a controller endpoint.
232
+ 1. Create `server/routes/...`.
233
+ 2. Import `Router` and needed app services from `@app`.
234
+ 3. Register `Router.get/post/put/patch/delete(...)`.
235
+ 4. Return response helpers or raw serializable data.
832
236
 
833
- # Maintenance Checklist For Existing Projects
237
+ ### Diagnose A Runtime Issue
834
238
 
835
- When maintaining a Proteum app:
239
+ 1. Run `npx proteum explain --json`.
240
+ 2. Run `npx proteum doctor`.
241
+ 3. If the issue is request-time behavior in dev, run:
242
+ - `npx proteum trace arm --capture deep`
243
+ - reproduce the failing request once
244
+ - `npx proteum trace latest` or `npx proteum trace show <requestId>`
245
+ 4. Inspect the touched controller, service, route, or page source.
246
+ 5. Only add temporary logging if the trace is insufficient.
836
247
 
837
- - inspect `server/index.ts` and `server/config/*.ts` first to understand which services actually exist
838
- - inspect `service.json` before moving or renaming services
839
- - inspect `server/controllers/**/*.ts` to understand the public client API
840
- - inspect `client/pages/**` for the real route table
841
- - check `_layout` folders before changing page chrome
842
- - check router plugins before assuming `auth`, `schema`, or `metrics` behavior
843
- - trace generated controller calls back to controller files, not to ad-hoc fetch URLs
248
+ For the full trace reference, see `node_modules/proteum/docs/request-tracing.md` in installed apps or `docs/request-tracing.md` in the framework repository.
844
249
 
845
- # Preferred Patterns For New Work
250
+ ## Preferred Patterns
846
251
 
252
+ - explicit `server/index.ts` bootstrap over hidden registration
847
253
  - `Router.page(path, setup, render)` over page-local fetch hacks
848
- - controller-backed APIs over ad-hoc manual `/api/...` route files
254
+ - controller-backed app APIs over ad hoc manual `/api/...` route files
849
255
  - service classes over random server helpers with hidden dependencies
850
- - `controllerPath` only when the file path would produce the wrong public API shape
851
- - `useContext()` or page render args for controller access on the client
852
- - one clear source of truth for catalogs and shared types
853
- - when a project already includes a Shadcn-based `client/components/ui/**` layer, reuse those components for standard UI primitives before creating custom ones
854
-
855
- # Legacy Or Discouraged Patterns
256
+ - one canonical source of truth for catalogs, registries, and shared types
257
+ - project-local Shadcn-based UI primitives when the app already provides them
856
258
 
857
- These exist in the codebase but should not be the default for new work:
259
+ ## Discouraged Patterns
858
260
 
859
- - older pages that overuse `api.reload(...)` and `api.set(...)`
860
- - older pages with deeply mixed UI and data responsibilities
861
- - legacy code that leans on manual `/api/...` routes for app APIs
862
- - any attempt to reintroduce `api.fetch(...)` for SSR page loading
261
+ - `api.fetch(...)` inside page files for SSR loading
863
262
  - client-side `@app` imports
864
263
  - runtime `@models` imports
264
+ - request-scoped state inside normal service methods
265
+ - hiding route registration behind abstractions that remove the top-level `Router.page(...)` call
266
+ - editing `.proteum` directly
865
267
 
866
- # Testing And Verification
268
+ ## Verification
867
269
 
868
- For app work, verify at the correct layer:
270
+ Verify at the correct layer:
869
271
 
870
272
  - route additions: boot the app and hit the real URL
871
- - controller changes: exercise the generated client call or `/api/...` endpoint
872
- - SSR changes: load the real page and inspect the rendered HTML and browser console
873
- - router/plugin changes: verify request context behavior, auth, redirects, metrics, and validation on a running app
273
+ - controller changes: exercise the generated client call or the generated `/api/...` endpoint
274
+ - SSR changes: load the real page and inspect rendered HTML plus browser console
275
+ - router/plugin changes: verify request context, auth, redirects, metrics, and validation on a running app
874
276
 
875
- Use the real app commands already present in the reference projects when possible:
277
+ Useful app commands:
876
278
 
877
279
  - `proteum dev`
878
- - `npx proteum build prod`
280
+ - `npx proteum refresh`
879
281
  - `npx proteum typecheck`
880
282
  - `npx proteum lint`
881
283
  - `npx proteum check`
882
-
883
- # Minimal Recipes
884
-
885
- ## Add a new app API
886
-
887
- 1. Create or extend `server/services/Feature/index.ts`.
888
- 2. Create `server/controllers/Feature.ts`.
889
- 3. Validate input with `this.input(schema)`.
890
- 4. Resolve auth or other request-derived values in the controller and pass them into the service method.
891
- 5. Call it from the client as `Feature.MethodName(...)`.
892
-
893
- ## Add a new SSR page
894
-
895
- 1. Create `client/pages/.../index.tsx`.
896
- 2. Register `Router.page('/real-url', setup, render)`.
897
- 3. Return `_auth`, `_layout`, and SSR fetchers from `setup`.
898
- 4. Read resolved data in `render`.
899
- 5. Use `useContext()` only for interactive follow-up actions.
900
-
901
- ## Add a new manual route
902
-
903
- 1. Create `server/routes/.../file.ts`.
904
- 2. Import `Router` and needed services from `@app`.
905
- 3. Register `Router.get/post/...`.
906
- 4. Use `schema.validate(...)` if the schema plugin is installed.
907
- 5. Return a response helper or raw JSON-safe data.
908
-
909
- # Summary Rule
910
-
911
- If you are unsure where code belongs:
912
-
913
- - page URL and SSR data: `client/pages`
914
- - reusable business logic: `server/services`
915
- - client-callable app API: `server/controllers/**/*.ts`
916
- - custom HTTP endpoint: `server/routes`
917
- - request-scoped cross-cutting concern: router plugin
284
+ - `npx proteum build prod`