Webspresso — Architecture (C4-style)

Purpose: Language- and platform-neutral map of the system, organized by feature sets.
Audience: Contributors, reviewers, and agents extending the framework.
Maintenance: Update this file whenever a feature set gains or loses a capability (see § Maintenance protocol).

MetaValue
Last reviewed2026-10-16
Package version0.0.84
Primary runtimeNode.js ≥ 18 (HTTP server process)
Secondary runtimeOptional in-process application kernel (no HTTP)

Maintenance protocol #

When to update this document

TriggerAction
New built-in pluginAdd row to § Built-in plugins; update container diagram if it introduces a new boundary
New CLI commandAdd to § CLI feature set
New ORM / auth / admin capabilityExtend the relevant feature-set section + component table
New extension point (hook, registry, API)Add to § Extension points
Breaking change to request pipeline or plugin orderUpdate § Request lifecycle and § Composition rules
New published export from package rootUpdate § Public surface

How to update

  1. Edit the feature-set section (not only the changelog).
  2. Bump Last reviewed and, if shipped, Package version.
  3. Add one line to Changelog at the bottom.

Agents and contributors: treat this file as the canonical structural index; narrative detail stays in README.md and doc/index.html.


Level 1 — System context #

Webspresso is a server-rendered web application framework with file-based routes, optional relational persistence, a plugin ecosystem, and operator tooling (CLI + admin UI).

Mermaid Diagram
View diagram source
C4Context
  title System context

  Person(dev, "Application developer", "Builds sites and APIs")
  Person(ops, "Operator", "Deploys, monitors, manages data")
  Person(admin_user, "Admin user", "Manages content via admin SPA")

  System(ws, "Webspresso application", "SSR + API + optional admin")

  System_Ext(db, "SQL database", "SQLite, PostgreSQL, MySQL, …")
  System_Ext(cdn, "CDN / third-party scripts", "Analytics, CAPTCHA, editor assets")
  System_Ext(fs, "Filesystem", "Templates, static assets, uploads")

  Rel(dev, ws, "Scaffolds, configures, extends")
  Rel(ops, ws, "Runs process, migrations, health checks")
  Rel(admin_user, ws, "HTTPS")
  Rel(ws, db, "ORM / migrations")
  Rel(ws, fs, "Reads templates, writes uploads")
  Rel(ws, cdn, "Optional script injection")
ActorGoal
Application developerShip SSR pages and JSON APIs with minimal boilerplate
OperatorRun one or more server processes; optional admin and audit tooling
Admin userCRUD on ORM-backed models without custom back-office code

Out of scope (by design): bundled hosting, multi-tenant SaaS control plane, mobile clients. Apps bring their own deployment target.


Level 2 — Containers #

Major deployable or runtime boundaries inside a typical application.

Mermaid Diagram
View diagram source
C4Container
  title Containers (typical deployment)

  Person(user, "Browser client")
  Person(operator, "Operator")

  Container(cli, "CLI", "Commander", "Scaffold, migrate, doctor, admin ops")
  Container(http, "HTTP application", "Express-compatible stack", "SSR, API, static files, plugins")
  Container(admin_spa, "Admin SPA", "Client-side Mithril app", "Served under configurable admin path")
  Container(orm, "ORM layer", "Knex + repositories", "Models, queries, cache, migrations")
  Container(kernel, "Application kernel", "In-process library", "Events, flows, views — optional")
  ContainerDb(database, "Database", "SQL")

  Rel(operator, cli, "Invokes")
  Rel(user, http, "HTTPS")
  Rel(user, admin_spa, "HTTPS (admin path)")
  Rel(http, orm, "Per-request DB access")
  Rel(http, admin_spa, "Embeds / serves")
  Rel(orm, database, "SQL")
  Rel(cli, orm, "Migrations, seeds")
ContainerCode anchorResponsibility
CLIbin/Project lifecycle; no long-running server
HTTP applicationsrc/server.js → createApp()Middleware, routing, rendering, plugin orchestration
File routersrc/file-router.jsMaps pages/ tree to SSR and API handlers
Template runtimeNunjucks + src/helpers.jsfsy.* helpers, assets, i18n in templates
Plugin hostsrc/plugin-manager.jsDependency order, lifecycle, inter-plugin APIs
ORMcore/orm/Schema, repositories, migrations, optional query cache
Site authenticationcore/auth/Session auth for public site (req.user) — separate import path
Admin SPAplugins/admin-panel/client/Mithril parts bundle; admin session (adminUser)
Application kernelcore/kernel/Event bus, flows, minimal views — not the HTTP createApp
OpenAPI helperscore/openapi/Spec generation for API documentation plugins

Note: createApp (SSR) and kernel.createApp (in-process) are different entry points with the same name.


Level 3 — Components by feature set #

Core HTTP & routing #

ComponentResponsibility
createAppAssemble Express app, plugins, routes, error pages, and graceful shutdown
discoverAppRoutesSingle-pass unified route scanner discovering pages, APIs, and route groups in one traversal
File routerpages/**/*.njk / pages/**/*.js → SSR; pages/api/*.{method}.js / src/api/*.{method}.js → API
JIT Route EvaluationDev-mode on-demand module evaluation (lazyRoutes: true) loading route handlers on first HTTP request
AOT Route ManifestBuild-time route serialization (webspresso build -> routes.manifest.json) bypassing runtime directory scanning
AOT TemplatesBuild-time Nunjucks precompilation (precompileTemplates -> templates.compiled.js) avoiding runtime parsing
definePagePure JS and companion page route definitions (load, head, render, middleware)
defineApiDeclarative JSON API endpoint definitions with Zod schema, middleware, and auto JSON serialization
defineModuleFeature domain encapsulation (modules/<name>/ with isolated pages/, api/, services/, and middleware/)
RouteTableImmutable route registry with deterministic priority tiers and .list(), .match(), .tree() inspection
Route configSibling .js: load, meta, middleware, hooks
API validationZod schema → req.input; 400 on failure
Global hookspages/_hooks.js lifecycle
i18nLocale JSON; t() in templates; route-level overrides
Client runtimeOptional Alpine + swup at /__webspresso/client-runtime/*
Security headersHelmet; CSP stricter in production
Static assetspublicDir; optional hashed manifest via assets config

Observability & Error Tracing #

ComponentResponsibility
Request CorrelationNative req.id from X-Request-Id header or crypto.randomUUID(); auto-attached to responses
Error Trace ObjectDevelopment payload enriched with { route, method, source, module, phase, requestId }
Console BannersHigh-visibility boxed terminal error formatting for rapid local debugging
Central Error BoundaryNormalized HTTP/framework error handling with production diagnostic masking

ORM & database #

ComponentResponsibility
zdb schema buildersColumn types including file, nanoid, relations
defineModelTable mapping, admin, rest, cache, hidden, scopes
createDatabaseKnex instance + model auto-load
RepositoryCRUD, query() builder, pagination, soft delete
Migrations / seedsKnex migrations; CLI + core/orm/seeder
Transactionsdb.transaction(trx => …)
Query cacheOpt-in memory provider; db.cache.* API
ORM eventsbeforeCreate, afterFind, …

Authentication (dual boundary & dual auth) #

Webspresso features a Dual Authentication (Session + JWT) architecture designed to seamlessly serve both SSR web applications and REST API / Mobile / SPA clients:

  • Session + Cookie Auth (Stateful): Primary auth mechanism for browser-rendered SSR routes (/, /dashboard) and Admin Panel (/_admin). Uses httpOnly secure cookies for XSS protection and immediate server-side session revocation.
  • JWT + Refresh Token Auth (Stateless): Built-in zero-dependency HS256 JWT auth for REST APIs and mobile/SPA clients (/api/*). Uses Authorization: Bearer <token> for access tokens (short-lived) and rotatable Refresh Tokens (long-lived).
LayerSession / TokenIdentity storeTypical login
Site SSR authApp session (userId) & remember_tokenApp model (e.g. User)Custom routes via setupRoutes
Site REST/API authJWT Bearer Access Token & Refresh TokenApp model (e.g. User)/api/login returning { accessToken, refreshToken }
Admin authAdmin session (adminUser)admin_users table/_admin SPA
ComponentResponsibility
createAuth / quickAuthCredential verify, session, remember-me, and opt-in JWT / Refresh Token manager
signJwt / verifyJwtZero-dependency HS256 HMAC-SHA256 JWT signing, verifying, and duration parsing
generateRefreshToken / refreshAccessTokenLong-lived refresh token generation & automatic token rotation
authenticate middlewareDual-Auth Evaluator: Checks Authorization: Bearer <token> header first; falls back to Session cookie, then Remember-Me cookie
requireJwt middlewareEnforces valid Bearer Access Token on API endpoints (rejects refresh tokens for access)
Policies / gatescan, authorize, route middleware: ['auth'] / middleware: ['jwt']
requireAuth / requireGuestRedirect or JSON 401; stores intendedUrl on site auth (app must consume on login POST)
Admin auth.jsSetup, login, logout, requireAuth for admin API
Admin intended routeClient sessionStorage — return to protected SPA route after login

Admin panel #

ComponentResponsibility
Admin pluginRegisters admin path, API, serves SPA HTML
Admin registryModels, menus, widgets, uploadUrl, custom pages
CRUD APIList/create/update/delete from model metadata
Field renderersTypes: text, number, boolean, json, rich-text, file-upload, relations
customFieldsOverride UI for columns (e.g. file-upload on string columns)
registerModule / registerPageDirPlugin extension: pages, menu, API, widgets (componentFile, pagesDir, custom HTML/URL pages, SSR scripts & styles, auto layout)

| User management | Optional CRUD for site users inside admin | | Rich text | Quill (CDN); HTML sanitized on save by default | | File upload UI | POST to uploadUrl; image preview; stores URL in model |

Built-in plugins #

Plugins declare name, version, optional dependencies, and lifecycle hooks (register, onRoutesReady, onReady).

PluginFeature setOne-line purpose
corsPluginSecurity / HTTPZero-dependency CORS middleware & preflight handling
basicAuthPluginSecurity / HTTPZero-dependency HTTP Basic Auth (RFC 7617) with named route middleware & global guard
csrfPluginSecurity / HTTPDouble-submit CSRF token validation and Nunjucks helpers
redirectPluginHTTPConfigurable redirects before file routes
rateLimitPluginHTTPNamed rate-limit middleware + optional global limiter
uploadPluginHTTP / adminMultipart upload endpoint + pluggable storage
healthCheckPluginOpsLiveness/readiness HTTP probe
restResourcePluginAPIAuto REST CRUD from model metadata
swaggerPluginAPI / docsOpenAPI 3 + Swagger UI from API routes
schemaExplorerPluginAPI / docsJSON ORM schema endpoint
recaptchaPluginSecurityreCAPTCHA verify middleware + helpers
emailPluginHTTP / AdminMJML + Nodemailer email sending with optional admin UI and auth integration
polarPluginHTTP / BillingPolar.sh subscription billing: checkout, portal, webhooks, Customer State sync, tier columns
adminPanelPluginAdminORM-backed CRUD SPA
contentPluginAdmin / CMSSchema-driven content types, entries, public API, inline edit
dataExchangePluginAdminExcel export + CSV/XLSX import
siteAnalyticsPluginAnalyticsSelf-hosted page views + admin charts
auditLogPluginComplianceAdmin mutation audit trail
ormCacheAdminPluginOps / ORMAdmin UI for query-cache metrics
sitemapPluginSEOsitemap.xml, robots.txt
analyticsPluginSEO / marketingThird-party tracker injection
seoCheckerPluginDev / SEOClient-side SEO audit toolbar
realtimePluginRealtimeFramework-agnostic realtime layer (WebSocket, SSE, Socket.IO, Redis pub/sub)
fileManagerPluginAdmin / MediaFilesystem media library, directory tree & asset picker
xlsxPluginData / ExportExcel XLSX generation, streaming export (res.xlsx), and parsing
csvPluginData / ExportRFC 4180 CSV generation, formula sanitization, streaming writer (res.csv), and parsing
dashboardPluginDevRoute browser at /_webspresso
lazyPluginPerformanceOn-demand plugin hydration wrapper deferring setup until first request

Package root re-exports a subset; full list: require('webspresso/plugins').

CLI feature set #

GroupCommands
Scaffoldnew, page, api, add tailwind
Server / Builddev, start, build
Databasedb:migrate, db:rollback, db:status, db:make, db:scaffold, seed, polar:migrate
Adminadmin:setup, admin:password, admin:list
Opsdoctor, upgrade, audit:prune, orm:map, favicon:generate

Client runtime & assets #

ComponentResponsibility
resolveClientRuntimeFeature flags: Alpine, swup
AssetManager / configureAssetsAsset path resolution, cache-busting query strings (?v=1.2.3), Vite/Webpack manifest resolution (manifestPath), and CDN prefixes (prefix) for fsy.asset, fsy.css, fsy.js, fsy.img
pageAssetsPer-route asset loading via load() return (stylesheets, scripts promoted to pageHead)
Tailwind (scaffold)App-level build:css; not part of core HTTP container

Application kernel (optional) #

ComponentResponsibility
Event busdispatch (sequential) / publish (concurrent)
defineFlowTrigger → condition → ordered actions
definePluginKernel plugins: events + inline views
BaseRepositoryIn-memory store emitting orm.<resource>.* events
View engineNamespaced minimal templates (ns::page)

Quality & tooling (repository) #

ComponentResponsibility
VitestUnit + integration tests
PlaywrightBrowser E2E (admin, auth, plugins)
TypeScript smokeindex.d.ts validation
BenchmarksVitest bench + CI regression script

Request lifecycle #

Order matters for correct behavior and security.

Incoming HTTP request
  → Security / timeout middleware
  → Request ID & Correlation assignment (req.id / X-Request-Id)
  → Body parsers
  → [Site auth session middleware] (if configured)
  → Static files
  → Client runtime routes
  → Plugin register() phase [e.g. redirect rules]
  → File-based routes (API + static SSR patterns)
  → Plugin onRoutesReady() [upload, admin, swagger, health, …]
  → setupRoutes() (application custom routes)
  → Dynamic / catch-all file routes (must be last)
  → 404
  → Central error handler (with trace enrichment & visual console banner)

Composition rules #

RuleReason
uploadPlugin before adminPanelPluginAdmin reads uploadUrl / webspresso.uploadPath for file fields
adminPanelPlugin before dataExchangePlugin, siteAnalyticsPlugin, auditLogPlugin, ormCacheAdminPlugin, emailPluginShared admin session and registry
redirectPlugin earlyMust run before file routes
createApp({ db }) when using ORM pluginsExposes ctx.db / req.db
Site auth + adminPanelPlugin({ auth })Optional site-user session UI in admin
Login GET in setupRoutes, not pages/login.njkAvoid route order bypassing requireGuest

Extension points #

MechanismUse for
createApp({ plugins })Built-in or custom plugins
createApp({ setupRoutes })Login, webhooks, custom Express routes
createApp({ middlewares })Reusable named middleware in route configs
createApp({ auth })Site-wide session authentication
createApp({ errorPages })Custom 404 (notFound), 500 (serverError), and 503 (timeout) templates or handler functions
Plugin register / onRoutesReadyRoutes, helpers, CSP, injections
ctx.usePlugin(name)Inter-plugin APIs
ctx.addHelper / addFilterTemplate surface
defineModel({ admin, rest, hooks, cache })Admin UI, REST exposure, ORM behavior
adminPanelPlugin({ configure }) / registerModuleAdmin menus, pages, widgets, APIs
admin.customFields / zdb.file()Admin form widgets
pages/_hooks.js + per-route hooksCross-cutting request logic
kernel.definePlugin / defineFlowNon-HTTP domain logic

Plugin contract (conceptual) #

{
  name, version, description?,
  dependencies?: { "other-plugin": semver },
  csp?: { ... },
  api?: { ... },
  register(ctx),
  onRoutesReady(ctx),
  onReady?(ctx)
}

Public surface #

ImportExports (high level)
webspressocreateApp, definePage, defineApi, defineModule, scanRoutes, discoverAppRoutes, generateRouteManifest, precompileTemplates, loadPrecompiledTemplates, compileRouteTable, RouteTable, router utils, ORM, kernel, selected plugins
webspresso/pluginsAll built-in plugins (xlsxPlugin, csvPlugin, realtimePlugin, fileManagerPlugin, adminPanelPlugin, lazyPlugin, defineLazyPlugin, etc.)
webspresso/core/authSite auth (createAuth, quickAuth, hash, middleware)
webspresso/core/ormORM submodules
webspresso/build/*Build/runtime manifests (routes.manifest.json, templates.compiled.js)

Documentation map #

DocumentRole
docs/ARCHITECTURE.md (this file)C4-style structure; feature-set index; update on structural changes
README.mdNarrative reference, examples, pitfalls
.agents/Modular AI agent guidebook and rules
docs/getting-started.mdOnboarding
docs/production-checklist.mdProduction hardening
plugins/admin-panel/client/README.mdAdmin SPA parts layout

Changelog #

DateChange
2026-10-16Cold-start & AOT optimizations: single-pass discoverAppRoutes, dev-mode JIT route evaluation (lazyRoutes), AOT route manifest (routes.manifest.json), template precompilation (templates.compiled.js), and on-demand lazy plugins (lazyPlugin, adminPanelPlugin({ lazy: true })).
2026-09-15Module file discovery (defineModule), modern Page & API loaders (definePage, defineApi), RouteTable deterministic compilation & introspection, request correlation IDs (req.id, X-Request-Id), and enhanced error tracing
2026-06-25contentPlugin — schema-driven CMS (content types, entries, public API, admin inline edit)
2026-06-17db:scaffold CLI — generate create-table migrations from all models/*.js
2026-06-17Initial C4-style architecture doc; admin intended-route after login; file upload image preview
Created · Updated