webspresso 0.0.95 → 0.0.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/ADMIN.md +225 -0
- package/.agents/AGENTS.md +72 -0
- package/.agents/ARCHITECTURE.md +119 -0
- package/.agents/AUTH.md +103 -0
- package/.agents/CLI.md +115 -0
- package/.agents/COMPRESSION.md +59 -0
- package/.agents/CONVENTIONS.md +46 -0
- package/.agents/EMAIL.md +141 -0
- package/.agents/ERRORS.md +201 -0
- package/.agents/MCP.md +103 -0
- package/.agents/ORM.md +230 -0
- package/.agents/PLUGINS.md +419 -0
- package/.agents/QUEUE.md +113 -0
- package/.agents/REALTIME.md +213 -0
- package/.agents/ROUTING.md +292 -0
- package/.agents/SERVICES.md +341 -0
- package/.agents/SHUTDOWN.md +67 -0
- package/.agents/STREAMING.md +73 -0
- package/.agents/WORKFLOW.md +27 -0
- package/.agents/internal/DOCUMENTATION_REVIEW.md +485 -0
- package/.agents/internal/TECHNICAL_REVIEW.md +428 -0
- package/.agents/skills/webspresso-admin-and-plugins/SKILL.md +122 -0
- package/.agents/skills/webspresso-framework/SKILL.md +56 -0
- package/.agents/skills/webspresso-orm-and-database/SKILL.md +119 -0
- package/.agents/skills/webspresso-routing-and-api/SKILL.md +114 -0
- package/.agents/skills/webspresso-services/SKILL.md +101 -0
- package/.cursorrules +14 -0
- package/AGENTS.md +175 -0
- package/CLAUDE.md +54 -0
- package/README.md +18 -14
- package/bin/commands/admin-password.js +2 -1
- package/bin/commands/admin-setup.js +1 -1
- package/bin/commands/agents-init.js +209 -0
- package/bin/commands/api.js +114 -48
- package/bin/commands/audit-prune.js +1 -1
- package/bin/commands/doctor.js +35 -0
- package/bin/commands/favicon-generate.js +1 -1
- package/bin/commands/new.js +13 -2
- package/bin/commands/orm-map.js +5 -4
- package/bin/commands/page.js +75 -89
- package/bin/commands/polar-migrate.js +1 -1
- package/bin/commands/seed.js +1 -1
- package/bin/commands/service.js +77 -0
- package/bin/webspresso.js +2 -2
- package/core/auth/hash.js +10 -5
- package/core/compileSchema.js +1 -1
- package/core/errors/middleware.js +22 -2
- package/core/errors/normalize.js +29 -2
- package/{utils/schemaCache.js → core/schema-cache.js} +2 -3
- package/index.d.ts +306 -0
- package/index.js +35 -1
- package/package.json +36 -14
- package/plugins/admin-panel/app.js +10 -9
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +22 -1
- package/plugins/admin-panel/core/api-extensions.js +4 -0
- package/plugins/basic-auth/index.js +3 -1
- package/plugins/content/client/inline-edit.js +12 -12
- package/plugins/cors.js +6 -7
- package/plugins/csrf/index.js +3 -2
- package/plugins/csv/engine.js +447 -0
- package/plugins/csv/index.js +94 -0
- package/plugins/csv/middleware.js +80 -0
- package/plugins/csv/services.js +138 -0
- package/plugins/file-manager/admin-component.js +613 -0
- package/plugins/file-manager/api-handlers.js +261 -0
- package/plugins/file-manager/core.js +601 -0
- package/plugins/file-manager/index.js +139 -0
- package/plugins/file-manager/security.js +217 -0
- package/plugins/index.js +45 -79
- package/plugins/mcp/transports/sse.js +4 -2
- package/plugins/site-analytics/admin-component.js +7 -8
- package/plugins/xlsx/engine.js +397 -0
- package/plugins/xlsx/index.js +91 -0
- package/plugins/xlsx/middleware.js +87 -0
- package/plugins/xlsx/services.js +118 -0
- package/src/api/api-loader.js +233 -0
- package/src/api/define-api.js +35 -0
- package/src/discovery/file-route-parser.js +201 -0
- package/src/discovery/scan-routes.js +265 -0
- package/src/file-router.js +9 -1
- package/src/modules/define-module.js +99 -0
- package/src/modules/module-discovery.js +117 -0
- package/src/pages/define-page.js +36 -0
- package/src/pages/page-loader.js +214 -0
- package/src/routing/mount-discovered-routes.js +78 -0
- package/src/routing/route-table.js +191 -0
- package/src/server.js +112 -15
- package/src/services/builtins/file-manager.js +178 -0
- package/src/services/discovery.js +6 -1
- package/src/services/index.js +6 -11
- package/bin/commands/skill.js +0 -187
- package/templates/skills/webspresso-usage/REFERENCE-framework.md +0 -289
- package/templates/skills/webspresso-usage/REFERENCE-kernel.md +0 -93
- 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.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webspresso-admin-and-plugins
|
|
3
|
+
description: >-
|
|
4
|
+
Extend the Mithril.js Admin Panel SPA and configure official plugins in Webspresso.
|
|
5
|
+
Use when creating custom admin pages (component.js, page.json), custom field renderers,
|
|
6
|
+
dashboard widgets, actions, or configuring plugins like fileManager, xlsx, csv, polar, realtime, csrf, cors, and basicAuth.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Webspresso Admin Panel & Plugins Skill
|
|
10
|
+
|
|
11
|
+
The Admin Panel is a modular Mithril.js SPA mounted at `/_admin` powered by `adminPanelPlugin({ db })`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Custom Admin Pages (`pagesDir` or `registerPageDir`)
|
|
16
|
+
|
|
17
|
+
Folder structure for auto-discovered admin pages:
|
|
18
|
+
```text
|
|
19
|
+
admin/pages/
|
|
20
|
+
└── system-stats/
|
|
21
|
+
├── page.json
|
|
22
|
+
└── component.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### `page.json`
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"id": "system-stats",
|
|
29
|
+
"label": "System Statistics",
|
|
30
|
+
"icon": "activity",
|
|
31
|
+
"order": 10,
|
|
32
|
+
"layout": true,
|
|
33
|
+
"permission": "admin"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `component.js` (Clean Mithril Component)
|
|
38
|
+
```javascript
|
|
39
|
+
module.exports = {
|
|
40
|
+
oninit(vnode) {
|
|
41
|
+
vnode.state.stats = null;
|
|
42
|
+
vnode.state.loading = true;
|
|
43
|
+
m.request({ method: 'GET', url: '/_admin/api/custom/stats' }).then((res) => {
|
|
44
|
+
vnode.state.stats = res;
|
|
45
|
+
vnode.state.loading = false;
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
view(vnode) {
|
|
49
|
+
if (vnode.state.loading) return m('.p-6', 'Loading stats...');
|
|
50
|
+
return m('.space-y-4', [
|
|
51
|
+
m('h2.text-xl.font-bold', 'System Overview'),
|
|
52
|
+
m('.grid.grid-cols-3.gap-4', [
|
|
53
|
+
m('.card.p-4.border.rounded', [
|
|
54
|
+
m('.text-sm.text-gray-500', 'Total Users'),
|
|
55
|
+
m('.text-2xl.font-semibold', vnode.state.stats.usersCount),
|
|
56
|
+
]),
|
|
57
|
+
]),
|
|
58
|
+
]);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. Admin Panel Extension Points
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
// Register custom widget in dashboard
|
|
69
|
+
registry.registerWidget('recent-signups', {
|
|
70
|
+
label: 'Recent Signups',
|
|
71
|
+
component: require('./widgets/recent-signups'),
|
|
72
|
+
width: 'half', // 'full' | 'half' | 'third'
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Register single record action button
|
|
76
|
+
registry.registerAction('User', {
|
|
77
|
+
name: 'impersonate',
|
|
78
|
+
label: 'Impersonate',
|
|
79
|
+
icon: 'user-check',
|
|
80
|
+
handler: async (record) => { ... },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Register custom field display/edit renderer
|
|
84
|
+
registry.registerFieldRenderer('color-picker', {
|
|
85
|
+
display: (val) => m('.w-6.h-6.rounded', { style: { backgroundColor: val } }),
|
|
86
|
+
edit: (val, onChange) => m('input[type=color]', { value: val, onchange: (e) => onChange(e.target.value) }),
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 3. Official Plugin Catalog & Usage
|
|
93
|
+
|
|
94
|
+
In `createApp({ plugins: [...] })`:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
const {
|
|
98
|
+
adminPanelPlugin,
|
|
99
|
+
fileManagerPlugin,
|
|
100
|
+
xlsxPlugin,
|
|
101
|
+
csvPlugin,
|
|
102
|
+
basicAuthPlugin,
|
|
103
|
+
corsPlugin,
|
|
104
|
+
csrfPlugin,
|
|
105
|
+
realtimePlugin,
|
|
106
|
+
polarPlugin,
|
|
107
|
+
} = require('webspresso/plugins');
|
|
108
|
+
|
|
109
|
+
createApp({
|
|
110
|
+
plugins: [
|
|
111
|
+
adminPanelPlugin({ db }),
|
|
112
|
+
fileManagerPlugin({ baseDir: './public/uploads', publicBasePath: '/uploads' }),
|
|
113
|
+
xlsxPlugin(),
|
|
114
|
+
csvPlugin(),
|
|
115
|
+
basicAuthPlugin({ users: { admin: process.env.ADMIN_BASIC_AUTH_PASS }, routes: ['/metrics'] }),
|
|
116
|
+
corsPlugin({ origin: ['https://example.com'], credentials: true }),
|
|
117
|
+
csrfPlugin({ cookie: true }),
|
|
118
|
+
realtimePlugin({ adapter: 'websocket' }),
|
|
119
|
+
polarPlugin({ apiKey: process.env.POLAR_ACCESS_TOKEN }),
|
|
120
|
+
],
|
|
121
|
+
});
|
|
122
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webspresso-framework
|
|
3
|
+
description: >-
|
|
4
|
+
Core workflow and guide for Webspresso, a lightweight, zero-dependency-sprawl full-stack
|
|
5
|
+
Node.js SSR and API framework. Use when scaffolding, architecting, building, or debugging
|
|
6
|
+
Webspresso applications, configuring plugins, dual auth, response compression, graceful shutdown,
|
|
7
|
+
and error boundaries.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Webspresso Framework Master Guide
|
|
11
|
+
|
|
12
|
+
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.
|
|
13
|
+
|
|
14
|
+
## 🛡️ 4-Step Mandatory Agent Workflow Protocol
|
|
15
|
+
|
|
16
|
+
1. **Discover & Triage**: Identify relevant topic guides (`.agents/`) and inspect existing files in `pages/api/`, `models/`, `services/`.
|
|
17
|
+
2. **Contract Adherence**: Export `{ schema, middleware, handler }` for APIs, `defineModel` for ORM, `defineService` for services.
|
|
18
|
+
3. **Zero External Dependencies**: Core functionality relies strictly on native Node.js modules (`crypto`, `path`, `fs`, `zlib`, `events`). NEVER install ad-hoc packages for JWT, passport, express-session, or custom routers.
|
|
19
|
+
4. **Targeted Verification**: Run specific Vitest unit tests (`npx vitest run tests/...`) to ensure zero regressions.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## ⚖️ Golden Rules & Anti-Patterns
|
|
24
|
+
|
|
25
|
+
| Category | ❌ NEVER DO THIS (Anti-Pattern) | ✅ ALWAYS DO THIS (Webspresso Way) |
|
|
26
|
+
| :--- | :--- | :--- |
|
|
27
|
+
| **Routing** | `routes/index.js`, `express.Router()`, `app.get('/api/users')` | `pages/api/users.get.js` exporting `{ schema, handler }` |
|
|
28
|
+
| **Database** | `db('users').where({ id }).select()` (Raw Knex) | `db.getRepository('User').findById(id)` |
|
|
29
|
+
| **Business Logic** | `controllers/UserController.js` | `services/user/get.js` → `ctx.service('user.get', input)` |
|
|
30
|
+
| **Auth** | `npm i jsonwebtoken passport express-session` | Built-in `req.auth`, `core/auth`, `middleware: ['jwt']` |
|
|
31
|
+
| **SSR Rendering**| `res.render('profile.njk', data)` inside handlers | Companion loader `pages/profile.js` exporting `async function load()` |
|
|
32
|
+
| **Exceptions** | `res.status(404).json({ error: 'Not found' })` | `throw new NotFoundError('User not found')` |
|
|
33
|
+
| **Background** | `setTimeout(...)`, `npm i bullmq` | `jobs/user/welcome.js` → `req.queue.dispatch('user.welcome', data)` |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🚀 CLI Commands
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
webspresso dev # Start dev server with hot reload
|
|
41
|
+
webspresso start # Start production server
|
|
42
|
+
webspresso doctor # Run system sanity checks
|
|
43
|
+
webspresso db:migrate # Run pending Knex migrations
|
|
44
|
+
webspresso db:seed # Run database seeders
|
|
45
|
+
webspresso agents:init # Scaffold AI Agent rules and skills
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🏗️ Core Architecture Overview
|
|
51
|
+
|
|
52
|
+
- **`pages/` & `pages/api/`**: File-based SSR templates (`.njk`), companion data loaders (`.js`), and method-suffixed API endpoints (`.get.js`, `.post.js`).
|
|
53
|
+
- **`services/`**: Auto-discovered domain services mapping to dot-separated names (`'user.create'`).
|
|
54
|
+
- **`models/`**: Schema-driven ORM models with `zdb` definitions, repositories, relations, scopes, and query cache.
|
|
55
|
+
- **`plugins/`**: Modular extension ecosystem (Admin Panel, Media Library, Polar Billing, CSV/XLSX, Realtime, CSRF, CORS, Basic Auth).
|
|
56
|
+
- **`views/`**: Nunjucks layouts, partials, and `fsy` template helpers.
|