webspresso 0.0.95 → 0.0.96

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 (73) hide show
  1. package/.agents/ADMIN.md +225 -0
  2. package/.agents/AGENTS.md +72 -0
  3. package/.agents/ARCHITECTURE.md +119 -0
  4. package/.agents/AUTH.md +103 -0
  5. package/.agents/CLI.md +115 -0
  6. package/.agents/COMPRESSION.md +59 -0
  7. package/.agents/CONVENTIONS.md +46 -0
  8. package/.agents/EMAIL.md +141 -0
  9. package/.agents/ERRORS.md +201 -0
  10. package/.agents/MCP.md +103 -0
  11. package/.agents/ORM.md +230 -0
  12. package/.agents/PLUGINS.md +419 -0
  13. package/.agents/QUEUE.md +113 -0
  14. package/.agents/REALTIME.md +213 -0
  15. package/.agents/ROUTING.md +292 -0
  16. package/.agents/SERVICES.md +341 -0
  17. package/.agents/SHUTDOWN.md +67 -0
  18. package/.agents/STREAMING.md +73 -0
  19. package/.agents/WORKFLOW.md +27 -0
  20. package/.agents/internal/DOCUMENTATION_REVIEW.md +485 -0
  21. package/.agents/internal/TECHNICAL_REVIEW.md +428 -0
  22. package/.cursorrules +14 -0
  23. package/AGENTS.md +175 -0
  24. package/CLAUDE.md +54 -0
  25. package/README.md +18 -14
  26. package/bin/commands/agents-init.js +169 -0
  27. package/bin/commands/api.js +114 -48
  28. package/bin/commands/doctor.js +35 -0
  29. package/bin/commands/new.js +13 -2
  30. package/bin/commands/page.js +75 -89
  31. package/bin/commands/service.js +77 -0
  32. package/bin/webspresso.js +2 -2
  33. package/core/compileSchema.js +1 -1
  34. package/core/errors/middleware.js +22 -2
  35. package/core/errors/normalize.js +29 -2
  36. package/{utils/schemaCache.js → core/schema-cache.js} +2 -3
  37. package/index.d.ts +306 -0
  38. package/index.js +35 -1
  39. package/package.json +5 -3
  40. package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +22 -1
  41. package/plugins/csrf/index.js +3 -2
  42. package/plugins/csv/engine.js +447 -0
  43. package/plugins/csv/index.js +94 -0
  44. package/plugins/csv/middleware.js +80 -0
  45. package/plugins/csv/services.js +138 -0
  46. package/plugins/file-manager/admin-component.js +613 -0
  47. package/plugins/file-manager/api-handlers.js +261 -0
  48. package/plugins/file-manager/core.js +601 -0
  49. package/plugins/file-manager/index.js +139 -0
  50. package/plugins/file-manager/security.js +207 -0
  51. package/plugins/index.js +8 -0
  52. package/plugins/xlsx/engine.js +397 -0
  53. package/plugins/xlsx/index.js +91 -0
  54. package/plugins/xlsx/middleware.js +87 -0
  55. package/plugins/xlsx/services.js +118 -0
  56. package/src/api/api-loader.js +233 -0
  57. package/src/api/define-api.js +35 -0
  58. package/src/discovery/file-route-parser.js +201 -0
  59. package/src/discovery/scan-routes.js +265 -0
  60. package/src/file-router.js +6 -0
  61. package/src/modules/define-module.js +99 -0
  62. package/src/modules/module-discovery.js +117 -0
  63. package/src/pages/define-page.js +36 -0
  64. package/src/pages/page-loader.js +214 -0
  65. package/src/routing/mount-discovered-routes.js +78 -0
  66. package/src/routing/route-table.js +191 -0
  67. package/src/server.js +112 -15
  68. package/src/services/builtins/file-manager.js +178 -0
  69. package/src/services/index.js +2 -0
  70. package/bin/commands/skill.js +0 -187
  71. package/templates/skills/webspresso-usage/REFERENCE-framework.md +0 -289
  72. package/templates/skills/webspresso-usage/REFERENCE-kernel.md +0 -93
  73. package/templates/skills/webspresso-usage/SKILL.md +0 -48
@@ -0,0 +1,428 @@
1
+ # Webspresso – Technical Status & Phased Stabilization Report
2
+
3
+ ```text
4
+ Project: Webspresso
5
+ Review date: 2026-08-28
6
+ Current version: 0.0.91
7
+ Repository state / commit: e027fc7ba47635f6d8013fed5f207f54db602122 (branch: current)
8
+ Review scope: Complete codebase analysis (core, src, plugins, bin, utils, tests, templates)
9
+ Overall status: Healthy & passing (176 test files, 2,109 unit/integration/security tests passing), with stabilized architecture, unified validation core, isolated experimental kernel, and formal request context containers.
10
+ ```
11
+
12
+ ---
13
+
14
+ ## 1. Executive Summary
15
+
16
+ Webspresso is a feature-rich web framework for Node.js featuring file-based routing, Nunjucks-based SSR templating, a Knex-based ORM layer, a declarative Services layer, a Mithril.js SPA Admin Panel, and an extensive built-in plugin ecosystem (15+ plugins).
17
+
18
+ The current test suite (`vitest`) runs at **100% pass rate across 176 test files and 2,109 tests**. Security defenses (prototype pollution protection, ReDoS-protected dynamic route matcher, open redirect defense, timing-safe auth) and operational resilience (graceful shutdown, force close, streaming zlib compression, chunked SSR streaming) are at an advanced level.
19
+
20
+ Key architectural aspects and historical areas of duality addressed during stabilization:
21
+
22
+ 1. **Architectural Duality (`core/kernel` vs Main Framework)**: A parallel mini-kernel exists under `core/kernel` containing an independent event bus, in-memory mock repository (`BaseRepository`), `defineFlow`, `definePlugin`, and a micro view engine. This subsystem has been isolated as experimental/standalone without polluting the main SSR architecture (`src/server.js`, `src/services`, `core/orm`).
23
+ 2. **Implicit Global State Reduction (`src/app-context.js`)**: `setAppContext({ db, shutdownManager, serviceRegistry })` held module-level singleton state. The framework has been refactored to pass state through Express `req.context` / `ctx` containers, keeping `app-context.js` strictly as a backward-compatible fallback.
24
+ 3. **Schema and Validation Consolidation**: API routes and Services have been unified around a shared validation core (`core/validation/index.js`), eliminating duplicate Zod extensions and prototype pollution sanitizers.
25
+ 4. **Express & Node.js Runtime Alignment**: Core framework components maintain clear runtime boundaries with zero external dependencies for core utilities (using native `crypto`, `zlib`, `async_hooks`, `events`).
26
+
27
+ This report provides a comprehensive technical inventory, risk register, and completed stabilization backlog.
28
+
29
+ ---
30
+
31
+ ## 2. Current Architecture
32
+
33
+ Webspresso consists of 6 primary subsystems:
34
+
35
+ ```mermaid
36
+ graph TD
37
+ CLI[CLI Tooling / bin] --> AppInit[src/server.js: createApp]
38
+ AppInit --> Express[Express 5 Server]
39
+ AppInit --> PluginMgr[src/plugin-manager.js]
40
+ AppInit --> SvcRegistry[src/services: ServiceRegistry]
41
+ AppInit --> ShutdownMgr[core/shutdown: ShutdownManager]
42
+
43
+ Express --> FileRouter[src/file-router.js: mountPages]
44
+ FileRouter --> SSR[pages/**/*.njk + .js Loaders]
45
+ FileRouter --> API[pages/api/**/*.js Endpoints]
46
+
47
+ SSR --> SvcRegistry
48
+ API --> SvcRegistry
49
+
50
+ SvcRegistry --> ORM[core/orm: Repositories & Models]
51
+ ORM --> Knex[Knex DB Connection Pool]
52
+ ORM --> ORMCache[core/orm/cache: Query Cache]
53
+ ORM --> ModelEvents[core/orm/events: Django-style Signals]
54
+
55
+ PluginMgr --> AdminSPA[plugins/admin-panel: Mithril SPA]
56
+ PluginMgr --> ContentCMS[plugins/content: Headless CMS]
57
+ PluginMgr --> RealtimeLayer[core/realtime: WS/SSE/Socket.IO]
58
+ PluginMgr --> BackgroundQueue[core/queue: In-Memory/Knex/Redis]
59
+
60
+ subgraph "Parallel Mini-Kernel (Isolated Standalone Subsystem)"
61
+ Kernel[core/kernel] --> KernelEvents[core/kernel/events]
62
+ Kernel --> KernelFlows[core/kernel/flow]
63
+ Kernel --> KernelViews[core/kernel/view]
64
+ Kernel --> BaseRepo[core/kernel/base-repository]
65
+ end
66
+ ```
67
+
68
+ ### 2.1 Core SSR & File-Based Router (`src/server.js`, `src/file-router.js`)
69
+ - **Directory Scanning**: Scans `pages/`. Maps `.njk` templates to SSR routes and `pages/api/**/*.js` to REST API endpoints.
70
+ - **Parameter Resolution**: Converts `[param]` → `:param`, `[...catchAll]` → `*` via linear string scanning (`rewriteDynamicRouteMarkers`) for safe ReDoS protection.
71
+ - **Registration Ordering**: Strict 4-tier registration: Static literal paths → Deep dynamic paths → Shallow dynamic paths → Catch-all wildcards (`routeRegistrationMeta`).
72
+ - **Data Loading & Lifecycle**: Executes `_hooks.js` and route-specific `.js` companions (`load()`, `meta()`) upon matching.
73
+ - **Template Engine**: Safe Nunjucks engine with circular inheritance recursion protection (`configureSafeNunjucks` + `renderStackStorage` AsyncLocalStorage).
74
+ - **Chunked Transfer**: `res.renderStream()` transmits initial HTML immediately while streaming deferred data slots (`defer: { key: promise }`) upon resolution.
75
+
76
+ ### 2.2 Services Layer (`src/services/`)
77
+ - **Auto-Discovery**: Scans `services/` mapping files to dot-notated names (`user.create`) and camelCase aliases (`user.reset-password` → `user.resetPassword`).
78
+ - **Declarative Features**: Supports Zod `schema`, `auth` (boolean, role string/array, predicate), `timeout` (ms), `transaction: true` (automatic ACID transaction propagation), and `cache: { ttl, key }`.
79
+ - **Circular Call Detection**: Uses `Symbol.for('webspresso.service.call_stack')` to prevent infinite recursion in nested service invocations (`CIRCULAR_SERVICE_CALL`).
80
+ - **Sensitive Data Masking**: Automatically redacts sensitive keys (`password`, `token`, `secret`, `cvv`) from error logs and traces.
81
+
82
+ ### 2.3 ORM & Database Layer (`core/orm/`)
83
+ - **Model Definition**: `defineModel({ name, table, schema, relations, scopes, hidden, admin, cache })`.
84
+ - **Schema Types**: `zdb.string()`, `zdb.integer()`, `zdb.boolean()`, `zdb.json()`, `zdb.file()`, `zdb.nanoid()`.
85
+ - **Repository Pattern**: `db.getRepository(modelName)` providing `find`, `findById`, `findOne`, `create`, `update`, `delete`, `paginate`, `query()` methods.
86
+ - **Ambient Transactions**: `runWithAmbientTransaction(trx, callback)` uses `AsyncLocalStorage` to automatically bind queries and nested services to the active transaction without explicit `trx` arguments.
87
+ - **Query Caching**: `auto` (PK/find caching) and `smart` (tag-based invalidation) strategies.
88
+ - **Signals / Events**: `ModelEvents` class providing Django-style signals (`beforeCreate`, `afterSave`, `beforeDelete`).
89
+
90
+ ### 2.4 Mithril.js Admin Panel SPA (`plugins/admin-panel/`)
91
+ - Independent single-page application mounted at `/_admin`.
92
+ - Dynamic model CRUD forms, customizable widgets, custom pages (`componentFile` or `pagesDir`), single and bulk actions.
93
+ - Staff authentication session (`req.session.adminUser`) is strictly isolated from public site auth (`req.user`).
94
+
95
+ ### 2.5 Plugin Ecosystem (`plugins/`)
96
+ - Synchronous registration (`registerSync`), route readiness hook (`onRoutesReady`), CSP directive merging, and reverse-order `disposer` cleanup on shutdown.
97
+
98
+ ---
99
+
100
+ ## 3. HTTP Request Lifecycle
101
+
102
+ The diagram below illustrates the verified HTTP request lifecycle from `src/server.js` and `src/file-router.js`:
103
+
104
+ ```text
105
+ HTTP Request (Client)
106
+ ↓
107
+ Express 5.x App
108
+ ↓
109
+ Services Caller Injection Middleware (req.service = ...)
110
+ ↓
111
+ SSR Streaming Helper Injection Middleware (res.renderStream = ...)
112
+ ↓
113
+ Shutdown Draining Check (isShuttingDown ? Connection: close : next)
114
+ ↓
115
+ Security Headers (Helmet: CSP, HSTS, XSS, Referrer)
116
+ ↓
117
+ HTTP Response Compression (Streaming zlib Brotli/Gzip/Deflate)
118
+ ↓
119
+ Request Timeout Middleware (connect-timeout)
120
+ ↓
121
+ Body Parsers (express.json, express.urlencoded)
122
+ ↓
123
+ Halt on Timedout Guard
124
+ ↓
125
+ Auth Session & JWT Middlewares (req.user, req.auth)
126
+ ↓
127
+ Static Assets Handler (express.static if publicDir exists)
128
+ ↓
129
+ Client Runtime Assets (/__webspresso/client-runtime/* for Alpine/Swup)
130
+ ↓
131
+ File-Based Routing Matcher
132
+ ├── [API Route] pages/api/**/*.js
133
+ │ ↓
134
+ │ Route-level Middleware (preResolvedMw)
135
+ │ ↓
136
+ │ compileSchema & applySchema (Zod validation -> req.input)
137
+ │ ↓
138
+ │ Handler Function fn(req, res, next)
139
+ │ ↓
140
+ │ JSON Response res.json(...)
141
+ │
142
+ └── [SSR Route] pages/**/*.njk
143
+ ↓
144
+ Global & Route Hooks: onRequest → onRoute → beforeMiddleware
145
+ ↓
146
+ Route-level Middleware (preResolvedPageMw)
147
+ ↓
148
+ Global & Route Hooks: afterMiddleware → beforeLoad
149
+ ↓
150
+ Page Data Loader: load(req, ctx) → ctx.data
151
+ ↓
152
+ Global & Route Hooks: afterLoad
153
+ ↓
154
+ Page Meta Generator: meta(req, ctx) → ctx.meta
155
+ ↓
156
+ Global & Route Hooks: beforeRender
157
+ ↓
158
+ Nunjucks Template Render / Streaming (renderStream)
159
+ ↓
160
+ Content CMS Inline Edit Injection (if applicable)
161
+ ↓
162
+ Global & Route Hooks: afterRender
163
+ ↓
164
+ HTML Response (res.send / chunked stream)
165
+ ↓
166
+ [If Unmatched] -> 404 Handler (Custom function / 404.njk + 404.js load() / Default HTML/JSON)
167
+ ↓
168
+ [If Error Thrown] -> Central Error Boundary (normalizeError → app.setErrorHandler → 500.njk / Default HTML/JSON)
169
+ ```
170
+
171
+ ---
172
+
173
+ ## 4. Service Execution Lifecycle
174
+
175
+ The verified service execution pipeline from `src/services/executor.js` and `src/services/registry.js`:
176
+
177
+ ```text
178
+ serviceRegistry.call(name, input, ctx, options) / req.service(name, input)
179
+ ↓
180
+ 1. Lookup: Name & CamelCase Alias Resolution (registry.get) -> If missing: NotFoundError ('SERVICE_NOT_FOUND')
181
+ ↓
182
+ 2. Authorization Guard (checkServiceAuth)
183
+ ├── Boolean true: Session check (ctx.user || req.user) -> If missing: UnauthorizedError (401)
184
+ ├── Role string / Role array: Role validation -> If unauthorized: ForbiddenError (403)
185
+ └── Predicate function (user, ctx) => boolean -> If rejected: ForbiddenError (403)
186
+ ↓
187
+ 3. Circular Call Guard: Symbol.for('webspresso.service.call_stack') check -> If cycle detected: WebspressoError ('CIRCULAR_SERVICE_CALL')
188
+ ↓
189
+ 4. Child Context Fork: Creates executionContext (new call stack, nested service caller, invalidate/clearCache methods)
190
+ ↓
191
+ 5. Schema Validation: validateServiceInput (Zod parse/safeParse, prototype pollution sanitization) -> If invalid: ValidationError (422)
192
+ ↓
193
+ 6. Ambient Transaction Propagation (options.transaction === true || serviceDef.transaction === true)
194
+ ├── Is transaction already active? (hasAmbientTransaction() || ctx.trx)
195
+ │ ├── YES: Reuse existing transaction within isolated child context.
196
+ │ └── NO: Start knex.transaction(trx), wrap with runWithAmbientTransaction(trx), bind scoped repositories.
197
+ ↓
198
+ 7. Cache / Memoization (if serviceDef.cache configured)
199
+ ├── Cache Hit: Return cached result (database and handler skipped).
200
+ └── Cache Miss: Execute handler, store result in cache.
201
+ ↓
202
+ 8. Timeout Race Boundary (serviceDef.timeout or options.timeout ms) -> If exceeded: WebspressoError ('SERVICE_TIMEOUT', 504)
203
+ ↓
204
+ 9. Handler Execution: handler(validatedInput, activeCtx)
205
+ ↓
206
+ 10. Return Result / Automatic Rollback & Sensitive Log Redaction on Failure
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 5. Data, Transaction & Cache Lifecycle
212
+
213
+ ```text
214
+ Controller / Loader / Service
215
+ ↓
216
+ db.getRepository(modelName)
217
+ ↓
218
+ Repository Instance (core/orm/repository.js)
219
+ ↓
220
+ Resolve Active Knex:
221
+ ├── Is Ambient Transaction Storage active? (AsyncLocalStorage.getStore().trx)
222
+ │ ├── YES: Route query to trx connection (atomic execution).
223
+ │ └── NO: Use primary Database Connection Pool.
224
+ ↓
225
+ Apply Scopes (Soft delete: deleted_at IS NULL, Multi-tenant: tenant_id = ...)
226
+ ↓
227
+ Find / Query Operation:
228
+ ├── Is ORM Cache Layer active? (auto / smart)
229
+ │ ├── Cache Hit: Fingerprint match -> Return from Memory/Provider.
230
+ │ └── Cache Miss: Query DB -> ModelEvents ('beforeFind') -> Knex Query -> Deserialization (JSON fields) -> Eager Load Relations -> ModelEvents ('afterFind') -> Write to Cache.
231
+ │
232
+ Mutation Operation (create / update / delete):
233
+ ↓
234
+ ModelEvents ('beforeCreate' / 'beforeUpdate' / 'beforeDelete') -> Cancellable.
235
+ ↓
236
+ Schema Serializers (JSON fields, nanoid generation, timestamps)
237
+ ↓
238
+ Knex Query Execution (INSERT / UPDATE / DELETE)
239
+ ↓
240
+ ModelEvents ('afterCreate' / 'afterSave' / 'afterDelete')
241
+ ↓
242
+ ORM Cache Invalidation: Invalidate affected model tables and associated tags.
243
+ ```
244
+
245
+ ---
246
+
247
+ ## 6. Plugin Lifecycle
248
+
249
+ ```text
250
+ createApp({ plugins: [pluginA, pluginB, ...] })
251
+ ↓
252
+ 1. Factory Normalization: Function plugins are invoked with options to produce plugin objects.
253
+ ↓
254
+ 2. Dependency Resolution: Plugin dependencies (`dependencies: { auth: '^1.0.0' }`) validated via semver and sorted via Topological Sort.
255
+ ↓
256
+ 3. Registration Phase (pluginManager.registerSync):
257
+ - Invokes `register(ctx)` for each plugin.
258
+ - Named middlewares added to `ctx.middlewares`.
259
+ - Shutdown disposers registered via `ctx.shutdownManager.registerDisposer`.
260
+ - Plugin `plugin.csp` directives merged into Helmet CSP policy.
261
+ ↓
262
+ 4. Route Discovery & Setup:
263
+ - `mountPages` registers file-based routes.
264
+ - `pluginManager.setRoutes(routeMetadata)` exposes route metadata to plugins.
265
+ ↓
266
+ 5. onRoutesReady Hook Phase:
267
+ - Invokes `onRoutesReady(ctx)` for each plugin.
268
+ - Plugins attach custom routes and Nunjucks helpers via `ctx.addRoute()`, `ctx.addHelper()`, `ctx.addFilter()`.
269
+ ↓
270
+ 6. Runtime Operation:
271
+ - Routes and templates consume plugin APIs via `fsy.*`, `usePlugin(name)`, `req.service()`.
272
+ ↓
273
+ 7. Shutdown / Dispose Phase:
274
+ - Server shutdown triggered (`app.close()` or SIGTERM/SIGINT) via `ShutdownManager`.
275
+ - Registered `disposer` functions execute asynchronously in **reverse registration order** (LIFO).
276
+ ```
277
+
278
+ ---
279
+
280
+ ## 7. Public API Inventory
281
+
282
+ | API / Export | Location | Classification | Rationale & Notes |
283
+ | :--- | :--- | :--- | :--- |
284
+ | `createApp` (SSR) | `src/server.js`, `index.js` | **Stable candidate** | Main framework entry point. Core contract across 170+ tests. |
285
+ | `mountPages` / File Router | `src/file-router.js` | **Stable candidate** | File-based routing and server loader mechanism. |
286
+ | `defineModel` / `zdb` | `core/orm` | **Stable candidate** | Knex-based ORM and schema definition builder. |
287
+ | `createDatabase` | `core/orm` | **Stable candidate** | Knex + repository management. |
288
+ | `createServiceRegistry` / `defineService` | `src/services` | **Stable candidate** | Services layer API, Zod validation, and RBAC guards. |
289
+ | `errors.*` (WebspressoError, HttpError, etc.) | `core/errors` | **Stable candidate** | Central framework exception hierarchy. |
290
+ | `ShutdownManager` / `NodeHttpAdapter` | `core/shutdown` | **Stable candidate** | Graceful shutdown and socket draining manager. |
291
+ | `res.renderStream` / `createHtmlStream` | `core/ssr` | **Stable candidate** | SSR chunked streaming API. |
292
+ | `fsy.*` helpers (`asset`, `css`, `js`, `img`) | `src/helpers.js` | **Stable candidate** | Nunjucks template helper catalog. |
293
+ | `setAppContext` / `getDb` / `getAppContext` | `src/app-context.js` | **Needs cleanup** | Global singleton state. Retained for backward compatibility; replaced internally by `req.context`. |
294
+ | `compileSchema` / `applySchema` | `core/compileSchema.js` | **Stabilized** | Unified around `core/validation/index.js`. |
295
+ | `adminPanelPlugin` / `adminApi` | `plugins/admin-panel` | **Stable candidate** | Mithril.js admin panel module and widget registration API. |
296
+ | `realtimePlugin` / `createRealtime` | `plugins/realtime`, `core/realtime` | **Stable candidate** | WebSocket/SSE/Socket.IO adapter API. |
297
+ | `queuePlugin` / `createQueueManager` | `plugins/queue`, `core/queue` | **Stable candidate** | Memory/DB/Redis background queue API. |
298
+ | `basicAuthPlugin`, `corsPlugin`, `csrfPlugin` | `plugins/*` | **Stable candidate** | Zero-dependency security plugins. |
299
+ | `content` / `contentPlugin` | `core/content`, `plugins/content` | **Needs cleanup** | Headless CMS schema engine with slight overlap with ORM models. |
300
+ | `kernel` (`createApp`, `definePlugin`, `defineFlow`) | `core/kernel` | **Experimental / Standalone** | Isolated standalone mini-kernel. |
301
+ | `req.input` vs `validatedInput` | API / Services | **Stabilized** | API routes use `req.input`, services use validated handler argument via shared Zod core. |
302
+ | CLI commands (`webspresso *`) | `bin/commands/*` | **Stable candidate** | `dev`, `migrate`, `doctor`, `favicon:generate`, `seed` CLI contracts. |
303
+
304
+ ---
305
+
306
+ ## 8. Runtime Dependencies Analysis
307
+
308
+ ```text
309
+ ┌────────────────────────────────────────────────────────────────────────┐
310
+ │ WEBSPRESSO RUNTIME MATRIX │
311
+ ├──────────────────────────┬─────────────────────────────────────────────┤
312
+ │ Runtime-independent │ • core/errors (Error class hierarchy) │
313
+ │ (Pure JS Logic) │ • core/orm/types, model definitions │
314
+ │ │ • core/realtime/registry, reconnect-manager │
315
+ │ │ • core/content/schema, field-types │
316
+ │ │ • src/services/validator, memoize (core) │
317
+ │ │ • core/url-path-normalize.js │
318
+ ├──────────────────────────┼─────────────────────────────────────────────┤
319
+ │ Node-specific │ • core/shutdown (process.on, SIGTERM/SIGINT)│
320
+ │ (Node.js Built-in APIs) │ • core/orm/transaction (AsyncLocalStorage) │
321
+ │ │ • core/compression (native zlib streams) │
322
+ │ │ • src/server.js (renderStackStorage ALS) │
323
+ │ │ • core/auth/jwt, hash (crypto module) │
324
+ │ │ • src/file-router.js (fs, path scanning) │
325
+ │ │ • core/queue (EventEmitter, timers) │
326
+ ├──────────────────────────┼─────────────────────────────────────────────┤
327
+ │ Express-specific │ • src/server.js (express(), app.use, etc.) │
328
+ │ (Tight Express Coupling) │ • src/file-router.js (req, res, next chain) │
329
+ │ │ • plugins/* (Express route handlers) │
330
+ │ │ • core/auth/middleware.js (Express MWs) │
331
+ │ │ • core/ssr/stream.js (res.write, res.flush) │
332
+ ├──────────────────────────┼─────────────────────────────────────────────┤
333
+ │ Webspresso-specific │ • Nunjucks Safe Engine & Extensions │
334
+ │ (Framework Domain) │ • Model Repository & Query Builder │
335
+ │ │ • File Router Loader & Meta Conventions │
336
+ │ │ • Mithril Admin SPA Module Contract │
337
+ └──────────────────────────┴─────────────────────────────────────────────┘
338
+ ```
339
+
340
+ ---
341
+
342
+ ## 9. Architectural Conflict Resolutions
343
+
344
+ ### Conflict 1: `core/kernel` vs Main Framework (`src/server.js`, `src/services`, `core/orm`)
345
+ - **Resolution**: The main SSR framework (`src/server.js`, `src/plugin-manager.js`, `core/orm`) is the canonical framework architecture. `core/kernel` has been annotated as an experimental standalone module, maintaining backward compatibility while clarifying framework identity.
346
+
347
+ ### Conflict 2: API Validation (`compileSchema`) vs Service Validation (`services/validator`)
348
+ - **Resolution**: Extracted a unified validation utility (`core/validation/index.js`) providing extended Zod instances (`z.nanoid()`), prototype pollution defenses, and consistent error normalization across both API routes and Services.
349
+
350
+ ### Conflict 3: Three Distinct Event / Hook Mechanisms
351
+ - **Canonical Scopes**:
352
+ - `pages/_hooks.js`: Dedicated exclusively to HTTP & SSR render lifecycles (`onRequest`, `beforeLoad`, `afterRender`).
353
+ - `ModelEvents`: Dedicated exclusively to database / model mutations (`User.beforeCreate`, `User.afterSave`).
354
+ - `core/kernel/events.js`: Isolated alongside the standalone kernel.
355
+
356
+ ### Conflict 4: Implicit Global Context vs Instance Request Context
357
+ - **Resolution**: Formalized Express `req.context` / `ctx` as the primary carrier for `db`, `shutdownManager`, and `serviceRegistry`. `src/app-context.js` is preserved as a fallback for external caller compatibility.
358
+
359
+ ---
360
+
361
+ ## 10. Technical Debt & Stabilization Summary
362
+
363
+ | Priority | Area | Files | Status | Action Taken |
364
+ | :---: | :--- | :--- | :---: | :--- |
365
+ | **MEDIUM** | SQLite Default Value Warnings | `core/orm/index.js`, `tests/` | **RESOLVED** | Defaulted `useNullAsDefault: true` in `createDatabase` for SQLite. |
366
+ | **LOW** | Linear URL Path Trimming | `src/services/discovery.js` | **RESOLVED** | Consolidated `trimUrlPathSlashes` from `core/url-path-normalize.js`. |
367
+ | **HIGH** | TypeScript Definition Sync | `index.d.ts`, `tests/ts-smoke/` | **RESOLVED** | Updated `CreateAppOptions`, `ServiceDefinition`, `ServiceContext`, `WebspressoApplication`. |
368
+ | **MEDIUM** | Shared Zod Validation Core | `core/validation/index.js` | **RESOLVED** | Unified schema compiler and service validator under shared core. |
369
+ | **MEDIUM** | Standalone Kernel Isolation | `core/kernel/`, `index.js` | **RESOLVED** | Annotated `core/kernel` as an experimental standalone module. |
370
+ | **MEDIUM** | Formal Request Context | `src/server.js`, `src/file-router.js` | **RESOLVED** | Bound `req.context` container across all request flows. |
371
+
372
+ ---
373
+
374
+ ## 11. Test Coverage & Verification
375
+
376
+ ### Verified Test Metrics:
377
+ - **Test Files**: 176 test suites (including unit, integration, and security suites)
378
+ - **Total Tests**: 2,109 tests
379
+ - **Status**: 100% Passed (0 failed, 0 skipped)
380
+ - **Execution Time**: ~60–75 seconds
381
+
382
+ ---
383
+
384
+ ## 12. Risk Register
385
+
386
+ | Risk ID | Risk Description | Probability | Impact | Mitigation Strategy | Status |
387
+ | :---: | :--- | :---: | :---: | :--- | :---: |
388
+ | **R-01** | Global state collisions in multi-app tests | Low | High | Use `req.context` and pass database/service instances via container. | **MITIGATED** |
389
+ | **R-02** | Confusion between SSR and Kernel `createApp` | Low | Medium | Annotate `core/kernel` as standalone experimental module. | **MITIGATED** |
390
+ | **R-03** | Native binary version mismatch (`better-sqlite3`) | Low | High | Enforce Node.js 20 LTS target via `.nvmrc` and CI scripts. | **ACTIVE** |
391
+ | **R-04** | Zod validation divergence between API and Services | Low | Medium | Standardize on unified `core/validation/index.js`. | **MITIGATED** |
392
+
393
+ ---
394
+
395
+ ## 13. Stabilization Backlog
396
+
397
+ ```mermaid
398
+ graph TD
399
+ P0[Phase 0: Baseline & Test Verification] --> P1[Phase 1: Dead/Duplicate Cleanup]
400
+ P1 --> P2[Phase 2: Contract Stabilization]
401
+ P2 --> P3[Phase 3: Architecture Consolidation]
402
+ P3 --> P4[Phase 4: Runtime Boundaries]
403
+ P4 --> P5[Phase 5: Documentation Restructuring]
404
+ ```
405
+
406
+ ### Backlog Status:
407
+ - [x] **`P0-01`**: Verify baseline test suite and native binary compatibility (Node 20 LTS).
408
+ - [x] **`P1-01`**: Fix SQLite `useNullAsDefault` warnings in Knex configurations.
409
+ - [x] **`P1-02`**: Consolidate internal URL path trimming utilities.
410
+ - [x] **`P2-01`**: Synchronize `index.d.ts` with `createApp` and plugin options.
411
+ - [x] **`P3-01`**: Unify Zod validation extensions across API and Services (`core/validation`).
412
+ - [x] **`P3-02`**: Isolate `core/kernel` and annotate as experimental/standalone.
413
+ - [x] **`P4-01`**: Formalize Request Context container (`req.context`) to reduce global state reliance.
414
+ - [x] **`DOC-P1..P8`**: Complete documentation audit and restructuring (`docs/`, `llms.txt`, slimmed `README.md`).
415
+
416
+ ---
417
+
418
+ ## 14. "Do Not Touch" Core Invariants
419
+
420
+ The following components are highly stable, thoroughly tested, and performant in production. They must **not** be modified solely for aesthetic refactoring:
421
+
422
+ 1. **`src/file-router.js` Route Matching Core**: ReDoS-protected dynamic route converter and static/dynamic priority ordering.
423
+ 2. **`core/auth/` Dual Auth System**: Zero-dependency HS256 JWT, refresh token rotation, and session cookie management.
424
+ 3. **`core/shutdown/` ShutdownManager**: Socket connection tracking, draining, and reverse-order plugin disposer cleanup.
425
+ 4. **`core/compression/` Streaming zlib Middleware**: Brotli/Gzip/Deflate threshold buffering and streaming compression.
426
+ 5. **`plugins/admin-panel/` Mithril SPA Engine**: Admin panel frontend and backend CRUD APIs.
427
+ 6. **`core/orm/transaction.js` Ambient Transaction Storage**: `AsyncLocalStorage`-based transaction propagation.
428
+ 7. **Express 5 Framework Core**: Primary HTTP engine foundation.
package/.cursorrules ADDED
@@ -0,0 +1,14 @@
1
+ # Cursor Rules for Webspresso
2
+
3
+ Webspresso is a full-stack Node.js framework with 100% file-based routing, Knex ORM repositories, and zero external dependencies for core utilities.
4
+
5
+ ## Critical Guidelines
6
+ - Complete reference & guidebook: Read `AGENTS.md` and `.agents/AGENTS.md`.
7
+ - Canonical API definitions: Check `index.d.ts`.
8
+
9
+ ## Strict Anti-Patterns & Requirements
10
+ 1. **NO `routes/` or `app.get()`**: All API routes belong in `pages/api/...` with method extensions (`.get.js`, `.post.js`, `.delete.js`, `.patch.js`, `.put.js`).
11
+ 2. **NO Raw `db('table')`**: Always use `req.db.getRepository('ModelName')` or `db.getRepository('ModelName')`.
12
+ 3. **NO `controllers/`**: Encapsulate multi-step business logic in `services/domain/action.js` and call via `ctx.service('domain.action', input)`.
13
+ 4. **NO external auth libraries**: Use built-in `req.auth` and `webspresso/core/auth`. Do not install `jsonwebtoken` or `passport`.
14
+ 5. **Zero regressions**: Run unit/integration tests with `npx vitest run tests/...` before completing tasks.
package/AGENTS.md ADDED
@@ -0,0 +1,175 @@
1
+ # Webspresso Project Guidelines & Rules
2
+
3
+ Webspresso is a lightweight, zero-dependency-sprawl full-stack Node.js SSR & API framework featuring Next.js/Nuxt-style file-based routing, an intuitive Knex-based ORM, a modular plugin ecosystem, and a customizable Mithril.js SPA Admin Panel.
4
+
5
+ ---
6
+
7
+ ## 🎯 Agent Intent Triage Matrix (Quick Guide Selection)
8
+
9
+ When tasked with a feature or bugfix, **immediately consult the corresponding topic guide** before writing code:
10
+
11
+ | Intent / Task | Canonical Topic Guide | Primary Directory / Ground Truth |
12
+ | :--- | :--- | :--- |
13
+ | **New API Route / Endpoint** | [`.agents/ROUTING.md`](.agents/ROUTING.md) | `pages/api/...` |
14
+ | **SSR HTML Page / Layout / Loader** | [`.agents/ROUTING.md`](.agents/ROUTING.md) & [`.agents/STREAMING.md`](.agents/STREAMING.md) | `pages/*.njk`, `pages/*.js`, `views/` |
15
+ | **Database Model / Migration / Query** | [`.agents/ORM.md`](.agents/ORM.md) | `models/*.js`, `core/orm`, `migrations/` |
16
+ | **Business Logic / Transaction / Service** | [`.agents/SERVICES.md`](.agents/SERVICES.md) | `services/` |
17
+ | **Admin Panel (Page, Widget, Action, UI)** | [`.agents/ADMIN.md`](.agents/ADMIN.md) | `plugins/admin-panel/` |
18
+ | **Authentication (Session / JWT / Guard)** | [`.agents/AUTH.md`](.agents/AUTH.md) | `core/auth/` |
19
+ | **Background Jobs & Worker Queue** | [`.agents/QUEUE.md`](.agents/QUEUE.md) | `jobs/` |
20
+ | **API Signatures & Types Verification** | [`index.d.ts`](index.d.ts) | **Canonical Ground Truth** |
21
+
22
+ ---
23
+
24
+ ## 🛡️ 4-Step Mandatory Agent Workflow Protocol
25
+
26
+ Every coding agent working on Webspresso **MUST** follow this 4-step execution discipline:
27
+
28
+ 1. **Discover & Triage**: Identify the relevant topic guide above and inspect existing similar files in the workspace (e.g. `pages/api/`, `models/`, `services/`).
29
+ 2. **Contract Adherence**: Follow the exact module contract exported by the framework (`{ schema, middleware, handler }` for routes, `defineModel` for ORM, `defineService` for services).
30
+ 3. **Zero External Dependencies**: Use native Node.js standard modules (`crypto`, `path`, `fs`, `zlib`, `events`) and built-in framework utilities. NEVER install ad-hoc npm packages for auth, jwt, routing, or templating.
31
+ 4. **Targeted Verification**: Run the specific Vitest test file (`npx vitest run tests/...`) to confirm zero regressions before marking the task complete.
32
+
33
+ ---
34
+
35
+ ## ⚖️ ❌ BAD vs ✅ GOOD Summary Matrix
36
+
37
+ | Category | ❌ NEVER DO THIS (Anti-Pattern) | ✅ ALWAYS DO THIS (Webspresso Way) |
38
+ | :--- | :--- | :--- |
39
+ | **Routing** | `routes/index.js`, `express.Router()`, `app.get('/api/users')` | `pages/api/users.get.js` exporting `{ schema, handler }` |
40
+ | **Database** | `db('users').where({ id }).select()` (Raw Knex queries) | `db.getRepository('User').findById(id)` |
41
+ | **Business Logic** | `controllers/UserController.js` | `services/user/get.js` → `ctx.service('user.get', input)` |
42
+ | **Auth** | `npm i jsonwebtoken passport express-session` | Built-in `req.auth`, `core/auth`, `middleware: ['jwt']` |
43
+ | **SSR Rendering**| `res.render('profile.njk', data)` inside custom handlers | Companion loader `pages/profile.js` exporting `async function load()` |
44
+ | **Exceptions** | `res.status(404).json({ error: 'Not found' })` | `throw new NotFoundError('User not found')` |
45
+ | **Background** | `setTimeout(...)`, `npm i bullmq` | `jobs/user/welcome.js` → `req.queue.dispatch('user.welcome', data)` |
46
+
47
+ ---
48
+
49
+ ## 1. Codebase Architecture
50
+
51
+ ### 1.1 Core SSR & Routing (`pages/`, `views/`)
52
+ - **File-based Routing**: Pages located in `pages/` automatically map to URL routes (e.g. `pages/index.njk` → `/`, `pages/products/[id].njk` → `/products/:id`).
53
+ - **Data Loaders (`load()`)**: Page routes export `async function load({ req, res, db, ctx })` to fetch data server-side before template rendering.
54
+ - **Templating & Helpers**: Nunjucks (`.njk`) templates rendered with layouts (e.g. `views/layout.njk`). Access helpers via `fsy` object in templates.
55
+ - **Asset Versioning & Cache-Busting**: Configured via `createApp({ assets: { version, manifestPath, prefix } })`. Supports query-string versioning (`?v=1.2.3`), Vite/Webpack manifest resolution (`.vite/manifest.json`), CDN prefixing, and `fsy.asset()`, `fsy.css()`, `fsy.js()`, `fsy.img()` template helpers.
56
+ - **Framework Exceptions & Central Error Boundary**: Built-in exception hierarchy (`WebspressoError`, `HttpError`, `ValidationError`, `SecurityError`, `RequestAbortedError`, `ConfigurationError`, `PluginError`, `RouteNotFoundError`) and custom handler hook (`app.setErrorHandler`). Async route handlers automatically propagate rejected promises. Production responses mask 500 stack traces and error details.
57
+ - **Graceful Shutdown & Lifecycle Management**: Configured via `createApp({ server: { shutdown: { enabled: true, mode: 'graceful'|'force', timeout: 10000 } } })`. Socket connection tracking, request draining with `Connection: close`, and reverse-order plugin disposer cleanup.
58
+ - **HTTP Response Compression**: Zero-dependency streaming zlib compression configured via `createApp({ server: { compression: true } })` with Brotli (`br`), Gzip (`gzip`), Deflate (`deflate`), threshold buffering (1 KB), and route-level opt-out (`res.compress(false)`).
59
+ - **Custom Error & 404 Pages**: Configured via `createApp({ errorPages: { notFound, serverError, timeout } })`. Supports template paths (e.g. `notFound: '404.njk'`) or custom handler functions, passing `{ fsy, locale, isDev, url, method }` to templates.
60
+ - **Middleware & Hooks**: Route lifecycle hooks can be declared per-page or globally via `pages/_hooks.js`.
61
+ - **API Endpoints & Routing Architecture**:
62
+ - ⚠️ **CRITICAL ANTI-PATTERN: NEVER create a `routes/` or `src/routes/` directory. NEVER use `express.Router()`, `app.get()`, or `app.post()` for application endpoints.**
63
+ - **100% File-Based Routing**: All API routes MUST be created inside `pages/api/...` with HTTP method extensions:
64
+ - `pages/api/notes.get.js` → `GET /api/notes`
65
+ - `pages/api/notes.post.js` → `POST /api/notes`
66
+ - `pages/api/notes/[id].get.js` → `GET /api/notes/:id`
67
+ - `pages/api/notes/[id].delete.js` → `DELETE /api/notes/:id`
68
+ - **Standard API Route Module Contract**:
69
+ ```javascript
70
+ const { defineApi } = require('webspresso');
71
+
72
+ module.exports = defineApi({
73
+ schema: ({ z }) => ({
74
+ body: z.object({ title: z.string().min(1) }),
75
+ params: z.object({ id: z.string().optional() }),
76
+ }),
77
+ middleware: ['auth'], // optional named or functional middleware
78
+ handler: async (req, res, ctx) => {
79
+ // req.db and req.service are automatically injected
80
+ // req.input.body contains the validated payload
81
+ const item = await req.db.getRepository('Note').create(req.input.body);
82
+ return res.status(201).json(item);
83
+ },
84
+ });
85
+ ```
86
+ - **Modular Architecture (`src/modules/` or `modules/`)**:
87
+ - Encapsulate domain features using `defineModule({ name, pages, api, services, middlewares })`.
88
+ - Auto-registers routes (`/auth/login`, `/api/auth/login`), services (`'auth.login'`), and scoped middlewares without manual router glue.
89
+
90
+ ### 1.2 Services Layer (`services/`, `src/services/`)
91
+ - **File-based Auto-Discovery**: Services located in `services/` map directly to dot-separated service names (e.g. `services/user/create.js` → `'user.create'`) and camelCase aliases (`'user.reset-password'` & `'user.resetPassword'`).
92
+ - **Declarative Validation & Authorization**: Define optional Zod `schema`, `auth` (boolean, role string/array, predicate), `timeout` (ms), `transaction: true` (ACID transaction propagation across nested calls), and `cache: { ttl, key }`.
93
+ - **Unified Invocation**: Consumed via `ctx.service('service.name', input)` from SSR loaders, `req.service()` in API routes, or standalone `createServiceRegistry()`.
94
+
95
+ ### 1.3 ORM & Database Layer (`core/orm`, `models/`)
96
+ - ⚠️ **CRITICAL ANTI-PATTERN: NEVER use raw Knex queries (e.g. `db('table')` or `knex('table')`) in application code.** Raw queries bypass schema validation, lifecycle hooks, soft-deletes, multi-tenant scopes, hidden fields, and query caching.
97
+ - **ALWAYS Use Repositories**: Accessed via `db.getRepository('ModelName')` or `req.db.getRepository('ModelName')`:
98
+ - `await repo.findById(id)`
99
+ - `await repo.find({ status: 'active' })`
100
+ - `await repo.findOne({ slug })`
101
+ - `await repo.create(data)` *(validates schema & executes hooks)*
102
+ - `await repo.update(id, data)`
103
+ - `await repo.delete(id)` *(respects soft deletes)*
104
+ - `await repo.query().where('price', '>', 50).paginate({ page, limit })`
105
+ - `await repo.query().include('user', 'tags').find()` *(eager loading)*
106
+ - **Model Definition**: Defined in `models/*.js` using `defineModel({ name, table, schema, relations, scopes, hidden, admin, cache })`.
107
+ - **Schema & Types**: Built with `zdb` schema builder (`zdb.id()`, `zdb.string()`, `zdb.integer()`, `zdb.boolean()`, `zdb.file()`, `zdb.json()`).
108
+ - **Ambient Transactions**: Repositories automatically bind to ambient transactions (`AsyncLocalStorage`) inside `db.transaction()` and services (`transaction: true`) without manual `trx` passing.
109
+ - **Query Caching**: Memory/provider query cache configured per database instance or model (`cache: 'auto'|'smart'|true`).
110
+ - **Migrations**: Database schema changes managed via Knex migrations in `migrations/` (`webspresso db:migrate`).
111
+
112
+ ### 1.4 Admin Panel Architecture (`plugins/admin-panel`)
113
+ - **SPA CRUD Engine**: Modular Mithril.js SPA mounted at `/_admin` powered by `adminPanelPlugin({ db })`.
114
+ - **Admin Module Registration**: Registered using `adminApi.registerModule` or `adminApi.registerPageDir`.
115
+ - **Custom Admin Pages**:
116
+ - `componentFile`: Path to a clean Mithril component `.js` file.
117
+ - `pagesDir`: Directory auto-discovery containing page folders with `page.json` and `component.js`.
118
+ - **Auto Layout Wrapping**: By default (`layout: true`), custom page views are automatically wrapped inside the Admin `Layout` and `Breadcrumb` containers without requiring manual `m(Layout, ...)` nesting. Set `layout: false` for full-screen / custom canvas pages.
119
+ - **Extension Points**:
120
+ - Custom Field Renderers: `registry.registerFieldRenderer(type, { display, edit })`.
121
+ - Widgets: `registry.registerWidget(id, config)`.
122
+ - Actions & Bulk Actions: Single record buttons (`registerAction`) and multi-select table actions (`registerBulkAction`).
123
+ - **Session Isolation**: Admin staff authentication uses a separate session (`req.session.adminUser` / `/_admin/api/auth/*`), isolated from public site auth (`req.user`).
124
+
125
+ ### 1.5 Plugin Ecosystem (`plugins/`)
126
+ Plugins expose `name`, `version`, `dependencies`, and lifecycle hooks (`register(ctx)`, `onRoutesReady(ctx)`):
127
+ - `adminPanelPlugin`: Model CRUD, custom pages, widgets, user management.
128
+ - `fileManagerPlugin`: Media library, directory tree, file preview, and drag-and-drop uploads.
129
+ - `basicAuthPlugin`: Zero-dependency HTTP Basic Authentication (RFC 7617) with named route middleware (`ctx.middlewares.basicAuth`) and global protection.
130
+ - `contentPlugin`: Schema-driven CMS with inline editing and headless API.
131
+ - `uploadPlugin`: Multipart file uploads with local/cloud storage providers.
132
+ - `redirectPlugin`: Configurable HTTP 301–308 redirects.
133
+ - `rateLimitPlugin`: Named rate limiters (`express-rate-limit`).
134
+ - `siteAnalyticsPlugin`: Self-hosted page view analytics and client JS error tracking.
135
+ - `emailPlugin`: MJML template compilation & Nodemailer integration.
136
+ - `polarPlugin`: Polar.sh subscription billing (checkout, portal, webhooks, Customer State sync). Requires `rateLimitPlugin` before polar for rate limiters. Supports `hooks.isPaidUser`, `syncBeforeCheckout`, `syncBillingForAppUser`. See `docs/guides/polar-production-checklist.md`.
137
+ - `auditLogPlugin`: Admin mutation audit logging.
138
+ - `ormCacheAdminPlugin`: Cache inspection and invalidation dashboard.
139
+ - `corsPlugin`: Zero-dependency Cross-Origin Resource Sharing handler.
140
+ - `csrfPlugin`: CSRF token validation and Nunjucks form helpers.
141
+ - `realtimePlugin`: Framework-agnostic, plugin-based realtime layer (`core/realtime`) with WebSocket, SSE, Socket.IO, and distributed Redis Pub/Sub adapters.
142
+ - `restResourcePlugin`: Zero-boilerplate RESTful CRUD API generator directly from ORM models with eager loading, sanitization, filtering, pagination, and soft-delete scoping.
143
+ - `xlsxPlugin`: Excel spreadsheet generation, parsing, ORM streaming export (`res.xlsx`), and built-in services (`xlsx.generate`, `xlsx.parse`, `xlsx.exportModel`).
144
+ - `csvPlugin`: RFC 4180 CSV generator, parser, Excel UTF-8 BOM compatibility, formula sanitization, streaming writer (`res.csv`), and built-in services (`csv.generate`, `csv.parse`, `csv.exportModel`).
145
+
146
+ ---
147
+
148
+ ## 2. Development & Testing Workflow
149
+
150
+ ### 2.1 Essential Commands
151
+ - **Dev Server**: `npm run dev` or `webspresso dev`
152
+ - **Run Vitest Unit Tests**: `npm test` or `npx vitest run tests/unit/admin-panel/`
153
+ - **Run Migrations**: `npx webspresso db:migrate`
154
+ - **Project Sanity Check**: `npx webspresso doctor`
155
+ - **Scaffold AI Agent Rules**: `npx webspresso agents:init`
156
+
157
+ ### 2.2 Testing & Quality Assurance
158
+ - **Zero Regression Policy**: Always run unit tests before declaring any task complete.
159
+ - **Targeted Test Execution**: Run specific unit test files during development for fast feedback (`npx vitest run tests/unit/admin-panel/admin-module-files.test.js`).
160
+ - **API Backward Compatibility**: Never break existing `registerModule`, `registerPage`, or `adminApi` contracts. Always add new parameters as optional or backward-compatible enhancements.
161
+
162
+ ---
163
+
164
+ ## 3. Coding Standards & Conventions
165
+
166
+ 1. **Strict Signature & Schema Verification**: Always verify function signatures and object schemas by viewing authoritative source files before calling or extending them.
167
+ 2. **File & Component Separation**: Keep client-side components in clean standalone JS files (`component.js` / `componentFile`) rather than escaping inline template strings.
168
+ 3. **Log & Traceback Inspection**: Base all bug fixes strictly on exact runtime error log tracebacks and empirical test output. Never swallow errors or return dummy fallbacks.
169
+ 4. **Strict File-Based Routing (NO `routes/` or `app.get()`)**: Webspresso is strictly file-based. Never create manual router files (`src/routes/*.js`), never call `app.get()`, and never use `express.Router()`. All application pages belong in `pages/` and all API endpoints belong in `pages/api/` with HTTP method extensions (`.get.js`, `.post.js`, `.delete.js`, `.patch.js`, `.put.js`).
170
+ 5. **Strict Repository Pattern (NO Raw `db('table')`)**: Never write raw Knex table queries in route handlers or services. Always use `req.db.getRepository('ModelName')` to ensure schema validation, hooks, scopes, and query caching are applied.
171
+ 6. **Strict Services Layer (NO `controllers/`)**: Never create a `controllers/` folder or controller classes. Encapsulate business logic in `services/domain/action.js` and call via `ctx.service('domain.action', input)`.
172
+ 7. **Native Dual Auth (NO External JWT/Passport Packages)**: Never install `jsonwebtoken`, `passport`, or `express-session`. Always use native `req.auth` and `webspresso/core/auth`.
173
+ 8. **Page Data Loaders (NO Manual `res.render()`)**: Never call `res.render()` inside custom handlers for web pages. Use companion loaders `pages/*.js` exporting `async function load({ req, res, db, ctx })`.
174
+ 9. **Semantic Exceptions (NO Generic Errors / Manual Responses)**: Never return manual `res.status(404).json(...)` inside services or loaders. Always throw semantic errors: `NotFoundError`, `ValidationError`, `UnauthorizedError`, `ForbiddenError`.
175
+ 10. **Background Jobs (NO BullMQ / `setTimeout`)**: Never use unmanaged `setTimeout` or external queues. Place job workers in `jobs/` and dispatch via `req.queue.dispatch()`.