webspresso 0.0.108 โ 0.0.110
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/LICENSE +21 -0
- package/README.md +3 -3
- package/bin/commands/add-esbuild.js +7 -3
- package/bin/commands/add-tailwind.js +9 -5
- package/bin/commands/build.js +20 -4
- package/bin/commands/dev.js +57 -7
- package/bin/commands/doctor.js +42 -1
- package/bin/commands/favicon-generate.js +10 -3
- package/bin/commands/new.js +8 -3
- package/bin/commands/start.js +3 -1
- package/bin/utils/add-command.js +16 -0
- package/core/app.js +45 -3
- package/core/auth/authenticate.js +3 -3
- package/core/auth/hash.js +167 -43
- package/core/auth/index.js +13 -1
- package/core/auth/jwt.js +21 -2
- package/core/auth/manager.js +63 -14
- package/core/auth/middleware.js +4 -2
- package/core/auth/oauth.js +5 -1
- package/core/auth/tokens.js +7 -2
- package/core/auth/totp.js +42 -6
- package/core/auth/user-agent.js +2 -0
- package/core/client/adapter/datastar.js +1401 -0
- package/core/client/api.js +1337 -0
- package/core/client/controller.js +1706 -0
- package/core/client/debug.js +367 -0
- package/core/client/devtool.js +1134 -0
- package/core/client/forms.js +1164 -0
- package/core/client/fragments.js +894 -0
- package/core/client/index.d.ts +59 -0
- package/core/client/index.js +391 -0
- package/core/client/lite.js +175 -0
- package/core/client/server-fragments.js +868 -0
- package/core/client/storage.js +339 -0
- package/core/client/utils.js +281 -0
- package/core/compression/middleware.js +277 -26
- package/core/context/app-context.js +25 -3
- package/core/context/request.js +32 -4
- package/core/errors/middleware.js +14 -0
- package/core/events/dispatcher.js +33 -0
- package/core/forms/flash.js +136 -102
- package/core/health/middleware.js +36 -6
- package/core/http/pipeline.js +45 -6
- package/core/index.js +25 -7
- package/core/kernel/view.js +41 -10
- package/core/metrics/middleware.js +30 -6
- package/core/metrics/registry.js +13 -5
- package/core/orm/cache/fingerprint.js +32 -11
- package/core/orm/cache/layer.js +19 -2
- package/core/orm/hidden.js +145 -0
- package/core/orm/model.js +48 -2
- package/core/orm/query-builder.js +343 -6
- package/core/orm/query-filters.js +14 -2
- package/core/orm/repository.js +64 -13
- package/core/orm/schema-helpers.js +9 -6
- package/core/orm/transaction.js +50 -6
- package/core/orm/types.js +4 -0
- package/core/queue/adapters/database.js +184 -2
- package/core/queue/adapters/memory.js +153 -5
- package/core/queue/adapters/redis.js +59 -4
- package/core/queue/job.js +14 -1
- package/core/queue/manager.js +115 -0
- package/core/resilience/circuit-breaker.js +27 -8
- package/core/services/builtins/exchange.js +174 -7
- package/core/services/builtins/file-manager.js +36 -0
- package/core/services/builtins/mail.js +27 -0
- package/core/services/builtins/queue.js +144 -0
- package/core/services/builtins/security.js +118 -0
- package/core/services/builtins/webhook.js +110 -0
- package/core/services/executor.js +38 -16
- package/core/services/index.js +4 -1
- package/core/sse/stream.js +28 -5
- package/core/utils/timeout.js +8 -1
- package/core/validation/compiler.js +10 -7
- package/index.d.ts +1320 -74
- package/index.js +128 -8
- package/package.json +75 -27
- package/plugins/admin-panel/client/parts/08-record-list.js +717 -70
- package/plugins/admin-panel/index.js +19 -8
- package/plugins/csrf/index.js +3 -3
- package/plugins/data-exchange/export.js +214 -0
- package/plugins/data-exchange/import.js +48 -5
- package/plugins/data-exchange/index.js +70 -28
- package/plugins/data-exchange/preview.js +266 -0
- package/plugins/data-exchange/template.js +242 -0
- package/plugins/email/admin-component.js +783 -141
- package/plugins/email/api-handlers.js +51 -1
- package/plugins/email/index.js +5 -0
- package/plugins/email/service.js +48 -0
- package/plugins/file-manager/admin-component.js +1546 -70
- package/plugins/file-manager/api-handlers.js +166 -1
- package/plugins/file-manager/core.js +598 -8
- package/plugins/file-manager/index.js +8 -0
- package/plugins/index.js +7 -0
- package/plugins/mcp/auth.js +3 -3
- package/plugins/oauth/index.js +36 -3
- package/plugins/queue/admin-component.js +1092 -0
- package/plugins/queue/api-handlers.js +248 -0
- package/plugins/queue/index.js +69 -0
- package/plugins/rest-resources/index.js +7 -2
- package/plugins/security/admin-component.js +689 -0
- package/plugins/security/api-handlers.js +169 -0
- package/plugins/security/audit.js +153 -0
- package/plugins/security/bruteforce.js +244 -0
- package/plugins/security/firewall.js +459 -0
- package/plugins/security/headers.js +214 -0
- package/plugins/security/honeypot.js +234 -0
- package/plugins/security/incident-recorder.js +137 -0
- package/plugins/security/index.js +211 -0
- package/plugins/seo-checker/analyzer.js +20 -7
- package/plugins/upload/index.js +36 -0
- package/plugins/webhooks/admin-component.js +702 -175
- package/plugins/webhooks/api-handlers.js +75 -1
- package/plugins/webhooks/dispatcher.js +290 -11
- package/plugins/webhooks/index.js +37 -2
- package/plugins/webhooks/sender.js +56 -0
- package/plugins/xlsx/engine.js +19 -4
- package/src/api/api-loader.js +19 -1
- package/src/bundle/index.js +443 -17
- package/src/client-runtime/bootstrap-swup.js +9 -0
- package/src/client-runtime/mount.js +15 -20
- package/src/client-runtime/resolve.js +3 -2
- package/src/dev/api-typegen.js +1300 -0
- package/src/dev/banner.js +10 -1
- package/src/dev/colors.js +1 -1
- package/src/dev/index.js +7 -1
- package/src/dev/typegen.js +173 -17
- package/src/dev-reload/index.js +1 -1
- package/src/discovery/file-route-parser.js +17 -3
- package/src/discovery/scan-routes.js +4 -1
- package/src/file-router.js +253 -69
- package/src/helpers.js +46 -26
- package/src/njk-frontmatter.js +30 -4
- package/src/routing/cascading.js +26 -8
- package/src/routing/mount-discovered-routes.js +76 -0
- package/src/server.js +231 -70
- package/views/partials/webspresso-client-runtime.njk +1 -9
- package/.agents/ADMIN.md +0 -426
- package/.agents/AGENTS.md +0 -96
- package/.agents/ARCHITECTURE.md +0 -163
- package/.agents/AUTH.md +0 -581
- package/.agents/CACHE.md +0 -148
- package/.agents/CLI.md +0 -649
- package/.agents/COMPRESSION.md +0 -59
- package/.agents/CONTEXT.md +0 -152
- package/.agents/CONVENTIONS.md +0 -50
- package/.agents/EARLY_HINTS.md +0 -120
- package/.agents/EMAIL.md +0 -223
- package/.agents/ERRORS.md +0 -260
- package/.agents/EVENTS.md +0 -179
- package/.agents/FLAGS.md +0 -118
- package/.agents/HEALTH.md +0 -118
- package/.agents/LIMITS.md +0 -109
- package/.agents/LOGGING.md +0 -93
- package/.agents/MCP.md +0 -103
- package/.agents/METRICS.md +0 -127
- package/.agents/MIGRATION_JOBS.md +0 -95
- package/.agents/ORM.md +0 -700
- package/.agents/PLUGINS.md +0 -729
- package/.agents/QUEUE.md +0 -290
- package/.agents/RATE_LIMIT.md +0 -147
- package/.agents/REALTIME.md +0 -213
- package/.agents/RESILIENCE.md +0 -235
- package/.agents/ROUTING.md +0 -605
- package/.agents/SCALE_OUT.md +0 -109
- package/.agents/SECRETS.md +0 -117
- package/.agents/SERVICES.md +0 -341
- package/.agents/SHUTDOWN.md +0 -74
- package/.agents/STREAMING.md +0 -108
- package/.agents/WORKFLOW.md +0 -27
- package/.agents/internal/DOCUMENTATION_REVIEW.md +0 -485
- package/.agents/internal/TECHNICAL_REVIEW.md +0 -428
- package/.agents/skills/webspresso-admin-and-plugins/SKILL.md +0 -122
- package/.agents/skills/webspresso-framework/SKILL.md +0 -89
- package/.agents/skills/webspresso-orm-and-database/SKILL.md +0 -127
- package/.agents/skills/webspresso-routing-and-api/SKILL.md +0 -130
- package/.agents/skills/webspresso-services/SKILL.md +0 -134
- package/.cursorrules +0 -14
- package/AGENTS.md +0 -203
- package/CLAUDE.md +0 -54
- package/core/kernel/run-demo.js +0 -58
- package/plugins/admin-panel/styles.js +0 -9
- package/plugins/data-exchange/export-xlsx.js +0 -119
- package/src/client-runtime/bootstrap-alpine-swup.js +0 -34
package/.agents/ADMIN.md
DELETED
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
# Mithril.js Admin Panel Customization & Extension Guide
|
|
2
|
-
|
|
3
|
-
Webspresso includes a customizable, zero-build Mithril.js Single Page Application (SPA) Admin Panel (`plugins/admin-panel`). It provides automatic CRUD interfaces for ORM models and supports extension points for custom pages, widgets, custom field renderers, actions, and client-side component injections.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Architecture & Session Isolation
|
|
8
|
-
|
|
9
|
-
The Admin Panel operates as a self-contained Mithril.js SPA mounted at `/_admin`.
|
|
10
|
-
|
|
11
|
-
- **Isolated Auth Session**: Admin staff authentication uses a dedicated session key (`req.session.adminUser`), isolated from public site user sessions (`req.user`).
|
|
12
|
-
- **Auth Endpoints**:
|
|
13
|
-
- `POST /_admin/api/auth/setup` โ Initial staff account setup (disabled once first admin exists).
|
|
14
|
-
- `POST /_admin/api/auth/login` โ Staff authentication.
|
|
15
|
-
- `POST /_admin/api/auth/logout` โ Terminate admin session.
|
|
16
|
-
- `GET /_admin/api/auth/me` โ Current authenticated staff user details.
|
|
17
|
-
- `GET /_admin/api/auth/check` โ Check if admin setup is required.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 2. Model Admin Metadata (`defineModel`)
|
|
22
|
-
|
|
23
|
-
Configure model behavior in the Admin Panel using the `admin` property when calling `defineModel`:
|
|
24
|
-
|
|
25
|
-
```js
|
|
26
|
-
import { defineModel, zdb } from 'webspresso';
|
|
27
|
-
|
|
28
|
-
export default defineModel({
|
|
29
|
-
name: 'Product',
|
|
30
|
-
table: 'products',
|
|
31
|
-
schema: zdb.schema({
|
|
32
|
-
id: zdb.id(),
|
|
33
|
-
name: zdb.string(),
|
|
34
|
-
slug: zdb.string(),
|
|
35
|
-
price: zdb.number(),
|
|
36
|
-
status: zdb.string({ default: 'active' }),
|
|
37
|
-
}),
|
|
38
|
-
admin: {
|
|
39
|
-
enabled: true, // Expose in Admin navigation
|
|
40
|
-
label: 'Products', // Display label
|
|
41
|
-
icon: '๐ฆ', // Navigation icon
|
|
42
|
-
displayField: 'name', // Field used for title/representation
|
|
43
|
-
searchFields: ['name', 'slug'], // Fields searched by table search input
|
|
44
|
-
filterable: ['status'], // Column filters enabled in table header
|
|
45
|
-
defaultSort: { column: 'id', order: 'desc' },
|
|
46
|
-
sortableColumns: ['name', 'price'], // Optional whitelist of sortable columns
|
|
47
|
-
sortable: true, // Set false to disable table sorting completely
|
|
48
|
-
readOnly: false, // Disable create/edit/delete actions
|
|
49
|
-
|
|
50
|
-
// Django Admin-inspired Features:
|
|
51
|
-
inlines: [ // Parent-child relational editing (Tabular/Stacked)
|
|
52
|
-
{
|
|
53
|
-
model: 'ProductVariant',
|
|
54
|
-
foreignKey: 'product_id',
|
|
55
|
-
fields: ['sku', 'price', 'inventory'],
|
|
56
|
-
title: 'Variants',
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
listEditable: ['price', 'status'], // Direct table row quick-edit without opening edit form
|
|
60
|
-
dateHierarchy: 'created_at', // Period drilldown navigation (Years -> Months -> Days)
|
|
61
|
-
listFilter: ['status'], // Faceted filtering with record counts per value
|
|
62
|
-
actions: [ // Declarative model-level bulk operations
|
|
63
|
-
{
|
|
64
|
-
id: 'mark-active',
|
|
65
|
-
label: 'Mark as Active',
|
|
66
|
-
handler: async ({ ids, repo, db, req, user }) => {
|
|
67
|
-
for (const id of ids) {
|
|
68
|
-
await repo.update(id, { status: 'active' });
|
|
69
|
-
}
|
|
70
|
-
return { updated: ids.length };
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 3-State Table Column Sorting
|
|
79
|
-
Table column headers support interactive 3-state cycling:
|
|
80
|
-
1. `Unsorted` (default, `โ` icon)
|
|
81
|
-
2. `ASC` (1st click, `โฒ` icon)
|
|
82
|
-
3. `DESC` (2nd click, `โผ` icon)
|
|
83
|
-
4. `Unsorted` (3rd click, reverts to default primary key order)
|
|
84
|
-
|
|
85
|
-
Column sortability can be configured per-column:
|
|
86
|
-
- `zdb.string({ sortable: true })` / `zdb.text({ sortable: false })`
|
|
87
|
-
- `zdb.string().config({ sortable: false })`
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## 3. Admin REST API (`/_admin/api/*`)
|
|
92
|
-
|
|
93
|
-
The Admin SPA communicates with the backend via JSON REST endpoints:
|
|
94
|
-
|
|
95
|
-
- `GET /_admin/api/models` โ List all models exposed to admin with schemas & metadata.
|
|
96
|
-
- `GET /_admin/api/models/:modelName/records` โ List paginated records (query params: `page`, `limit`, `search`, `filter`, `sort`, `year`, `month`, `day`).
|
|
97
|
-
- `GET /_admin/api/models/:modelName/records/:id` โ Retrieve single record details (auto-loads `_inlines` if defined).
|
|
98
|
-
- `POST /_admin/api/models/:modelName/records` โ Create new record (syncs `_inlines` automatically).
|
|
99
|
-
- `PUT /_admin/api/models/:modelName/records/:id` โ Update existing record (syncs `_inlines` updates, additions, and deletions with `_delete: true`).
|
|
100
|
-
- `DELETE /_admin/api/models/:modelName/records/:id` โ Delete record (soft or hard delete).
|
|
101
|
-
- `POST /_admin/api/models/:modelName/records/:id/restore` โ Restore soft-deleted record.
|
|
102
|
-
|
|
103
|
-
### Inline Model Relational Endpoints (Django Inlines)
|
|
104
|
-
- `GET /_admin/api/models/:model/records/:id/inlines/:inlineModel` โ List child items belonging to parent record.
|
|
105
|
-
- `POST /_admin/api/models/:model/records/:id/inlines/:inlineModel` โ Create a child item attached to parent.
|
|
106
|
-
- `PUT /_admin/api/models/:model/records/:id/inlines/:inlineModel/:inlineId` โ Update specific child item.
|
|
107
|
-
- `DELETE /_admin/api/models/:model/records/:id/inlines/:inlineModel/:inlineId` โ Delete child item.
|
|
108
|
-
|
|
109
|
-
### Fast Inline & Batch Editing (Django `list_editable`)
|
|
110
|
-
- `PATCH /_admin/api/models/:model/records/:id/quick-edit` โ Quickly update allowed `listEditable` columns for a single row without full form submission.
|
|
111
|
-
- `PATCH /_admin/api/models/:model/records/batch-edit` โ Save multiple table row edits simultaneously (`{ updates: [{ id, changes }] }`).
|
|
112
|
-
|
|
113
|
-
### Date Hierarchy & Faceted Filters (Django `date_hierarchy` & `list_filter`)
|
|
114
|
-
- `GET /_admin/api/models/:model/date-hierarchy` โ Drilldown periods with counts (`?year=...&month=...`).
|
|
115
|
-
- `GET /_admin/api/models/:model/filter-facets` โ Retrieve distinct values with record counts for `listFilter` columns.
|
|
116
|
-
|
|
117
|
-
### Model Actions (Django Actions)
|
|
118
|
-
- `POST /_admin/api/models/:model/actions/:actionId` โ Execute declarative action on selected record IDs (`{ ids: [...] }`).
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## 4. Custom Pages (`registerModule` / `registerPageDir`)
|
|
124
|
-
|
|
125
|
-
Custom Admin pages support:
|
|
126
|
-
1. **Clean Mithril.js Component Files** (`componentFile` / `component`)
|
|
127
|
-
2. **Native Custom HTML Pages** (`html` / `htmlFile`) โ e.g. EUIX Engine, Vue, Alpine apps rendered directly in the DOM with full Tailwind CSS styling.
|
|
128
|
-
3. **External URL Pages** (`url` / `iframeUrl`) โ Embedded in clean `<iframe>` containers.
|
|
129
|
-
|
|
130
|
-
```js
|
|
131
|
-
const { registry } = adminPanelPlugin({ db });
|
|
132
|
-
|
|
133
|
-
// Example 1: Mithril Component
|
|
134
|
-
registry.registerModule('analytics-report', {
|
|
135
|
-
label: 'Analytics Report',
|
|
136
|
-
icon: '๐',
|
|
137
|
-
category: 'Reports',
|
|
138
|
-
componentFile: path.join(__dirname, 'admin-pages/analytics/component.js'),
|
|
139
|
-
layout: true, // Auto-wrap inside Admin layout header & sidebar (set false for full-screen view)
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// Example 2: EUIX Engine / Native HTML Page
|
|
143
|
-
registry.registerModule('euix-module', {
|
|
144
|
-
id: 'euix-module',
|
|
145
|
-
scripts: ['https://unpkg.com/euixjs@latest/dist/EUIXEngine.umd.js'],
|
|
146
|
-
pages: [
|
|
147
|
-
{
|
|
148
|
-
id: 'euix-counter',
|
|
149
|
-
title: 'EUIX Counter',
|
|
150
|
-
path: '/euix-counter',
|
|
151
|
-
htmlFile: path.join(__dirname, 'admin-pages/euix-counter.html') // Rendered directly into DOM with Tailwind & scripts
|
|
152
|
-
}
|
|
153
|
-
],
|
|
154
|
-
menu: [
|
|
155
|
-
{ id: 'euix-counter', label: 'EUIX Counter', path: '/euix-counter', icon: 'zap' }
|
|
156
|
-
]
|
|
157
|
-
});
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Automatic Directory Discovery (`registerPageDir`)
|
|
161
|
-
Directories containing page folders with `page.json` and `component.js` (or `index.html`) are auto-discovered:
|
|
162
|
-
|
|
163
|
-
```text
|
|
164
|
-
admin-pages/
|
|
165
|
-
โโโ analytics/
|
|
166
|
-
โ โโโ page.json # { "id": "analytics", "label": "Analytics", "icon": "๐", "layout": true }
|
|
167
|
-
โ โโโ component.js # clean Mithril component (export default { view() { return m('div', 'Content'); } })
|
|
168
|
-
โโโ custom-tool/
|
|
169
|
-
โโโ page.json # { "id": "custom-tool", "label": "Custom Tool", "icon": "โก" }
|
|
170
|
-
โโโ index.html # Native HTML file
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
```js
|
|
174
|
-
registry.registerPageDir(path.join(__dirname, 'admin-pages'));
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## 5. Page & Plugin Title Management
|
|
180
|
-
|
|
181
|
-
Admin Panel supports configurable base titles, title templates, and dynamic SPA page titles:
|
|
182
|
-
|
|
183
|
-
### Plugin Configuration
|
|
184
|
-
```js
|
|
185
|
-
adminPanelPlugin({
|
|
186
|
-
db,
|
|
187
|
-
title: 'Acme Admin', // Base title in <title> and header (default: 'Admin Panel')
|
|
188
|
-
titleTemplate: '%s | %b', // Format template: %s = page title, %b = base title (default: '%s | %b')
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Module & Page Title Configuration
|
|
193
|
-
When registering modules and custom pages, titles are automatically propagated to navigation and browser document title:
|
|
194
|
-
```js
|
|
195
|
-
adminApi.registerModule({
|
|
196
|
-
id: 'reports',
|
|
197
|
-
title: 'Reports & Analytics', // Module fallback title
|
|
198
|
-
pages: [
|
|
199
|
-
{
|
|
200
|
-
id: 'monthly-report',
|
|
201
|
-
title: 'Monthly Report', // Document title -> "Monthly Report | Acme Admin"
|
|
202
|
-
path: '/reports/monthly',
|
|
203
|
-
component: ...,
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
id: 'live-dashboard',
|
|
207
|
-
documentTitle: 'Live Monitor (Fullscreen)', // Raw document.title override
|
|
208
|
-
path: '/reports/live',
|
|
209
|
-
layout: false,
|
|
210
|
-
component: ...,
|
|
211
|
-
}
|
|
212
|
-
]
|
|
213
|
-
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Dynamic Client-Side Title Helper (`setAdminPageTitle`)
|
|
217
|
-
From any Mithril component or client script:
|
|
218
|
-
```js
|
|
219
|
-
// Dynamic title formatted with template (e.g. "Sales Overview | Acme Admin")
|
|
220
|
-
window.setAdminPageTitle('Sales Overview');
|
|
221
|
-
|
|
222
|
-
// Custom template override
|
|
223
|
-
window.setAdminPageTitle('Sales Overview', { template: '%s โ %b' });
|
|
224
|
-
|
|
225
|
-
// Raw document title without template
|
|
226
|
-
window.setAdminPageTitle('Sales Overview', { raw: true });
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## 6. Custom Field Renderers (`registerFieldRenderer`)
|
|
232
|
-
|
|
233
|
-
Register custom display and edit renderers for specific column types:
|
|
234
|
-
|
|
235
|
-
```js
|
|
236
|
-
registry.registerFieldRenderer('color-picker', {
|
|
237
|
-
// 1. Table & detail view display
|
|
238
|
-
display: (value) => m('span.color-badge', { style: { backgroundColor: value } }, value),
|
|
239
|
-
|
|
240
|
-
// 2. Form input editor
|
|
241
|
-
edit: (value, onChange, fieldConfig) => m('input[type=color]', {
|
|
242
|
-
value: value || '#000000',
|
|
243
|
-
oninput: (e) => onChange(e.target.value),
|
|
244
|
-
}),
|
|
245
|
-
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## 7. Dashboard Widgets (`registerWidget`)
|
|
251
|
-
|
|
252
|
-
Register dashboard widgets for the Admin overview screen:
|
|
253
|
-
|
|
254
|
-
```js
|
|
255
|
-
registry.registerWidget('recent-orders', {
|
|
256
|
-
title: 'Recent Orders',
|
|
257
|
-
width: 'half', // 'full' | 'half' | 'third'
|
|
258
|
-
componentFile: path.join(__dirname, 'widgets/recent-orders.js'),
|
|
259
|
-
});
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Built-in Dashboard Widgets
|
|
263
|
-
- **`model-stats`**: Model overview cards displaying record counts, column counts, and last update timestamps.
|
|
264
|
-
- **`database-storage`**: Database Storage & Health monitor showing:
|
|
265
|
-
- Database engine (SQLite, PostgreSQL, MySQL) & active file sizes
|
|
266
|
-
- Total tables and total record counts across the schema
|
|
267
|
-
- Storage health status badge with high-volume alerts for unpruned logs
|
|
268
|
-
- Top tables by row count with visual progress percentage bars
|
|
269
|
-
- Direct navigation links to model CRUD screens
|
|
270
|
-
- **`quick-actions`**: Fast shortcuts to create new records across enabled models.
|
|
271
|
-
- **`recent-activity`**: Timeline of recent administrative mutations (creates, updates, deletes) powered by `audit_logs` / `admin_activity_logs` with direct links to record changes.
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## 8. Single Record & Bulk Table Actions
|
|
276
|
-
|
|
277
|
-
Add custom action buttons to model table views:
|
|
278
|
-
|
|
279
|
-
```js
|
|
280
|
-
// Single record button action
|
|
281
|
-
registry.registerAction('Product', {
|
|
282
|
-
id: 'duplicate',
|
|
283
|
-
label: 'Duplicate',
|
|
284
|
-
icon: '๐',
|
|
285
|
-
handler: async (record, { request, reload }) => {
|
|
286
|
-
await request.post(`/api/products/${record.id}/duplicate`);
|
|
287
|
-
reload();
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// Record action with navigation redirect (e.g. audit-timeline)
|
|
292
|
-
registry.registerAction('Product', {
|
|
293
|
-
id: 'view-history',
|
|
294
|
-
label: 'History',
|
|
295
|
-
icon: 'clock',
|
|
296
|
-
handler: async (record, model) => {
|
|
297
|
-
return { redirect: `/_admin/audit-log?model=${model.name}&recordId=${record.id}` };
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Bulk multi-select table action
|
|
302
|
-
registry.registerBulkAction('Product', {
|
|
303
|
-
id: 'bulk-archive',
|
|
304
|
-
label: 'Archive Selected',
|
|
305
|
-
icon: '๐ฆ',
|
|
306
|
-
handler: async (selectedIds, { request, reload }) => {
|
|
307
|
-
await request.post('/api/products/bulk-archive', { ids: selectedIds });
|
|
308
|
-
reload();
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
## 9. Client Components & Custom Client Script Injections
|
|
316
|
-
|
|
317
|
-
Inject custom client-side JavaScript / Mithril components into the Admin SPA runtime:
|
|
318
|
-
|
|
319
|
-
```js
|
|
320
|
-
registry.registerClientComponent('custom-banner', `
|
|
321
|
-
window.AdminRegistry.registerWidget('custom-banner', {
|
|
322
|
-
title: 'Custom Banner',
|
|
323
|
-
view: function() {
|
|
324
|
-
return m('.banner', 'Welcome to Custom Admin!');
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
`);
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## 10. Offline & Zero-CDN Architecture
|
|
333
|
-
|
|
334
|
-
The Admin Panel is 100% self-contained and operates completely offline without external CDN dependencies (`unpkg.com`, `cdn.jsdelivr.net`, or `cdn.tailwindcss.com`):
|
|
335
|
-
- **Vendored Static Assets (`plugins/admin-panel/vendor/`)**:
|
|
336
|
-
- `mithril.min.js` โ Client SPA runtime (~28 KB).
|
|
337
|
-
- `tailwind.min.js` โ Client utility compiler & style runtime (~412 KB).
|
|
338
|
-
- `quill.min.js` & `quill.snow.min.css` โ Rich-text WYSIWYG editor.
|
|
339
|
-
- **Local Asset Serving**: Served locally at `GET /_admin/vendor/:file` with proper MIME types, path traversal protections, and `Cache-Control: public, max-age=86400` caching.
|
|
340
|
-
- **Hardened CSP**: Works in air-gapped / intranet environments with strict `'self'` Content Security Policy without leaking third-party network requests.
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
## 11. Toast Notifications, Modal Confirmations & Session Expiry UX
|
|
345
|
-
|
|
346
|
-
The Admin SPA includes a built-in reactive notification and modal system that replaces intrusive browser `alert()` and `confirm()` dialogs.
|
|
347
|
-
|
|
348
|
-
### Toast Notifications (`window.notify`)
|
|
349
|
-
Display auto-dismissing, animated toasts in the top-right corner with pause-on-hover:
|
|
350
|
-
|
|
351
|
-
```js
|
|
352
|
-
// Available on window.notify or as global helpers: notifySuccess, notifyError, notifyWarning, notifyInfo
|
|
353
|
-
notify.success('Record created successfully');
|
|
354
|
-
notify.error('Failed to save record: Validation error');
|
|
355
|
-
notify.warning('Please review unsaved changes');
|
|
356
|
-
notify.info('Export started in the background');
|
|
357
|
-
|
|
358
|
-
// Custom duration (TTL in milliseconds, default 4000ms):
|
|
359
|
-
notify.success('Saved!', 2000);
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Confirmation Modal (`window.confirmModal` / `confirmAction`)
|
|
363
|
-
Display an accessible, styled modal dialog returning a Promise resolving to `true` or `false`:
|
|
364
|
-
|
|
365
|
-
```js
|
|
366
|
-
// Destructive confirmation (danger: true highlights the confirm button in red)
|
|
367
|
-
const confirmed = await confirmAction({
|
|
368
|
-
title: 'Delete User',
|
|
369
|
-
message: 'Are you sure you want to permanently delete this user?',
|
|
370
|
-
confirmText: 'Delete',
|
|
371
|
-
cancelText: 'Cancel',
|
|
372
|
-
danger: true,
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
if (confirmed) {
|
|
376
|
-
await api.delete(`/users/${id}`);
|
|
377
|
-
notify.success('User deleted');
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### Session Expiration & Intended Return-To Redirection
|
|
382
|
-
When an authenticated staff user's session expires or an API call returns `401 Unauthorized`:
|
|
383
|
-
1. `redirectToLogin('expired')` captures the active route and redirects to `/_admin/#!/login?returnTo=<route>&reason=expired`.
|
|
384
|
-
2. The login screen displays an informational notice banner: *"Your session has expired. Please sign in again."*
|
|
385
|
-
3. After authenticating successfully, the user is automatically redirected to their intended route.
|
|
386
|
-
4. **Open-Redirect Hardening**: All return destinations are strictly validated by `isSafeIntendedRoute(path)` to disallow protocol-relative URLs (`//evil.com`), foreign protocols (`http:`, `javascript:`), or backslashes.
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## 12. Admin Login Brute-Force Protection & Rate Limiting
|
|
391
|
-
|
|
392
|
-
The Admin Panel includes built-in in-memory rate limiting to defend staff login endpoints against credential stuffing and brute-force password guessing.
|
|
393
|
-
|
|
394
|
-
### Configuration (`adminPanelPlugin`)
|
|
395
|
-
|
|
396
|
-
```js
|
|
397
|
-
import { createApp, adminPanelPlugin } from 'webspresso';
|
|
398
|
-
|
|
399
|
-
const app = createApp({
|
|
400
|
-
plugins: [
|
|
401
|
-
adminPanelPlugin({
|
|
402
|
-
db,
|
|
403
|
-
// Configure or disable login rate limiting:
|
|
404
|
-
loginRateLimit: {
|
|
405
|
-
enabled: true, // Default: true
|
|
406
|
-
maxAttempts: 5, // Max failed attempts before blocking (default: 5)
|
|
407
|
-
windowMs: 15 * 60 * 1000, // Tracking window (default: 15 minutes)
|
|
408
|
-
blockDurationMs: 15 * 60 * 1000 // Temporary block duration (default: 15 minutes)
|
|
409
|
-
},
|
|
410
|
-
}),
|
|
411
|
-
],
|
|
412
|
-
});
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
To disable rate limiting (e.g. in test or internal automated environments):
|
|
416
|
-
```js
|
|
417
|
-
adminPanelPlugin({ db, loginRateLimit: false });
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Protection Mechanics
|
|
421
|
-
- **IP Tracking**: Tracks failed attempts keyed by client IP (`req.ip` or upstream trusted proxy headers).
|
|
422
|
-
- **Automatic Block**: After `maxAttempts` failed logins within `windowMs`, returns HTTP 429 Too Many Requests with a `Retry-After: <seconds>` response header and JSON error payload.
|
|
423
|
-
- **Success Reset**: A single successful login clears the failed attempt counter for that IP.
|
|
424
|
-
- **Programmatic Reset**: Cleared automatically upon server restart or via `plugin.api.resetLoginAttempts(ip)`.
|
|
425
|
-
|
|
426
|
-
|
package/.agents/AGENTS.md
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Webspresso Project Guidelines & Rules
|
|
2
|
-
|
|
3
|
-
Webspresso is a modern, 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, zero-dependency Dual Authentication (Session + JWT), Graceful Shutdown & Force Close, HTTP Response Compression, Centralized Framework Exceptions, 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`](ROUTING.md) | `pages/api/...` |
|
|
14
|
-
| **SSR HTML Page / Layout / Loader** | [`.agents/ROUTING.md`](ROUTING.md) & [`.agents/STREAMING.md`](STREAMING.md) | `pages/*.njk`, `pages/*.js`, `views/` |
|
|
15
|
-
| **Database Model / Migration / Query** | [`.agents/ORM.md`](ORM.md) | `models/*.js`, `core/orm`, `migrations/` |
|
|
16
|
-
| **Business Logic / Transaction / Service** | [`.agents/SERVICES.md`](SERVICES.md) | `services/` |
|
|
17
|
-
| **Admin Panel (Page, Widget, Action, UI)** | [`.agents/ADMIN.md`](ADMIN.md) | `plugins/admin-panel/` |
|
|
18
|
-
| **Authentication (Session / JWT / Guard)** | [`.agents/AUTH.md`](AUTH.md) | `core/auth/` |
|
|
19
|
-
| **Background Jobs & Worker Queue** | [`.agents/QUEUE.md`](QUEUE.md) | `jobs/` |
|
|
20
|
-
| **Decoupled Events & Signals** | [`.agents/EVENTS.md`](EVENTS.md) | `core/events/`, `listeners/` |
|
|
21
|
-
| **Fault Tolerance / Circuit Breaker / Retry** | [`.agents/RESILIENCE.md`](RESILIENCE.md) | `core/resilience/` |
|
|
22
|
-
| **Stateless Scale-Out (Redis Sessions & DB Pool)** | [`.agents/SCALE_OUT.md`](SCALE_OUT.md) | `core/auth/redis-session.js`, `core/orm/pool.js` |
|
|
23
|
-
| **Cloud Secrets (GCP & AWS Secret Manager)** | [`.agents/SECRETS.md`](SECRETS.md) | `core/secrets/`, `bin/commands/secrets-pull.js` |
|
|
24
|
-
| **Cloud Metrics & Distributed Tracing** | [`.agents/METRICS.md`](METRICS.md) | `core/metrics/`, `/metrics` |
|
|
25
|
-
| **Cloud Migration Jobs (Zero-Downtime DB Deploy)** | [`.agents/MIGRATION_JOBS.md`](MIGRATION_JOBS.md) | `bin/commands/add-migration-job.js`, `core/orm/migrate-cloud.js` |
|
|
26
|
-
| **Rate Limiting Engine (Zero-Dependency & Redis)** | [`.agents/RATE_LIMIT.md`](RATE_LIMIT.md) | `core/rate-limit/` |
|
|
27
|
-
| **Feature Flags & Canary Splitter (`core/flags`)** | [`.agents/FLAGS.md`](FLAGS.md) | `core/flags/` |
|
|
28
|
-
| **Ambient Context & Composable Hooks (`core/context`)** | [`.agents/CONTEXT.md`](CONTEXT.md) | `core/context/` |
|
|
29
|
-
| **API Signatures & Types Verification** | [`index.d.ts`](../index.d.ts) | **Canonical Ground Truth** |
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## ๐ก๏ธ 4-Step Mandatory Agent Workflow Protocol
|
|
34
|
-
|
|
35
|
-
Every coding agent working on Webspresso **MUST** follow this 4-step execution discipline:
|
|
36
|
-
|
|
37
|
-
1. **Discover & Triage**: Identify the relevant topic guide above and inspect existing similar files in the workspace (e.g. `pages/api/`, `models/`, `services/`).
|
|
38
|
-
2. **Contract Adherence**: Follow the exact module contract exported by the framework (`{ schema, middleware, handler }` for routes, `defineModel` for ORM, `defineService` for services).
|
|
39
|
-
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.
|
|
40
|
-
4. **Targeted Verification**: Run the specific Vitest test file (`npx vitest run tests/...`) to confirm zero regressions before marking the task complete.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Agent Guidebook Index
|
|
45
|
-
|
|
46
|
-
This `.agents/` customization root is organized into modular topic guides:
|
|
47
|
-
|
|
48
|
-
1. **[File-Based Routing & API Routes](.agents/ROUTING.md)** โ File-based page routes (`pages/`), method-suffixed API routes (`pages/api/*.get.js`, `*.post.js`), parameter brackets (`[id]`), Zod request schemas, and the strict prohibition of manual `routes/` directories or `app.get()`.
|
|
49
|
-
2. **[Architecture & Structure](.agents/ARCHITECTURE.md)** โ File-based routing (`pages/`), Cold Start & AOT Optimizations (`discoverAppRoutes`, `lazyRoutes: true`, `routes.manifest.json`, `templates.compiled.js`, `lazyPlugin`), Asset Management & Versioning (`AssetManager`, `fsy.asset`), ORM models & `zdb` schemas (`core/orm`), Mithril.js Admin Panel SPA (`plugins/admin-panel`), and Plugin Ecosystem.
|
|
50
|
-
3. **[Services Layer](.agents/SERVICES.md)** โ File-based auto-discovery (`services/`), Zod validation, declarative `auth` & RBAC guards, automatic ACID transaction propagation (`transaction: true`), timeouts, and memoization.
|
|
51
|
-
4. **[Exceptions & Error Handling](.agents/ERRORS.md)** โ Django-inspired framework exception hierarchy (`WebspressoError`, `HttpError`, `ValidationError`, `SecurityError`, `RequestAbortedError`), central error boundary, `app.setErrorHandler()`, and production error masking.
|
|
52
|
-
5. **[Graceful Shutdown & Lifecycle](.agents/SHUTDOWN.md)** โ `ShutdownManager`, `NodeHttpAdapter`, connection draining, force close mode, and reverse-order plugin disposer cleanup.
|
|
53
|
-
6. **[HTTP Response Compression](.agents/COMPRESSION.md)** โ Native streaming zlib compression (`server.compression`), Brotli/Gzip/Deflate negotiation, threshold handling, and `res.compress(false)` route opt-out.
|
|
54
|
-
7. **[Dual Authentication System](.agents/AUTH.md)** โ Stateful Session + Cookie & Stateless HS256 JWT + Refresh Token Rotation, `req.auth` helpers, and `middleware: ['jwt']` guard integrations.
|
|
55
|
-
8. **[ORM & Database Layer](.agents/ORM.md)** โ Model definitions with `defineModel`, `zdb` schemas, `zdb` vs `z` single source of truth, Repositories API, Query Caching, Relations, Soft Delete, Scopes & Migrations.
|
|
56
|
-
9. **[Plugin Ecosystem Guide](.agents/PLUGINS.md)** โ Lifecycle hooks (`register`, `onRoutesReady`), CSP headers, and detailed reference for all 20 built-in official plugins (including `webhooksPlugin`, `apiKeyPlugin`, `xlsxPlugin`, `csvPlugin`, `fileManagerPlugin`, `realtimePlugin`, and `basicAuthPlugin`).
|
|
57
|
-
10. **[Realtime Layer & Adapters](.agents/REALTIME.md)** โ Framework-agnostic realtime layer (`core/realtime`), generic WebSocket, SSE, and Socket.IO adapters, subscription identity, backoff reconnect, and auth lifecycle.
|
|
58
|
-
11. **[Email Plugin Guide](.agents/EMAIL.md)** โ MJML template compilation, Nodemailer transport, DB delivery logs, Auth Email bridge, and Admin UI.
|
|
59
|
-
12. **[Admin Panel Customization](.agents/ADMIN.md)** โ Extending Mithril.js Admin Panel SPA (Custom pages `component.js`, custom field renderers, widgets, single & bulk actions).
|
|
60
|
-
13. **[CLI Tooling & Commands](CLI.md)** โ `webspresso dev`, `build`, `doctor`, `db:migrate`, `db:seed`, `polar:migrate`, `favicon:generate`, `add:tailwind`, `add:docker`, `add:cloudrun`, `add:aws`, `add:cloudflare`, `deploy:check`, `agents:init`.
|
|
61
|
-
14. **[Development & Testing Workflow](.agents/WORKFLOW.md)** โ CLI commands, Vitest unit/integration testing, Playwright E2E tests, TypeScript type checking, and zero regression policy.
|
|
62
|
-
15. **[Coding Standards & Conventions](.agents/CONVENTIONS.md)** โ Zero external dependencies policy, strict function signature & schema verification, clean component separation, and log traceback inspection rules.
|
|
63
|
-
16. **[Background Job Queue](.agents/QUEUE.md)** โ In-Memory, Knex Database, Distributed Redis, AWS SQS, and Google Cloud Pub/Sub queue adapters, job auto-discovery (`jobs/`), retries, and graceful draining.
|
|
64
|
-
17. **[SSR Streaming & Chunked Transfer](.agents/STREAMING.md)** โ Native HTTP chunked streaming (`res.renderStream()`), deferred data loader slots (`defer: { key: promise }`), and TTFB optimization.
|
|
65
|
-
18. **Polar billing production checklist** โ [docs/guides/polar-production-checklist.md](../docs/guides/polar-production-checklist.md) (env, webhooks, rate limits, external tier hooks, CSP). Plugin reference: [PLUGINS.md ยง polarPlugin](PLUGINS.md).
|
|
66
|
-
19. **[Decoupled Events & Signals Architecture](.agents/EVENTS.md)** โ Zero-dependency enterprise event dispatcher (`core/events`), sync/async/parallel/serial/waterfall dispatch, wildcard listeners (`order.*`), Django-style `Signal` and sender filtering, queue bridging, and listener auto-discovery.
|
|
67
|
-
20. **[HTTP 103 Early Hints](.agents/EARLY_HINTS.md)** โ Zero-dependency RFC 8288 / RFC 8297 Early Hints dispatcher (`core/early-hints`), preloading route CSS/JS and fonts before SSR loader execution, `createApp({ earlyHints })`, and `res.earlyHints(links)` / `ctx.earlyHints(links)` helpers.
|
|
68
|
-
21. **[Payload Limits & DoS Protection](.agents/LIMITS.md)** โ Zero-dependency request body limits and DoS protection (`core/limits`), `createApp({ limits })`, automatic `PayloadTooLargeError` (HTTP 413) mapping, route overrides (`limits.routes`), streaming bypass, and native HMAC webhook `req.rawBody` capture.
|
|
69
|
-
22. **[Cloud & Kubernetes Health Probes](.agents/HEALTH.md)** โ Zero-dependency RFC-compliant liveness (`/healthz`), readiness (`/readyz`), and combined diagnostic (`/health`) probes (`core/health`), event loop lag telemetry, database/queue health monitors, automatic HTTP 503 draining on graceful shutdown, and `createApp({ healthCheck: true })`.
|
|
70
|
-
23. **[LRU & Tagged Cache Engine](.agents/CACHE.md)** โ Zero-dependency, memory-bounded in-memory LRU cache (`core/cache`), byte budget constraints (`maxBytes` / `maxMemoryMb`), TTL expiration, stampede protection (`getOrSet`), leak-free tag invalidation (`TaggedLruCache`), ORM query cache provider, and `createApp({ cache })`.
|
|
71
|
-
24. **[Enterprise Resilience & Circuit Breaker](.agents/RESILIENCE.md)** โ Zero-dependency fault tolerance engine (`core/resilience`), three-state `CircuitBreaker` (`CLOSED`, `OPEN`, `HALF_OPEN`), rolling window failure rate, per-call execution timeout, fallback handlers, and exponential backoff retry engine (`retry`, `withRetry`) with randomized jitter and transient error detection.
|
|
72
|
-
25. **[Structured Cloud Logging & Distributed Tracing](.agents/LOGGING.md)** โ Zero-dependency cloud logger (`core/logger`), GCP Cloud Logging, AWS CloudWatch, automatic trace propagation (`x-cloud-trace-context`, `x-amzn-trace-id`, `traceparent`), sensitive key redaction, and `req.logger` child context.
|
|
73
|
-
26. **[Stateless Scale-Out & Database Pool Management](.agents/SCALE_OUT.md)** โ Distributed Redis session store (`createRedisSessionStore`), Redis session tracker (`createRedisSessionTracker`), zero-dependency RESP client, serverless DB connection pool optimizer (`normalizeServerlessPoolConfig`), and scale-out preflight audits (`deploy:check`).
|
|
74
|
-
27. **[Cloud Secrets Management](.agents/SECRETS.md)** โ Zero-dependency Google Cloud Secret Manager & AWS Secrets Manager/SSM integration (`core/secrets`), in-memory caching with TTL, dot-notation JSON subkeys, process.env hydration, and `webspresso secrets:pull`.
|
|
75
|
-
28. **[Cloud Metrics & Distributed Tracing](.agents/METRICS.md)** โ Zero-dependency Prometheus exposition format (`/metrics`), JSON telemetry (`/metrics.json`), HTTP latency histograms, Node.js event loop/memory/pool/cache collectors, and W3C `traceparent` & `x-trace-id` propagation (`core/metrics`).
|
|
76
|
-
29. **[Cloud Migration Jobs & Zero-Downtime Database Deploy](.agents/MIGRATION_JOBS.md)** โ Dedicated pre-deploy migration jobs for Cloud Run, AWS ECS, and Kubernetes (`webspresso add:migration-job`), connection retries, and stale lock auto-healing (`webspresso db:migrate --safe`).
|
|
77
|
-
30. **[Native Zero-Dependency Rate Limiting Engine](.agents/RATE_LIMIT.md)** โ Framework-agnostic rate limiter (`core/rate-limit`), sliding window in-memory & Redis stores, RFC 6585 standard headers (`RateLimit-*`, `Retry-After`), Express & Hono dual support, and `rateLimit({ window, limit })`.
|
|
78
|
-
31. **[Feature Flags & Canary Traffic Splitter](.agents/FLAGS.md)** โ Zero-dependency feature flag and canary rollout engine (`core/flags`), deterministic FNV-1a bucketing, targeting rules (users, roles, email domains), A/B variants, SSR template helpers (`fsy.hasFeature`), and declarative API guards (`defineApi({ flag })`).
|
|
79
|
-
32. **[Ambient Context & Composable Hooks](.agents/CONTEXT.md)** โ Zero-dependency execution context powered by `AsyncLocalStorage` (`core/context`), eliminating prop drilling across loaders, services, models, and workers with `useContext`, `useDb`, `useAuth`, `useUser`, `useService`, `useLogger`, `useReq`, `useRes`, `useParams`, `useQuery`, `useTransaction`, and `withContext`.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Essential Rules Summary
|
|
84
|
-
|
|
85
|
-
- **Strict File-Based Routing (NO `routes/` or `app.get()`)**: NEVER create a `routes/` or `src/routes/` directory. NEVER call `app.get()`, `app.post()`, or `express.Router()`. ALL application endpoints MUST be defined inside `pages/` and `pages/api/...` with HTTP method extensions (`.get.js`, `.post.js`, `.delete.js`, `.patch.js`, `.put.js`).
|
|
86
|
-
- **Strict Repository Pattern (NO Raw `db('table')`)**: NEVER write raw Knex table queries in application code. ALWAYS access database models through repositories via `db.getRepository('ModelName')` or `req.db.getRepository('ModelName')` to ensure schema validation, hooks, scopes, and query caching are applied.
|
|
87
|
-
- **Strict Services Layer (NO `controllers/`)**: NEVER create a `controllers/` folder or controller classes. Encapsulate multi-step business logic in `services/domain/action.js` and invoke via `ctx.service('domain.action', input)` to leverage automatic transaction propagation (`transaction: true`) and Zod validation.
|
|
88
|
-
- **Native Dual Auth (NO External JWT/Passport Packages)**: NEVER install `jsonwebtoken`, `passport`, or `express-session`. ALWAYS use native `req.auth` and `webspresso/core/auth` (`middleware: ['jwt']` / `middleware: ['auth']`).
|
|
89
|
-
- **Page Data Loaders (NO Manual `res.render()`)**: NEVER call `res.render()` inside custom handlers for SSR pages. Use companion loaders `pages/*.js` exporting `async function load({ req, res, db, ctx })`.
|
|
90
|
-
- **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`.
|
|
91
|
-
- **Background Jobs (NO BullMQ / `setTimeout`)**: NEVER use unmanaged `setTimeout` or external queues. Place job workers in `jobs/` and dispatch via `req.queue.dispatch()`.
|
|
92
|
-
- **Zero External Dependencies**: Core framework functions (Auth, JWT, CORS, Routing, Errors, Compression, Shutdown, Nunjucks helpers) must rely strictly on native Node.js modules (`crypto`, `path`, `fs`, `events`, `zlib`, `async_hooks`).
|
|
93
|
-
- **Zero Regression Policy**: Always run Vitest tests (`npm test` or `npx vitest run`) before declaring any task complete.
|
|
94
|
-
- **Strict Verification**: Inspect authoritative source files for function signatures and schema definitions before writing consuming code.
|
|
95
|
-
- **Log & Traceback Inspection**: Base all bug fixes strictly on exact runtime error log tracebacks and empirical test output.
|
|
96
|
-
- **`zdb` vs `z` Single Source of Truth (NO `schema: z.object` in Models)**: NEVER wrap model schemas in `z.object({...})`. Pass a clean plain object `schema: { ... }` or functional schema `schema: ({ zdb, z }) => ({ ... })`. ALWAYS use `zdb.*` for persistent database columns in `models/*.js` (`zdb.id()`, `zdb.string()`, `zdb.integer()`, `zdb.email()`, etc.) to generate migrations, query filters, and Admin UI controls. Use pure `z.*` ONLY for in-memory request/service payloads (`pages/api/...`, `services/...`). Access raw Zod primitives in models via `zdb.z` without importing `zod`.
|