webspresso 0.0.96 → 0.0.98

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 (121) hide show
  1. package/.agents/ADMIN.md +153 -5
  2. package/.agents/ARCHITECTURE.md +10 -0
  3. package/.agents/CLI.md +195 -1
  4. package/.agents/PLUGINS.md +153 -9
  5. package/.agents/QUEUE.md +43 -0
  6. package/.agents/skills/webspresso-admin-and-plugins/SKILL.md +122 -0
  7. package/.agents/skills/webspresso-framework/SKILL.md +56 -0
  8. package/.agents/skills/webspresso-orm-and-database/SKILL.md +119 -0
  9. package/.agents/skills/webspresso-routing-and-api/SKILL.md +114 -0
  10. package/.agents/skills/webspresso-services/SKILL.md +101 -0
  11. package/bin/commands/add-esbuild.js +80 -0
  12. package/bin/commands/add-tailwind.js +76 -31
  13. package/bin/commands/admin-password.js +2 -1
  14. package/bin/commands/admin-setup.js +1 -1
  15. package/bin/commands/agents-init.js +51 -11
  16. package/bin/commands/analytics-prune.js +57 -0
  17. package/bin/commands/api.js +207 -15
  18. package/bin/commands/audit-prune.js +1 -1
  19. package/bin/commands/build.js +99 -0
  20. package/bin/commands/dev.js +64 -35
  21. package/bin/commands/doctor.js +26 -0
  22. package/bin/commands/email-prune.js +47 -0
  23. package/bin/commands/favicon-generate.js +1 -1
  24. package/bin/commands/make-job.js +86 -0
  25. package/bin/commands/make-model.js +250 -0
  26. package/bin/commands/new.js +45 -28
  27. package/bin/commands/openapi.js +102 -0
  28. package/bin/commands/orm-map.js +5 -4
  29. package/bin/commands/page.js +6 -3
  30. package/bin/commands/polar-migrate.js +1 -1
  31. package/bin/commands/queue-prune.js +59 -0
  32. package/bin/commands/routes.js +52 -0
  33. package/bin/commands/seed.js +1 -1
  34. package/bin/commands/service.js +6 -3
  35. package/bin/commands/typegen.js +106 -0
  36. package/bin/commands/upload-prune.js +79 -0
  37. package/bin/webspresso.js +22 -0
  38. package/core/applySchema.js +13 -6
  39. package/core/auth/hash.js +31 -17
  40. package/core/compression/middleware.js +23 -17
  41. package/core/openapi/build-from-api-routes.js +160 -29
  42. package/core/orm/cache/fingerprint.js +15 -1
  43. package/core/orm/cache/memory-provider.js +27 -2
  44. package/core/orm/index.js +12 -7
  45. package/core/orm/model.js +49 -7
  46. package/core/queue/adapters/database.js +94 -0
  47. package/core/queue/adapters/memory.js +62 -0
  48. package/core/queue/adapters/redis.js +80 -0
  49. package/core/queue/manager.js +123 -0
  50. package/core/ssr/stream.js +11 -0
  51. package/index.d.ts +660 -10
  52. package/index.js +44 -96
  53. package/package.json +32 -12
  54. package/plugins/admin-panel/api.js +279 -17
  55. package/plugins/admin-panel/app.js +124 -31
  56. package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +314 -9
  57. package/plugins/admin-panel/client/parts/04-field-renderers.js +264 -67
  58. package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +10 -5
  59. package/plugins/admin-panel/client/parts/06-login-setup-forms.js +119 -28
  60. package/plugins/admin-panel/client/parts/07-model-list.js +49 -8
  61. package/plugins/admin-panel/client/parts/08-record-list.js +243 -23
  62. package/plugins/admin-panel/client/parts/09-record-form.js +59 -12
  63. package/plugins/admin-panel/client/parts/10-export-registry.js +23 -0
  64. package/plugins/admin-panel/core/admin-module.js +13 -7
  65. package/plugins/admin-panel/core/api-extensions.js +34 -2
  66. package/plugins/admin-panel/core/registry.js +96 -16
  67. package/plugins/admin-panel/index.js +96 -0
  68. package/plugins/admin-panel/lib/login-rate-limiter.js +119 -0
  69. package/plugins/admin-panel/modules/admin-users.js +16 -1
  70. package/plugins/admin-panel/modules/bulk-actions.js +13 -5
  71. package/plugins/admin-panel/modules/custom-pages.js +492 -3
  72. package/plugins/admin-panel/modules/dashboard.js +283 -0
  73. package/plugins/admin-panel/modules/menu.js +56 -18
  74. package/plugins/admin-panel/modules/user-management.js +24 -6
  75. package/plugins/audit-log/admin-component.js +11 -0
  76. package/plugins/audit-log/api-handlers.js +34 -0
  77. package/plugins/audit-log/index.js +129 -3
  78. package/plugins/audit-log/purge.js +60 -10
  79. package/plugins/basic-auth/index.js +3 -1
  80. package/plugins/content/client/inline-edit.js +12 -12
  81. package/plugins/cors.js +6 -7
  82. package/plugins/dashboard/app.js +152 -27
  83. package/plugins/dashboard/index.js +143 -39
  84. package/plugins/dashboard/styles.js +78 -0
  85. package/plugins/data-exchange/export-xlsx.js +9 -2
  86. package/plugins/data-exchange/import.js +9 -2
  87. package/plugins/data-exchange/index.js +6 -3
  88. package/plugins/email/index.js +132 -2
  89. package/plugins/email/purge.js +60 -10
  90. package/plugins/file-manager/core.js +1 -1
  91. package/plugins/file-manager/security.js +33 -23
  92. package/plugins/index.js +49 -87
  93. package/plugins/mcp/transports/sse.js +4 -2
  94. package/plugins/orm-cache-admin/index.js +4 -2
  95. package/plugins/queue/index.js +11 -0
  96. package/plugins/schema-explorer/admin-component.js +714 -0
  97. package/plugins/schema-explorer/relations-graph.js +205 -0
  98. package/plugins/schema-explorer.js +248 -69
  99. package/plugins/site-analytics/admin-component.js +30 -8
  100. package/plugins/site-analytics/api-handlers.js +42 -0
  101. package/plugins/site-analytics/index.js +147 -2
  102. package/plugins/site-analytics/purge.js +168 -0
  103. package/plugins/swagger.js +261 -13
  104. package/plugins/upload/index.js +26 -0
  105. package/plugins/upload/orphan-pruner.js +292 -0
  106. package/src/api/api-loader.js +3 -1
  107. package/src/bundle/index.js +517 -0
  108. package/src/bundle/manifest.js +165 -0
  109. package/src/dev/banner.js +296 -0
  110. package/src/dev/colors.js +70 -0
  111. package/src/dev/index.js +62 -0
  112. package/src/dev/profiler.js +354 -0
  113. package/src/dev/typegen.js +497 -0
  114. package/src/dev-reload/index.js +611 -0
  115. package/src/file-router.js +213 -63
  116. package/src/helpers.js +958 -98
  117. package/src/njk-frontmatter.js +12 -0
  118. package/src/pages/page-loader.js +61 -11
  119. package/src/server.js +629 -63
  120. package/src/services/discovery.js +6 -1
  121. package/src/services/index.js +6 -13
package/.agents/ADMIN.md CHANGED
@@ -133,7 +133,59 @@ registry.registerPageDir(path.join(__dirname, 'admin-pages'));
133
133
 
134
134
  ---
135
135
 
136
- ## 5. Custom Field Renderers (`registerFieldRenderer`)
136
+ ## 5. Page & Plugin Title Management
137
+
138
+ Admin Panel supports configurable base titles, title templates, and dynamic SPA page titles:
139
+
140
+ ### Plugin Configuration
141
+ ```js
142
+ adminPanelPlugin({
143
+ db,
144
+ title: 'Acme Admin', // Base title in <title> and header (default: 'Admin Panel')
145
+ titleTemplate: '%s | %b', // Format template: %s = page title, %b = base title (default: '%s | %b')
146
+ });
147
+ ```
148
+
149
+ ### Module & Page Title Configuration
150
+ When registering modules and custom pages, titles are automatically propagated to navigation and browser document title:
151
+ ```js
152
+ adminApi.registerModule({
153
+ id: 'reports',
154
+ title: 'Reports & Analytics', // Module fallback title
155
+ pages: [
156
+ {
157
+ id: 'monthly-report',
158
+ title: 'Monthly Report', // Document title -> "Monthly Report | Acme Admin"
159
+ path: '/reports/monthly',
160
+ component: ...,
161
+ },
162
+ {
163
+ id: 'live-dashboard',
164
+ documentTitle: 'Live Monitor (Fullscreen)', // Raw document.title override
165
+ path: '/reports/live',
166
+ layout: false,
167
+ component: ...,
168
+ }
169
+ ]
170
+ });
171
+ ```
172
+
173
+ ### Dynamic Client-Side Title Helper (`setAdminPageTitle`)
174
+ From any Mithril component or client script:
175
+ ```js
176
+ // Dynamic title formatted with template (e.g. "Sales Overview | Acme Admin")
177
+ window.setAdminPageTitle('Sales Overview');
178
+
179
+ // Custom template override
180
+ window.setAdminPageTitle('Sales Overview', { template: '%s — %b' });
181
+
182
+ // Raw document title without template
183
+ window.setAdminPageTitle('Sales Overview', { raw: true });
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 6. Custom Field Renderers (`registerFieldRenderer`)
137
189
 
138
190
  Register custom display and edit renderers for specific column types:
139
191
 
@@ -152,7 +204,7 @@ registry.registerFieldRenderer('color-picker', {
152
204
 
153
205
  ---
154
206
 
155
- ## 6. Dashboard Widgets (`registerWidget`)
207
+ ## 7. Dashboard Widgets (`registerWidget`)
156
208
 
157
209
  Register dashboard widgets for the Admin overview screen:
158
210
 
@@ -164,9 +216,20 @@ registry.registerWidget('recent-orders', {
164
216
  });
165
217
  ```
166
218
 
219
+ ### Built-in Dashboard Widgets
220
+ - **`model-stats`**: Model overview cards displaying record counts, column counts, and last update timestamps.
221
+ - **`database-storage`**: Database Storage & Health monitor showing:
222
+ - Database engine (SQLite, PostgreSQL, MySQL) & active file sizes
223
+ - Total tables and total record counts across the schema
224
+ - Storage health status badge with high-volume alerts for unpruned logs
225
+ - Top tables by row count with visual progress percentage bars
226
+ - Direct navigation links to model CRUD screens
227
+ - **`quick-actions`**: Fast shortcuts to create new records across enabled models.
228
+ - **`recent-activity`**: Timeline of recent administrative mutations (creates, updates, deletes).
229
+
167
230
  ---
168
231
 
169
- ## 7. Single Record & Bulk Table Actions
232
+ ## 8. Single Record & Bulk Table Actions
170
233
 
171
234
  Add custom action buttons to model table views:
172
235
 
@@ -196,7 +259,7 @@ registry.registerBulkAction('Product', {
196
259
 
197
260
  ---
198
261
 
199
- ## 8. Client Components & Custom Client Script Injections
262
+ ## 9. Client Components & Custom Client Script Injections
200
263
 
201
264
  Inject custom client-side JavaScript / Mithril components into the Admin SPA runtime:
202
265
 
@@ -213,7 +276,7 @@ registry.registerClientComponent('custom-banner', `
213
276
 
214
277
  ---
215
278
 
216
- ## 9. Offline & Zero-CDN Architecture
279
+ ## 10. Offline & Zero-CDN Architecture
217
280
 
218
281
  The Admin Panel is 100% self-contained and operates completely offline without external CDN dependencies (`unpkg.com`, `cdn.jsdelivr.net`, or `cdn.tailwindcss.com`):
219
282
  - **Vendored Static Assets (`plugins/admin-panel/vendor/`)**:
@@ -223,3 +286,88 @@ The Admin Panel is 100% self-contained and operates completely offline without e
223
286
  - **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.
224
287
  - **Hardened CSP**: Works in air-gapped / intranet environments with strict `'self'` Content Security Policy without leaking third-party network requests.
225
288
 
289
+ ---
290
+
291
+ ## 11. Toast Notifications, Modal Confirmations & Session Expiry UX
292
+
293
+ The Admin SPA includes a built-in reactive notification and modal system that replaces intrusive browser `alert()` and `confirm()` dialogs.
294
+
295
+ ### Toast Notifications (`window.notify`)
296
+ Display auto-dismissing, animated toasts in the top-right corner with pause-on-hover:
297
+
298
+ ```js
299
+ // Available on window.notify or as global helpers: notifySuccess, notifyError, notifyWarning, notifyInfo
300
+ notify.success('Record created successfully');
301
+ notify.error('Failed to save record: Validation error');
302
+ notify.warning('Please review unsaved changes');
303
+ notify.info('Export started in the background');
304
+
305
+ // Custom duration (TTL in milliseconds, default 4000ms):
306
+ notify.success('Saved!', 2000);
307
+ ```
308
+
309
+ ### Confirmation Modal (`window.confirmModal` / `confirmAction`)
310
+ Display an accessible, styled modal dialog returning a Promise resolving to `true` or `false`:
311
+
312
+ ```js
313
+ // Destructive confirmation (danger: true highlights the confirm button in red)
314
+ const confirmed = await confirmAction({
315
+ title: 'Delete User',
316
+ message: 'Are you sure you want to permanently delete this user?',
317
+ confirmText: 'Delete',
318
+ cancelText: 'Cancel',
319
+ danger: true,
320
+ });
321
+
322
+ if (confirmed) {
323
+ await api.delete(`/users/${id}`);
324
+ notify.success('User deleted');
325
+ }
326
+ ```
327
+
328
+ ### Session Expiration & Intended Return-To Redirection
329
+ When an authenticated staff user's session expires or an API call returns `401 Unauthorized`:
330
+ 1. `redirectToLogin('expired')` captures the active route and redirects to `/_admin/#!/login?returnTo=<route>&reason=expired`.
331
+ 2. The login screen displays an informational notice banner: *"Your session has expired. Please sign in again."*
332
+ 3. After authenticating successfully, the user is automatically redirected to their intended route.
333
+ 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.
334
+
335
+ ---
336
+
337
+ ## 12. Admin Login Brute-Force Protection & Rate Limiting
338
+
339
+ The Admin Panel includes built-in in-memory rate limiting to defend staff login endpoints against credential stuffing and brute-force password guessing.
340
+
341
+ ### Configuration (`adminPanelPlugin`)
342
+
343
+ ```js
344
+ import { createApp, adminPanelPlugin } from 'webspresso';
345
+
346
+ const app = createApp({
347
+ plugins: [
348
+ adminPanelPlugin({
349
+ db,
350
+ // Configure or disable login rate limiting:
351
+ loginRateLimit: {
352
+ enabled: true, // Default: true
353
+ maxAttempts: 5, // Max failed attempts before blocking (default: 5)
354
+ windowMs: 15 * 60 * 1000, // Tracking window (default: 15 minutes)
355
+ blockDurationMs: 15 * 60 * 1000 // Temporary block duration (default: 15 minutes)
356
+ },
357
+ }),
358
+ ],
359
+ });
360
+ ```
361
+
362
+ To disable rate limiting (e.g. in test or internal automated environments):
363
+ ```js
364
+ adminPanelPlugin({ db, loginRateLimit: false });
365
+ ```
366
+
367
+ ### Protection Mechanics
368
+ - **IP Tracking**: Tracks failed attempts keyed by client IP (`req.ip` or upstream trusted proxy headers).
369
+ - **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.
370
+ - **Success Reset**: A single successful login clears the failed attempt counter for that IP.
371
+ - **Programmatic Reset**: Cleared automatically upon server restart or via `plugin.api.resetLoginAttempts(ip)`.
372
+
373
+
@@ -116,4 +116,14 @@ Plugins expose `name`, `version`, `dependencies`, and lifecycle hooks (`register
116
116
  | `xlsxPlugin` | Excel / Export | Excel spreadsheet generation, parsing, ORM streaming export (`res.xlsx`), and services |
117
117
  | `csvPlugin` | CSV / Export | RFC 4180 CSV generator, parser, Excel UTF-8 BOM, streaming writer (`res.csv`), and services |
118
118
 
119
+ ---
120
+
121
+ ## 5. Developer Experience & Live/Hot Reload (`src/dev-reload/`)
122
+
123
+ - **Zero-Dependency SSE Reload Hub**: Enabled via `createApp({ devReload: true })` (or `devReload: { watchTemplates: true, watchCss: true, debounce: 50 }`).
124
+ - **Instant CSS Hot Swap**: Modifying `.css` files dynamically refreshes all `<link rel="stylesheet">` elements without page refresh or DOM state loss.
125
+ - **Template & Layout Live Reload**: Modifying Nunjucks templates (`.njk`, `.html`) in `views/` or pages in `pages/` automatically invalidates frontmatter/loader caches and broadcasts a debounced `'full'` reload event to active browser tabs.
126
+ - **Error Overlay Frame**: Client runtime script automatically renders terminal-free in-browser error frames for compile/build errors with line numbers and dismiss keyboard shortcuts (`Esc`).
127
+ - **DevTools Toolbar & Dashboard**: Embedded via `fsy.devToolbar()` and available at `/_webspresso` for interactive inspection of routes, models, services, cache, and profiler metrics.
128
+
119
129
 
package/.agents/CLI.md CHANGED
@@ -13,8 +13,12 @@ npx webspresso dev
13
13
  # --port, -p <number> (default: 3001)
14
14
  # --host <string> (default: localhost)
15
15
 
16
- # Build production bundle / verify assets
16
+ # Build production bundle / compile assets (Tailwind + esbuild with manifest.json)
17
17
  npx webspresso build
18
+ # Flags:
19
+ # --no-css (skip CSS build)
20
+ # --no-js (skip JS bundle build)
21
+ # --no-hash (disable content hashing in filenames)
18
22
  ```
19
23
 
20
24
  ---
@@ -113,3 +117,193 @@ npx webspresso agents:init
113
117
  npx webspresso agents:init --force
114
118
  ```
115
119
 
120
+ ---
121
+
122
+ ## 8. Tailwind CSS Setup & Migration (`add:tailwind`)
123
+
124
+ Add or upgrade Tailwind CSS in a project:
125
+
126
+ ```bash
127
+ # Add Tailwind CSS v4 (Oxide engine, LightningCSS, zero-config)
128
+ npx webspresso add tailwind --v4
129
+
130
+ # Add Tailwind CSS v3 (legacy PostCSS engine)
131
+ npx webspresso add tailwind --v3
132
+
133
+ # Upgrade existing Tailwind v3 project to v4
134
+ npx webspresso add tailwind --upgrade
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 9. Client Bundler Setup (`add:esbuild`)
140
+
141
+ Add client-side JS/TS bundling with esbuild incremental watching:
142
+
143
+ ```bash
144
+ # Scaffold esbuild client bundler setup
145
+ npx webspresso add esbuild
146
+ # or
147
+ npx webspresso add:esbuild
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 10. Data Retention & Storage Cleanup Commands
153
+
154
+ Keep databases and storage clean by pruning historical records and unreferenced files:
155
+
156
+ ```bash
157
+ # Delete audit log entries older than N days (default: 90)
158
+ npx webspresso audit:prune --days 90
159
+
160
+ # Delete email delivery logs older than N days (default: 90)
161
+ npx webspresso email:prune --days 90
162
+
163
+ # Delete completed/failed background jobs older than N days (default: 30)
164
+ npx webspresso queue:prune --days 30
165
+
166
+ # Delete expired site analytics visits & JS errors older than N days
167
+ npx webspresso analytics:prune --days 90
168
+
169
+ # Scan and delete orphaned uploads not referenced by any database model
170
+ npx webspresso upload:prune
171
+
172
+ # Dry run mode (inspect orphaned files without deleting)
173
+ npx webspresso upload:prune --dry-run
174
+ ```
175
+
176
+ ---
177
+
178
+ ## 11. Routes Introspection (`routes`)
179
+
180
+ List and inspect all compiled file-based and API routes in terminal:
181
+
182
+ ```bash
183
+ # List all application routes in a colorized table
184
+ npx webspresso routes
185
+
186
+ # Filter to only API endpoints
187
+ npx webspresso routes --api
188
+
189
+ # Filter to only SSR page routes
190
+ npx webspresso routes --pages
191
+
192
+ # Output routes as machine-readable JSON
193
+ npx webspresso routes --json
194
+ ```
195
+
196
+ ---
197
+
198
+ ## 12. Dev Server DX & Query Profiler
199
+
200
+ When starting in development mode (`isDev: true` / `process.env.NODE_ENV !== 'production'`), Webspresso automatically:
201
+
202
+ - **Displays Startup Banner**: ASCII box with Node/Framework version, Local & Admin URLs, Database dialect, and counts of routes, models, services, and plugins.
203
+ - **Request Profiler & Logger**: Color-coded HTTP requests with status, response duration, and database metrics:
204
+ ```text
205
+ [GET 200] /api/notes — 14.2ms | 2 DB queries (2.8ms)
206
+ ```
207
+ - **N+1 Query Detection**: Flags queries executing repeatedly against the same table within a single request:
208
+ ```text
209
+ ⚠️ [webspresso:n+1] Potential N+1 query pattern detected on table 'users' (5 queries, 6.4ms). Consider eager loading with repo.query().include('users') or batching.
210
+ ```
211
+ - **Configuration (`dev` options in `createApp`)**:
212
+ ```javascript
213
+ createApp({
214
+ dev: {
215
+ banner: true, // show startup banner (default: true in dev)
216
+ routeTable: true, // show route table in banner (default: true)
217
+ profiler: true, // enable request & DB profiler (default: true)
218
+ nPlusOne: true, // detect N+1 queries (default: true)
219
+ nPlusOneThreshold: 4,// query count threshold for warning (default: 4)
220
+ slowQueryMs: 50, // flag queries slower than N ms (default: 50)
221
+ verbose: false, // log individual SQL statements
222
+ }
223
+ });
224
+ ```
225
+
226
+ ---
227
+
228
+ ## 13. Scaffolding & Code Generation (`make:*` Commands)
229
+
230
+ Quickly generate boilerplate adhering strictly to Webspresso contracts:
231
+
232
+ ```bash
233
+ # 1. Scaffold an ORM Model in models/<Name>.js with parsed zdb fields and Knex migration
234
+ npx webspresso make:model Post --fields title:string,content:text,published:boolean,views:integer --migration
235
+ # Flags:
236
+ # --fields <list> (title:string,content:text,views:integer,price:number,published:boolean,authorId:id)
237
+ # --table <name> (custom table name; defaults to pluralized lowercase)
238
+ # --migration, -m (auto-generate timestamped Knex migration in migrations/)
239
+ # --soft-deletes (include deletedAt column and default scope)
240
+
241
+ # 2. Scaffold API Endpoints in pages/api/
242
+ # Single endpoint with Zod validation and handler:
243
+ npx webspresso make:api notes/export --method POST --auth
244
+
245
+ # Full REST CRUD Suite (list, create, detail, update, delete) in pages/api/posts:
246
+ npx webspresso make:api posts --crud --model Post
247
+
248
+ # 3. Scaffold an SSR Page in pages/
249
+ npx webspresso make:page blog/[slug]
250
+ # Generates pages/blog/[slug].njk template + companion loader pages/blog/[slug].js
251
+
252
+ # 4. Scaffold a Service in services/<domain>/<action>.js
253
+ npx webspresso make:service order.process --transaction --auth admin
254
+
255
+ # 5. Scaffold a Background Queue Worker in jobs/<name>.js
256
+ npx webspresso make:job send-welcome-email --queue default --retries 3
257
+ ```
258
+
259
+ ---
260
+
261
+ ## 14. OpenAPI & API Documentation Export (`openapi` / `api:docs`)
262
+
263
+ Generate and export standard OpenAPI 3.0 JSON specification from file-based API routes and Zod schemas:
264
+
265
+ ```bash
266
+ # Print OpenAPI 3.0 specification to stdout
267
+ npx webspresso openapi
268
+
269
+ # Export directly to a JSON file
270
+ npx webspresso openapi --out openapi.json
271
+
272
+ # Export with custom title, version, and server URL
273
+ npx webspresso api:docs --out public/openapi.json --title "My API" --api-version "2.0.0" --server "https://api.myapp.com"
274
+
275
+ # Include ORM model schemas in components.schemas
276
+ npx webspresso openapi --out openapi.json --include-orm
277
+ ```
278
+
279
+ ---
280
+
281
+ ## 15. TypeScript Definitions & IDE Auto-Complete Generator (`typegen` / `types`)
282
+
283
+ Scan ORM models, business services, and routes to automatically generate typed TypeScript declaration files (`.webspresso/types.d.ts` and `webspresso-env.d.ts`) with module augmentation:
284
+
285
+ ```bash
286
+ # Generate TypeScript definitions
287
+ npx webspresso typegen
288
+
289
+ # Aliases
290
+ npx webspresso types
291
+ npx webspresso generate:types
292
+
293
+ # Watch mode (automatically regenerates on model/service/page edits)
294
+ npx webspresso typegen --watch
295
+
296
+ # Custom output destination
297
+ npx webspresso typegen --out types/webspresso.d.ts --no-env-file
298
+ ```
299
+
300
+ ### Generated Capabilities & IDE DX:
301
+ - **Typed Models (`db.getRepository('Model')`)**: Auto-completes model names and infers entity column types from Zod schemas.
302
+ - **Typed Services (`req.service('name', input)`)**: Auto-completes registered service names and enforces validated input payloads.
303
+ - **Typed Route Table (`AppRoute`, `AppRoutePath`)**: Union types for all discovered SSR and API routes.
304
+
305
+
306
+
307
+
308
+
309
+
@@ -91,6 +91,8 @@ Schema-driven headless CMS & inline content editing.
91
91
  Multipart file upload manager with local / cloud storage providers.
92
92
  - **Options**: `{ path: '/api/upload', local: { destDir, publicBasePath }, maxBytes: 10000000, mimeAllowlist: ['image/png', 'image/jpeg'] }`
93
93
  - **Features**: Single & multi-file uploads, file size & extension validation, storage drivers.
94
+ - **Orphan Pruning**: `scanOrphanedUploads({ db, destDir })` and `pruneOrphanedUploads({ db, destDir, dryRun })` to detect and remove disk files no longer referenced by any database model, accompanied by CLI command `webspresso upload:prune [--dry-run]`.
95
+
94
96
 
95
97
  ### 2.5 `fileManagerPlugin` (`plugins/file-manager`)
96
98
  Filesystem-first media library, directory explorer, and modal asset picker for Admin Panel.
@@ -122,12 +124,49 @@ Request rate limiting using express-rate-limit logic.
122
124
  - **Options**: `{ windowMs: 15 * 60 * 1000, max: 100 }`
123
125
 
124
126
  ### 2.9 `siteAnalyticsPlugin` (`plugins/site-analytics`)
125
- Self-hosted privacy-focused page view analytics and client error tracking.
126
- - **Options**: `{ path: '/_analytics', db }`
127
+ Self-hosted privacy-focused page view analytics, client error tracking, and automated retention cleanup.
128
+ - **Options**:
129
+ - `db`: Knex database instance.
130
+ - `tableName`: Table name for page views (default: `'analytics_page_views'`).
131
+ - `errorsTableName`: Table name for client errors (default: `'analytics_client_errors'`).
132
+ - `retentionDays`: Page views retention window in days (default: `90`).
133
+ - `errorRetentionDays`: Client error logs retention window in days (default: `30`).
134
+ - `cleanupIntervalMs`: Background scheduled cleanup interval in milliseconds (default: `86400000` / 24 hours).
135
+ - `autoCleanup`: Enable automated periodic background cleanup (default: `true`).
136
+ - `cleanupOnStart`: Run an initial non-blocking cleanup shortly after startup (default: `true`).
137
+ - `retention`: Shorthand object `{ enabled, days, errorDays, intervalMs, runOnStart }` or `false` to disable retention cleanup.
138
+ - `excludePaths`, `excludeBots`, `customBots`, `anonymizeIp`, `trustProxy`, `collectErrors`, `dashboard`.
139
+ - **Programmatic API (`plugin.api`)**:
140
+ - `purge({ days, errorDays, olderThan, errorsOlderThan })`: Manual purge of page views and error logs.
141
+ - `purgeAnalyticsData(knex, options)`: Standalone query purge helper.
142
+ - `startCleanup(intervalMs)` / `stopCleanup()`: Control background cleanup lifecycle.
143
+ - `getRetentionConfig()`: Inspect active retention configuration.
144
+ - **Admin REST Endpoint**: `POST /_admin/api/analytics/purge` (accepts `{ days, errorDays }`).
145
+ - **Admin UI**: "Purge Old Data" button with confirmation prompt in the Analytics admin dashboard header.
146
+ - **CLI Command**:
147
+ ```bash
148
+ webspresso analytics:prune --days 90 --error-days 30
149
+ ```
150
+ - **Lifecycle Integration**: Background timer uses `.unref()` to avoid keeping Node event loop open, and registers a framework disposer to clear timers on shutdown.
127
151
 
128
152
  ### 2.10 `emailPlugin` (`plugins/email`)
129
- Transactional email compiler (MJML) & Nodemailer transport integration.
130
- - **Options**: `{ transport, from: 'noreply@example.com', templatesDir }`
153
+ Transactional email compiler (MJML) & Nodemailer transport integration with database delivery logging and auto-retention cleanup.
154
+ - **Options**:
155
+ - `transport` / `smtp`: Nodemailer transport or SMTP settings.
156
+ - `defaults`: Default sender/reply-to address.
157
+ - `templatesDir`: Directory containing `.mjml` templates.
158
+ - `logToDb`: Store delivery history in database (default `true` when `db` is supplied).
159
+ - `tableName`: Database table name (default `'email_logs'`).
160
+ - `retentionDays`: Days to retain email logs (default `90`).
161
+ - `cleanupIntervalMs`: Background cleanup timer frequency (default 24h).
162
+ - `autoCleanup`: Enable scheduled background purge (default `true`).
163
+ - `cleanupOnStart`: Run initial purge shortly after boot (default `true`).
164
+ - `retention`: `{ enabled, days: 90, intervalMs: 86400000, runOnStart: true }` (or `false` to disable).
165
+ - **Pruning CLI**:
166
+ ```bash
167
+ webspresso email:prune --days 90
168
+ ```
169
+ - **Admin Panel UI**: Includes log listing, test email dispatch, template preview, connection verification, and "Purge 90d" action.
131
170
 
132
171
  ### 2.11 `polarPlugin` (`plugins/polar`)
133
172
  Polar.sh subscription billing — checkout, customer portal, webhooks, Customer State sync, tier columns. Zero extra deps (`crypto` + `fetch`).
@@ -178,17 +217,86 @@ Polar.sh subscription billing — checkout, customer portal, webhooks, Customer
178
217
  - [docs/guides/polar-production-checklist.md](../docs/guides/polar-production-checklist.md)
179
218
 
180
219
  ### 2.12 `auditLogPlugin` (`plugins/audit-log`)
181
- Admin mutation tracking and audit log audit history.
182
- - **Options**: `{ db, retainDays: 90 }`
220
+ Admin mutation tracking and audit history with scheduled retention and manual purge API.
221
+ - **Options**:
222
+ - `db`: Database instance (must expose `.knex`).
223
+ - `tableName`: Database table name (default `'audit_logs'`).
224
+ - `retentionDays`: Days to retain audit trail entries (default `90`).
225
+ - `cleanupIntervalMs`: Background cleanup timer frequency (default 24h).
226
+ - `autoCleanup`: Enable scheduled background purge (default `true`).
227
+ - `cleanupOnStart`: Run initial purge shortly after boot (default `true`).
228
+ - `retention`: `{ enabled, days: 90, intervalMs: 86400000, runOnStart: true }` (or `false` to disable).
229
+ - **Pruning CLI**:
230
+ ```bash
231
+ webspresso audit:prune --days 90
232
+ ```
233
+ - **API & Admin Panel**:
234
+ - `POST /_admin/api/audit-logs/purge`: `{ days: 90 }` or `{ olderThan: '2026-01-01' }`
235
+ - "Purge 90d" button directly in the Admin Panel audit log viewer.
236
+ - Lifecycle integration: background timers use `.unref()` and clean up on server shutdown.
183
237
 
184
238
  ### 2.13 `ormCacheAdminPlugin` (`plugins/orm-cache-admin`)
185
239
  ORM Cache inspection and invalidation dashboard.
186
240
 
187
241
  ### 2.14 `schemaExplorerPlugin` (`plugins/schema-explorer`)
188
- Interactive JSON schema & OpenAPI route specification generator.
242
+ Interactive Database Schema & ER Diagram Explorer for both raw JSON/OpenAPI endpoints and Admin Panel SPA.
243
+ - **Admin Panel Page (`/_admin/schema`)**:
244
+ - Interactive Table & Column details (Primary Keys, Foreign Keys, Nullability, Types, Constraints, Scopes).
245
+ - Visual Relationship Map (ER Diagram) with bidirectional incoming & outgoing relation links.
246
+ - Interactive table cards highlighting connected models and key mappings (`posts.author_id ➔ authors.id`).
247
+ - One-click Mermaid.js ER diagram code generation and copy.
248
+ - JSON schema export.
249
+ - **Options**:
250
+ - `admin: true` — Automatically registers into `adminPanelPlugin` when present.
251
+ - `adminPath: '/schema'` — Custom path inside Admin Panel.
252
+ - `menuLabel: 'Schema Explorer'` — Sidebar menu label.
253
+ - `menuIcon: 'database'` — Sidebar icon.
254
+ - `path: '/_schema'` — Raw JSON endpoint path.
255
+ - `exclude: ['SecretModel']` — Models to exclude.
256
+ - **Usage**:
257
+ ```js
258
+ const { createApp } = require('webspresso');
259
+ const { adminPanelPlugin, schemaExplorerPlugin } = require('webspresso/plugins');
260
+
261
+ const { app } = createApp({
262
+ plugins: [
263
+ adminPanelPlugin({ db }),
264
+ schemaExplorerPlugin({ admin: true }),
265
+ ],
266
+ });
267
+ ```
189
268
 
190
- ### 2.15 `swaggerPlugin` (`plugins/swagger`)
191
- Interactive OpenAPI 3.0 Swagger UI documentation.
269
+ ### 2.15 `swaggerPlugin` / `openapiPlugin` (`plugins/swagger`)
270
+ Interactive OpenAPI 3.0 API documentation supporting both modern **Scalar API Reference** and classic **Swagger UI**, automated parameter/tag/summary inference, auth detection, Admin Panel embedding, and CLI export.
271
+
272
+ - **Options**:
273
+ - `path`: Base path for documentation (default: `/_swagger`). Spec served at `{path}/openapi.json`.
274
+ - `ui`: Default playground engine: `'swagger'` or `'scalar'` (default: `'swagger'`).
275
+ - `theme`: Theme for Scalar UI (`'default'`, `'purple'`, `'moon'`, `'solarized'`, etc.).
276
+ - `darkMode`: Scalar dark mode toggle (default: `true`).
277
+ - `admin`: Auto-register inside Admin Panel (`/_admin/#!/api-docs`) when `admin-panel` plugin is loaded (default: `true`).
278
+ - `adminTitle`: Admin navigation label (default: `'API Docs'`).
279
+ - `includeOrmSchemas`: Merge ORM models into `components.schemas` (default: `false`).
280
+ - `authorize`: Custom `(req) => boolean` guard function.
281
+ - **Endpoints**:
282
+ - `GET /_swagger`: Primary UI (Scalar or Swagger based on `ui` option).
283
+ - `GET /_swagger/scalar`: Always serves modern Scalar UI.
284
+ - `GET /_swagger/swagger`: Always serves Swagger UI.
285
+ - `GET /_swagger/openapi.json`: OpenAPI 3.0 specification document.
286
+ - **Example**:
287
+ ```javascript
288
+ const { createApp, openapiPlugin } = require('webspresso');
289
+
290
+ const { app } = createApp({
291
+ plugins: [
292
+ openapiPlugin({
293
+ ui: 'scalar',
294
+ theme: 'purple',
295
+ includeOrmSchemas: true,
296
+ }),
297
+ ],
298
+ });
299
+ ```
192
300
 
193
301
  ### 2.16 `realtimePlugin` (`plugins/realtime`, `core/realtime`)
194
302
  Framework-agnostic, plugin-based, and adapter-driven Realtime layer supporting WebSocket, SSE, Socket.IO, and distributed Redis Pub/Sub transports with zero SSR execution hazards.
@@ -415,5 +523,41 @@ RFC 4180 compliant CSV generator, parser, ORM model export, streaming chunk writ
415
523
  - `csv.createStreamWriter(stream, options)` → `{ writeHeader, writeRow, writeRows, end }`
416
524
  - **Built-in Services**: `csv.generate`, `csv.parse`, `csv.exportModel` accessible via `ctx.service()` or `req.service()`.
417
525
 
526
+ ### 2.19 `dashboardPlugin` / `devToolbarPlugin` (`plugins/dashboard`)
527
+ Interactive Webspresso Developer Dashboard SPA mounted at `/_webspresso` and Floating In-Page DevTools bar (`fsy.devToolbar()`) inspired by Django Debug Toolbar and Nuxt DevTools.
528
+
529
+ - **Aliases**: `dashboardPlugin`, `devToolbarPlugin`, `devtoolsPlugin`.
530
+ - **Options**:
531
+ - `path`: Base URL path for dashboard (default `/_webspresso`).
532
+ - `title`: Dashboard browser title (default `'Webspresso Developer Dashboard'`).
533
+ - `enabled`: Boolean to force enable in production (default `process.env.NODE_ENV !== 'production'`).
534
+ - **Dashboard Features (`/_webspresso`)**:
535
+ - **Routes Tab**: Full table of file-based SSR and API routes with live search, method badges, dynamic parameters (`[id]`), and target files.
536
+ - **Models Tab**: All registered ORM models with database tables, columns list, cache strategy (`smart` / `auto`), and soft-delete status.
537
+ - **Services Tab**: All business services with transaction safety status, authentication guards (`admin`, roles), schemas, and cache TTL.
538
+ - **Plugins & Config Tabs**: Active plugin manifests, dependencies, and sanitized framework configuration.
539
+ - **JSON API Endpoints**:
540
+ - `GET /_webspresso/api/routes`
541
+ - `GET /_webspresso/api/plugins`
542
+ - `GET /_webspresso/api/config`
543
+ - `GET /_webspresso/api/models`
544
+ - `GET /_webspresso/api/services`
545
+ - `GET /_webspresso/api/overview` (aggregate system metrics, memory, uptime, node version)
546
+ - **Floating In-Page Dev Toolbar (`fsy.devToolbar()`)**:
547
+ - Automatically embedded in `views/layout.njk` during development (`NODE_ENV !== 'production'`).
548
+ - **Collapsed Bottom Pill**:
549
+ - `⚡ DEV` toggle button with `Alt+D` hotkey shortcut.
550
+ - Current route method, HTTP status code (`[GET 200] /path`).
551
+ - Ambient database queries pill (`🗄️ N queries (Xms)`) from `AsyncLocalStorage` request profiler.
552
+ - Prominent N+1 warning alert badge (`⚠️ N+1 (M)`).
553
+ - Quick access buttons to `Dashboard (/_webspresso)`, `Admin (/_admin)`, `API Docs (/_swagger)`, and `Schema (/_schema)`.
554
+ - **Expandable DevTools Drawer (toggled via click or `Alt+D`)**:
555
+ - **🗄️ SQL Queries Tab**: Execution duration (<40ms green, >40ms red), table pills, formatted SQL statement, and N+1 warning box with actionable suggestions (`repo.query().include(...)`).
556
+ - **📄 Route & Page Tab**: Route path, matched file, template name, params, and parsed query string.
557
+ - **🚀 Quick Links Tab**: Configurable tool cards for fast navigation between admin, swagger, and custom tooling.
558
+ - **💻 System Tab**: Process uptime, memory usage, environment, and Node platform metrics.
559
+ - **Zero Production Overhead**: When `process.env.NODE_ENV === 'production'`, `devToolbar()` immediately returns `""` with zero overhead.
560
+
561
+
418
562
 
419
563
 
package/.agents/QUEUE.md CHANGED
@@ -111,3 +111,46 @@ module.exports.options = {
111
111
  backoff: { type: 'exponential', delay: 2000 },
112
112
  };
113
113
  ```
114
+
115
+ ---
116
+
117
+ ## 5. Job Retention & Pruning
118
+
119
+ To prevent the queue database table or memory cache from accumulating indefinitely:
120
+
121
+ ### 1. Auto-Retention in `createQueueManager` / `queuePlugin`
122
+ ```js
123
+ queuePlugin({
124
+ adapter: 'database',
125
+ db: appDb,
126
+ retentionDays: 7, // Keep completed jobs for 7 days
127
+ cleanupIntervalMs: 24 * 60 * 60 * 1000, // Run every 24h
128
+ autoCleanup: true,
129
+ retentionStatuses: ['completed'], // or ['completed', 'failed']
130
+ });
131
+ ```
132
+
133
+ ### 2. Programmatic `clean()`
134
+ ```js
135
+ // Delete completed jobs older than 7 days
136
+ const deletedCount = await queue.clean({
137
+ days: 7,
138
+ status: ['completed'], // or 'failed', or ['completed', 'failed']
139
+ });
140
+
141
+ // Or with an explicit cutoff date:
142
+ await queue.clean({
143
+ olderThan: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
144
+ status: 'failed',
145
+ });
146
+ ```
147
+
148
+ ### 3. CLI Command: `queue:prune`
149
+ ```bash
150
+ # Delete completed jobs older than 7 days
151
+ webspresso queue:prune --days 7
152
+
153
+ # Delete both completed and failed jobs older than 14 days
154
+ webspresso queue:prune --days 14 --status completed,failed
155
+ ```
156
+