Imported from litepacks/webspresso (
AGENTS.md). Install upstream withnpx skills add litepacks/webspresso. Copyright stays with the author.
Webspresso Project Guidelines & Rules
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.
🎯 Agent Intent Triage Matrix (Quick Guide Selection)
When tasked with a feature or bugfix, immediately consult the corresponding topic guide before writing code:
| Intent / Task | Canonical Topic Guide | Primary Directory / Ground Truth |
|---|---|---|
| New API Route / Endpoint | .agents/ROUTING.md |
pages/api/... |
| SSR HTML Page / Layout / Loader | .agents/ROUTING.md & .agents/STREAMING.md |
pages/*.njk, pages/*.js, views/ |
| Database Model / Migration / Query | .agents/ORM.md |
models/*.js, core/orm, migrations/ |
| Business Logic / Transaction / Service | .agents/SERVICES.md |
services/ |
| Admin Panel (Page, Widget, Action, UI) | .agents/ADMIN.md |
plugins/admin-panel/ |
| Authentication (Session / JWT / Guard) | .agents/AUTH.md |
core/auth/ |
| Background Jobs & Worker Queue | .agents/QUEUE.md |
jobs/ |
| Decoupled Events & Signals | .agents/EVENTS.md |
core/events/, listeners/ |
| Fault Tolerance / Circuit Breaker / Retry | .agents/RESILIENCE.md |
core/resilience/ |
| API Signatures & Types Verification | index.d.ts |
Canonical Ground Truth |
🛡️ 4-Step Mandatory Agent Workflow Protocol
Every coding agent working on Webspresso MUST follow this 4-step execution discipline:
- Discover & Triage: Identify the relevant topic guide above and inspect existing similar files in the workspace (e.g.
pages/api/,models/,services/). - Contract Adherence: Follow the exact module contract exported by the framework (
{ schema, middleware, handler }for routes,defineModelfor ORM,defineServicefor services). - 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. - Targeted Verification: Run the specific Vitest test file (
npx vitest run tests/...) to confirm zero regressions before marking the task complete.
⚖️ ❌ BAD vs ✅ GOOD Summary Matrix
| Category | ❌ NEVER DO THIS (Anti-Pattern) | ✅ ALWAYS DO THIS (Webspresso Way) |
|---|---|---|
| Routing | routes/index.js, express.Router(), app.get('/api/users') |
pages/api/users.get.js exporting { schema, handler } |
| Database | db('users').where({ id }).select() (Raw Knex queries) |
db.getRepository('User').findById(id) |
| Business Logic | controllers/UserController.js |
services/user/get.js → ctx.service('user.get', input) |
| Auth | npm i jsonwebtoken passport express-session |
Built-in req.auth, core/auth, middleware: ['jwt'] |
| SSR Rendering | res.render('profile.njk', data) inside custom handlers |
Companion loader pages/profile.js exporting async function load() |
| Exceptions | res.status(404).json({ error: 'Not found' }) |
throw new NotFoundError('User not found') |
| Background | setTimeout(...), npm i bullmq |
jobs/user/welcome.js → req.queue.dispatch('user.welcome', data) |
1. Codebase Architecture
1.1 Core SSR & Routing (pages/, views/)
- File-based Routing: Pages located in
pages/automatically map to URL routes (e.g.pages/index.njk→/,pages/products/[id].njk→/products/:id). - Data Loaders (
load()): Page routes exportasync function load({ req, res, db, ctx })to fetch data server-side before template rendering. - Templating & Helpers: Nunjucks (
.njk) templates rendered with layouts (e.g.views/layout.njk). Access helpers viafsyobject in templates. - Asset Versioning & Cache-Busting: Configured via
createApp({ assets: { version, manifestPath, prefix } }). Supports query-string versioning (?v=1.2.3), Vite/Webpack manifest resolution (.vite/manifest.json), CDN prefixing, andfsy.asset(),fsy.css(),fsy.js(),fsy.img()template helpers. - Framework Exceptions & Central Error Boundary: Built-in exception hierarchy (
WebspressoError,HttpError,ValidationError,SecurityError,RequestAbortedError,ConfigurationError,PluginError,RouteNotFoundError) and custom handler hook (app.setErrorHandler). Async route handlers automatically propagate rejected promises. Production responses mask 500 stack traces and error details. - Graceful Shutdown & Lifecycle Management: Configured via
createApp({ server: { shutdown: { enabled: true, mode: 'graceful'|'force', timeout: 10000 } } }). Socket connection tracking, request draining withConnection: close, and reverse-order plugin disposer cleanup. - HTTP Response Compression: Zero-dependency streaming zlib compression configured via
createApp({ server: { compression: true } })with Brotli (br), Gzip (gzip), Deflate (deflate), threshold buffering (1 KB), and route-level opt-out (res.compress(false)). - HTTP 103 Early Hints & Critical Asset Preloading: Zero-dependency RFC 8288 / RFC 8297 Early Hints dispatcher configured via
createApp({ earlyHints: true })or per-pagedefinePage({ earlyHints }). Emits informational 103 status code with route CSS/JS preloads before asyncload()finishes to minimize TTFB, FCP and LCP, with safe fallback andres.earlyHints(links)/ctx.earlyHints(links)helpers. - Configurable Payload Size Limits & DoS Protection: Zero-dependency body limit enforcement configured via
createApp({ limits: { json: '1mb', urlencoded: '1mb', raw: false, text: false, parameterLimit: 1000, captureRawBody: false } })or shorthandlimits: '5mb', with automatic HTTP 413PayloadTooLargeErrorand HTTP 400BadRequestErrormapping, route overrides (limits.routes), streaming bypass (limits.exclude), and raw body capture onreq.rawBodyfor webhook signatures. - Native Cloud & Kubernetes Health & Readiness Probes: Zero-dependency RFC-compliant liveness (
/healthz), readiness (/readyz), and combined diagnostic (/health) endpoints configured viacreateApp({ healthCheck: true }). Includes non-blocking event loop lag monitoring (perf_hooks.monitorEventLoopDelay), database/queue connectivity tests, and automatic HTTP 503 draining integration withShutdownManagerwhen pods enter graceful termination. - High-Performance In-Memory LRU & Tagged Cache Engine: Zero-dependency memory-bounded caching (
core/cache) configured viacreateApp({ cache: { maxEntries: 1000, maxMemoryMb: 50, defaultTtl: '15m' } })or shorthandcache: true|false. Provides O(1) LRU eviction, byte budget constraints preventing OOM, leak-free tag invalidation (TaggedLruCache), stampede protection (getOrSet), and powers ORM query caching and Zod schema caching. - Enterprise Resilience & Fault Tolerance (Circuit Breaker & Retry Engine): Zero-dependency resilience system (
core/resilience) featuring a three-stateCircuitBreaker(CLOSED,OPEN,HALF_OPEN), rolling window failure rate tracking, per-call execution timeouts, graceful fallbacks, and an exponential backoff retry engine (retry,withRetry) with randomized jitter and transient error detection (ECONNRESET, 429, 5xx). Seamlessly integrated into the Services Layer (defineService({ circuitBreaker, retry })) and exposed viaapp.breakers,app.getBreaker(),req.breaker(), andreq.retry(). - Custom Error & 404 Pages: Configured via
createApp({ errorPages: { notFound, serverError, timeout } }). Supports template paths (e.g.notFound: '404.njk') or custom handler functions, passing{ fsy, locale, isDev, url, method }to templates. - Cold Start & High-Performance Optimizations:
- Unified single-pass route scanner (
discoverAppRoutes). - Dev-mode on-demand (JIT) route evaluation (
lazyRoutes: true, dev boot ~15ms). - Ahead-of-time (AOT) route table manifest (
webspresso build->.webspresso/routes.manifest.json). - Ahead-of-time (AOT) Nunjucks template precompilation (
webspresso build->.webspresso/templates.compiled.js). - On-demand lazy plugin hydration (
lazyPlugin,adminPanelPlugin({ lazy: true }),fileManagerPlugin({ lazy: true })).
- Unified single-pass route scanner (
- Middleware & Hooks: Route lifecycle hooks can be declared per-page or globally via
pages/_hooks.js. - API Endpoints & Routing Architecture:
- ⚠️ CRITICAL ANTI-PATTERN: NEVER create a
routes/orsrc/routes/directory. NEVER useexpress.Router(),app.get(), orapp.post()for application endpoints. - 100% File-Based Routing: All API routes MUST be created inside
pages/api/...with HTTP method extensions:pages/api/notes.get.js→GET /api/notespages/api/notes.post.js→POST /api/notespages/api/notes/[id].get.js→GET /api/notes/:idpages/api/notes/[id].delete.js→DELETE /api/notes/:id
- Standard API Route Module Contract:
const { defineApi } = require('webspresso'); module.exports = defineApi({ schema: ({ z }) => ({ body: z.object({ title: z.string().min(1) }), params: z.object({ id: z.string().optional() }), }), middleware: ['auth'], // optional named or functional middleware handler: async (req, res, ctx) => { // req.db and req.service are automatically injected // req.input.body contains the validated payload const item = await req.db.getRepository('Note').create(req.input.body); return res.status(201).json(item); }, }); - Modular Architecture (
src/modules/ormodules/):- Encapsulate domain features using
defineModule({ name, pages, api, services, middlewares }). - Auto-registers routes (
/auth/login,/api/auth/login), services ('auth.login'), and scoped middlewares without manual router glue.
- Encapsulate domain features using
- ⚠️ CRITICAL ANTI-PATTERN: NEVER create a
1.2 Services Layer (services/, src/services/)
- File-based Auto-Discovery: Services located in
services/map directly to dot-separated service names (e.g.services/user/create.js→'user.create') and camelCase aliases ('user.reset-password'&'user.resetPassword'). - Declarative Validation & Authorization: Define optional Zod
schema,auth(boolean, role string/array, predicate),timeout(ms),transaction: true(ACID transaction propagation across nested calls), andcache: { ttl, key }. - Unified Invocation: Consumed via
ctx.service('service.name', input)from SSR loaders,req.service()in API routes, or standalonecreateServiceRegistry().
1.3 ORM & Database Layer (core/orm, models/)
- ⚠️ CRITICAL ANTI-PATTERN: NEVER use raw Knex queries (e.g.
db('table')orknex('table')) in application code. Raw queries bypass schema validation, lifecycle hooks, soft-deletes, multi-tenant scopes, hidden fields, and query caching. - ALWAYS Use Repositories: Accessed via
db.getRepository('ModelName')orreq.db.getRepository('ModelName'):await repo.findById(id)await repo.find({ status: 'active' })await repo.findOne({ slug })await repo.create(data)(validates schema & executes hooks)await repo.update(id, data)await repo.delete(id)(respects soft deletes)await repo.query().where('price', '>', 50).paginate({ page, limit })await repo.query().include('user', 'tags').find()(eager loading)
- Model Definition: Defined in
models/*.jsusingdefineModel({ name, table, schema, relations, scopes, hidden, admin, cache }). - Schema & Types: Built with
zdbschema builder (zdb.id(),zdb.string(),zdb.integer(),zdb.boolean(),zdb.file(),zdb.json()). - Ambient Transactions: Repositories automatically bind to ambient transactions (
AsyncLocalStorage) insidedb.transaction()and services (transaction: true) without manualtrxpassing. - Query Caching: Memory/provider query cache configured per database instance or model (
cache: 'auto'|'smart'|true). - Migrations: Database schema changes managed via Knex migrations in
migrations/(webspresso db:migrate).
1.4 Admin Panel Architecture (plugins/admin-panel)
- SPA CRUD Engine: Modular Mithril.js SPA mounted at
/_adminpowered byadminPanelPlugin({ db }). - Admin Module Registration: Registered using
adminApi.registerModuleoradminApi.registerPageDir. - Custom Admin Pages:
componentFile: Path to a clean Mithril component.jsfile.pagesDir: Directory auto-discovery containing page folders withpage.jsonandcomponent.js.- Auto Layout Wrapping: By default (
layout: true), custom page views are automatically wrapped inside the AdminLayoutandBreadcrumbcontainers without requiring manualm(Layout, ...)nesting. Setlayout: falsefor full-screen / custom canvas pages.
- Extension Points:
- Custom Field Renderers:
registry.registerFieldRenderer(type, { display, edit }). - Widgets:
registry.registerWidget(id, config). - Actions & Bulk Actions: Single record buttons (
registerAction) and multi-select table actions (registerBulkAction).
- Custom Field Renderers:
- Session Isolation: Admin staff authentication uses a separate session (
req.session.adminUser//_admin/api/auth/*), isolated from public site auth (req.user).
1.5 Plugin Ecosystem (plugins/)
Plugins expose name, version, dependencies, and lifecycle hooks (register(ctx), onRoutesReady(ctx)):
adminPanelPlugin: Model CRUD, custom pages, widgets, user management.fileManagerPlugin: Media library, directory tree, file preview, and drag-and-drop uploads.basicAuthPlugin: Zero-dependency HTTP Basic Authentication (RFC 7617) with named route middleware (ctx.middlewares.basicAuth) and global protection.contentPlugin: Schema-driven CMS with inline editing and headless API.uploadPlugin: Multipart file uploads with local/cloud storage providers.redirectPlugin: Configurable HTTP 301–308 redirects.rateLimitPlugin: Named rate limiters (express-rate-limit).siteAnalyticsPlugin: Self-hosted page view analytics and client JS error tracking.emailPlugin: MJML template compilation & Nodemailer integration.polarPlugin: Polar.sh subscription billing (checkout, portal, webhooks, Customer State sync). RequiresrateLimitPluginbefore polar for rate limiters. Supportshooks.isPaidUser,syncBeforeCheckout,syncBillingForAppUser. Seedocs/guides/polar-production-checklist.md.auditLogPlugin: Admin mutation audit logging.ormCacheAdminPlugin: Cache inspection and invalidation dashboard.corsPlugin: Zero-dependency Cross-Origin Resource Sharing handler.csrfPlugin: CSRF token validation and Nunjucks form helpers.realtimePlugin: Framework-agnostic, plugin-based realtime layer (core/realtime) with WebSocket, SSE, Socket.IO, and distributed Redis Pub/Sub adapters.restResourcePlugin: Zero-boilerplate RESTful CRUD API generator directly from ORM models with eager loading, sanitization, filtering, pagination, and soft-delete scoping.xlsxPlugin: Excel spreadsheet generation, parsing, ORM streaming export (res.xlsx), and built-in services (xlsx.generate,xlsx.parse,xlsx.exportModel).csvPlugin: RFC 4180 CSV generator, parser, Excel UTF-8 BOM compatibility, formula sanitization, streaming writer (res.csv), and built-in services (csv.generate,csv.parse,csv.exportModel).apiKeyPlugin: Zero-dependency B2B & Developer API Key Management with SHA-256 secure storage, constant-time verification, granular wildcard scopes, named route middleware (ctx.middlewares.apiKey), and non-blocking usage tracking.webhooksPlugin: Outgoing Webhook Dispatcher with HMAC-SHA256 cryptographic signatures, wildcard event matching (*,order.*), automatic retries with exponential backoff, background job queue integration (core/queue), built-in services (webhook.dispatch,webhook.ping,webhook.retry), and Mithril.js Admin Panel management UI.
2. Development & Testing Workflow
2.1 Essential Commands
- Dev Server:
npm run devorwebspresso dev - Run Vitest Unit Tests:
npm testornpx vitest run tests/unit/admin-panel/ - Run Migrations:
npx webspresso db:migrate - Project Sanity Check:
npx webspresso doctor - Scaffold AI Agent Rules:
npx webspresso agents:init
2.2 Testing & Quality Assurance
- Zero Regression Policy: Always run unit tests before declaring any task complete.
- Targeted Test Execution: Run specific unit test files during development for fast feedback (
npx vitest run tests/unit/admin-panel/admin-module-files.test.js). - API Backward Compatibility: Never break existing
registerModule,registerPage, oradminApicontracts. Always add new parameters as optional or backward-compatible enhancements.
3. Coding Standards & Conventions
- Strict Signature & Schema Verification: Always verify function signatures and object schemas by viewing authoritative source files before calling or extending them.
- File & Component Separation: Keep client-side components in clean standalone JS files (
component.js/componentFile) rather than escaping inline template strings. - Log & Traceback Inspection: Base all bug fixes strictly on exact runtime error log tracebacks and empirical test output. Never swallow errors or return dummy fallbacks.
- Strict File-Based Routing (NO
routes/orapp.get()): Webspresso is strictly file-based. Never create manual router files (src/routes/*.js), never callapp.get(), and never useexpress.Router(). All application pages belong inpages/and all API endpoints belong inpages/api/with HTTP method extensions (.get.js,.post.js,.delete.js,.patch.js,.put.js). - Strict Repository Pattern (NO Raw
db('table')): Never write raw Knex table queries in route handlers or services. Always usereq.db.getRepository('ModelName')to ensure schema validation, hooks, scopes, and query caching are applied. - Strict Services Layer (NO
controllers/): Never create acontrollers/folder or controller classes. Encapsulate business logic inservices/domain/action.jsand call viactx.service('domain.action', input). - Native Dual Auth (NO External JWT/Passport Packages): Never install
jsonwebtoken,passport, orexpress-session. Always use nativereq.authandwebspresso/core/auth. - Page Data Loaders (NO Manual
res.render()): Never callres.render()inside custom handlers for web pages. Use companion loaderspages/*.jsexportingasync function load({ req, res, db, ctx }). - 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. - Background Jobs (NO BullMQ /
setTimeout): Never use unmanagedsetTimeoutor external queues. Place job workers injobs/and dispatch viareq.queue.dispatch().
