paradox-node
Generate and run full-stack Express.js CRUD servers with PostgreSQL backends from Paradox specifications.
Define your types in .dox, and paradox-node generates a complete server with CRUD routes, Pug-templated HTML views, user authentication, and permissions — then compiles and runs it.
Usage
paradox-node --port 3000 --title "My App" --crud User --crud Post
All flags:
| Flag | Default | Description |
|---|---|---|
|
(required) |
Port to run the server on |
|
(required) |
The name of your app (used in manifest and page headers) |
|
|
Author name (included in manifest) |
|
|
Footer text displayed on HTML pages |
|
|
Path to a TypeScript module to serve additional routes |
|
(repeatable) |
Product type name to generate CRUD routes for |
|
|
Product type to use for user accounts (enables authentication) |
|
|
Matrix variable name for role-based permissions |
|
|
PostgreSQL connection URL |
You must provide at least --crud or --extra.
Example
Given this .dox specification:
import std
type User
name: Text
email: Text
password: Text
type Post
title: Text
body: Text
author: Text
Run:
paradox-node --port 3000 --title "Blog" --crud Post --account User
This:
-
Generates TypeScript types via
paradox generate --typescript -
Generates PostgreSQL DDL via
paradox generate --postgresql -
Creates
store.ts(pg Pool initialization) -
Creates
main.ts(full Express server with CRUD + auth) -
Compiles both with
tsc -
Initializes the database schema
-
Starts the server on port 3000
Generated Routes
For each --crud type, the following routes are generated:
| Method | Path | Description |
|---|---|---|
|
|
List all records (HTML table or JSON) |
|
|
Show create form (HTML) |
|
|
Create a new record |
|
|
Show a single record (HTML or JSON) |
|
|
Show edit form (HTML) |
|
|
Update a record |
|
|
Show delete confirmation (HTML) |
|
|
Delete a record |
All handlers support both JSON and HTML responses. When the request Accept header is application/json, responses are JSON. Otherwise, Pug templates render full HTML pages.
How It Works
paradox-node operates in six stages:
-
Generate specification — Runs
paradox generate --specto produce a JSON representation of the full.doxAST -
Generate TypeScript types — Runs
paradox generate --typescriptto produce type definitions and validation functions -
Generate PostgreSQL DDL — Runs
paradox generate --postgresqlto produceCREATE TABLEstatements, concatenated intoschema.sql -
Generate server code — Produces
store.ts(pg Pool) andmain.ts(Express app with all routes, middleware, auth, and views) -
Compile — Runs
tscon the generated TypeScript files -
Run — Starts the compiled server, initializing the database schema on boot
CRUD Operations
Each CRUD type gets a full set of database-backed handlers using parameterized SQL queries:
-
Create —
INSERTwith validation via the generatedvalid<Type>function -
Read —
SELECT … WHERE id = $1 -
Update —
UPDATE … SET … WHERE id = $Nwith validation -
Delete —
DELETE … WHERE id = $1 -
List —
SELECT *with both tabular HTML and JSON output
Authentication
When --account is provided, the server generates a full session-based authentication system:
-
POST /register— Create a new account (the account type must haveemailandpasswordfields) -
GET /register— Registration form -
POST /login— Authenticate with email and password -
GET /login— Login form -
GET /logoutandPOST /logout— End the session
Sessions are stored in-memory and tracked via an httpOnly cookie. Protected routes redirect unauthenticated users to /login.
Permissions
When --permissions is provided with a Paradox matrix variable, CRUD operations check the permission matrix before allowing access. Each operation (create, read, update, delete) is checked against the matrix for the relevant type.
Illumination
If a type has an illuminate interface instance, the generated server uses the illumination function instead of JSON.stringify when rendering views, providing custom HTML rendering of values.
HTML Views
The server uses Pug templates for HTML rendering:
-
List view — Tabular display of all records with links to view, edit, and delete
-
Item view — Detail view of a single record with edit and delete buttons
-
Create/Edit forms — Auto-generated forms based on the product type’s fields
-
Login/Register — Authentication forms (when
--accountis used)
Union fields render as dropdown selects, product fields render as nested forms, and standard fields render as text inputs.
Extra Routes
The --extra flag accepts a path to a TypeScript module that exports additional route handlers. The module’s named exports become GET routes at /<export-name>. If the module exports a uriHandlers object, its entries are registered as both GET and POST routes.
See Also
-
TypeScript Code Generation — The types and validation functions used by the server
-
PostgreSQL Code Generation — The DDL that initializes the database
-
paradox-express — Lighter-weight Express scaffold (handlers only, no database)
-
paradox-servant — Haskell Servant equivalent