Framekit is a TypeScript meta-framework inspired by Frappe. It lets you build metadata-driven business applications with DocTypes, modules, permissions, workflows, hooks, generated APIs, customization, audit trails, outbox events, realtime publishing, a Desk UI, and portable Nitro deployment.
Nitro is the default host engine, but the framework core does not depend on Nitro, React, Drizzle, Redis, BullMQ, or Postgres. Those live behind adapter ports so applications can run in Node containers first and later target serverless or edge-style platforms where appropriate.
- Metadata-defined DocTypes and modules.
- Generated CRUD, workflow, metadata, customization, audit, outbox, diagnostics, auth, and OpenAPI endpoints.
- Password auth with signed session tokens.
- Tenant-aware permissions and Bearer-token context resolution.
- In-memory development stores and durable Postgres stores.
- Custom fields, view metadata, and naming series.
- Audit log and durable outbox with worker dispatch helpers.
- Realtime document event publishing.
- React Desk UI generated from metadata.
- Typed SDK, CLI scaffolding, Docker Compose, CI, and deployment docs.
corepack enable
corepack prepare pnpm@11.9.0 --activate
pnpm install
pnpm devThe CRM example API runs at:
http://localhost:3000Run the Desk UI in another terminal:
pnpm dev:deskThe Desk usually runs at http://localhost:5173. If that port is occupied, Vite will choose the next available port.
Desk uses the API's HttpOnly session cookie; it does not persist bearer tokens in browser storage.
Development-only CRM login:
{ "email": "admin@example.com", "password": "admin12345" }pnpm typecheck
pnpm test
pnpm build
pnpm audit:all
pnpm --filter @framekit/example-crm outbox:dispatch
pnpm --filter @framekit/cli framekit create-app alpha-suite
pnpm --filter @framekit/cli framekit new-module sales
pnpm --filter @framekit/cli framekit new-doctype sales-order
pnpm --filter @framekit/cli framekit generate-sdk examples/crm/src/app.ts
pnpm --filter @framekit/cli framekit generate-migration examples/crm/src/app.ts examples/crm/src/app.tsSystem, contracts, migrations, realtime, and operations:
GET /health
GET /health/dependencies
GET /api/meta
GET /api/diagnostics
GET /api/migrations
POST /api/migrations/plan
POST /api/migrations/apply
POST /api/commands/{command}
GET /api/realtime/events
GET /api/realtime/stream
GET /api/openapi.json/health/dependencies runs adapter-provided dependency checks, for example Postgres, Redis, queues, or downstream services.
Migration planning, executable apply/replay, drift rules, upgrade backfill, and rollback limits are documented in Executable migrations. Atomic bulk commands, cross-document sagas, idempotency, compensation, and recovery limits are documented in Mutation consistency.
Auth lifecycle, provider login, audit, and admin APIs:
Production identity-linking, OIDC Authorization Code + PKCE, invitation, recovery, and MFA policy are documented in docs/identity.md.
POST /api/auth/login
GET /api/auth/me
POST /api/auth/refresh
POST /api/auth/logout
POST /api/auth/password/change
POST /api/auth/providers/{id}/login
GET /api/auth/audit
GET /api/auth/users
POST /api/auth/users
PATCH /api/auth/users/{id}
PUT /api/auth/users/{id}
DELETE /api/auth/users/{id}
POST /api/auth/users/{id}/password
GET /api/auth/roles
POST /api/auth/roles
PATCH /api/auth/roles/{id}
PUT /api/auth/roles/{id}
DELETE /api/auth/roles/{id}
GET /api/auth/tokens
POST /api/auth/tokens
DELETE /api/auth/tokens/{id}Documents:
GET /api/doctypes/{doctype}
POST /api/doctypes/{doctype}
GET /api/doctypes/{doctype}/{id}
PATCH /api/doctypes/{doctype}/{id}
DELETE /api/doctypes/{doctype}/{id}
POST /api/doctypes/{doctype}/{id}/transitionFramework records:
GET /api/audit
GET /api/outbox
POST /api/outbox/{id}/dispatch
POST /api/outbox/{id}/failCustomization:
GET /api/custom-fields
POST /api/custom-fields
GET /api/views
POST /api/viewsExample login and authenticated request:
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/login \
-H 'content-type: application/json' \
-H 'origin: http://localhost:3000' \
-d '{"email":"admin@example.com","password":"admin12345"}' \
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
curl -s http://localhost:3000/api/doctypes/customer \
-H "authorization: Bearer $TOKEN"When an auth service is configured, every API route except health checks, login/provider login, and the OpenAPI document requires a valid bearer token or session cookie. Tenant, user, role, and permission headers never override that authenticated context.
Framework operations use dedicated permissions (or the * superuser permission):
| Permission | Operations |
|---|---|
framekit.diagnostics.read |
Runtime diagnostics |
framekit.migrations.read |
Migration history |
framekit.migrations.manage |
Migration planning and apply |
framekit.realtime.read |
Realtime event history and SSE stream |
framekit.audit.read |
Runtime audit trail |
framekit.outbox.read |
Outbox inspection |
framekit.outbox.manage |
Outbox dispatch/failure mutation |
framekit.customization.read |
Custom-field and view inspection |
framekit.customization.manage |
Custom-field and view mutation |
Apps without an auth service cannot access protected routes by default. Local-only prototypes may explicitly enable development.allowHeaderIdentity; Framekit accepts that escape hatch only when NODE_ENV=development or NODE_ENV=test.
SDK auth lifecycle and admin example:
import { createClient } from "@framekit/sdk";
const client = createClient({ baseUrl: "http://localhost:3000" });
await client.login("admin@example.com", "admin12345");
await client.me();
await client.refresh();
await client.upsertRole({
id: "support",
name: "Support",
permissions: ["crm.customer.read"]
});
const apiToken = await client.createApiToken({
name: "CRM import",
roles: ["support"],
permissions: ["crm.customer.read"]
});
await client.authAudit();
await client.logout();SDK failures are typed and preserve server status, code, details, and request identity. Retries are opt-in and limited to safe/idempotent operations; see SDK errors, retries, and configuration upgrades.
Provider login uses the same session shape after an app registers an auth provider:
await client.loginWithProvider("oidc", "<provider-token>");Migration workflow with SDK and CLI:
import { nextApp } from "./next-app";
const plan = await client.planMigration(nextApp);
await client.applyMigration(plan, { allowDestructive: false });pnpm --filter @framekit/cli framekit generate-sdk examples/crm/src/app.ts --out /tmp/crm-sdk.ts
pnpm --filter @framekit/cli framekit generate-migration examples/crm/src/app.ts examples/crm/src/next-app.ts --out /tmp/crm-migration.tsDocType is the primary metadata unit. It defines fields, permissions, naming, workflows, indexes, and views for a business document.
import { defineDocType } from "@framekit/core";
export const deal = defineDocType({
name: "deal",
label: "Deal",
naming: { prefix: "DEAL", series: true, digits: 5 },
fields: [
{ name: "title", label: "Title", type: "text", required: true, inList: true },
{ name: "amount", label: "Amount", type: "currency", default: 0, inList: true }
],
permissions: [
{ action: "create", permissions: ["crm.deal.write"] },
{ action: "read", permissions: ["crm.deal.read"] }
]
});Module groups DocTypes, permissions, navigation, hooks, jobs, typed settings, and dependencies. Apps can provide stable translation keys and canonical BCP 47 locale fallback; see Localization and Typed Settings.
Runtime executes framework use cases: validation, permissions, hooks, document persistence, audit, outbox, realtime publishing, custom fields, views, and naming series.
Nitro adapter exposes the runtime through generated HTTP routes.
| Package | Purpose | Verification status |
|---|---|---|
@framekit/core |
Pure metadata definitions: DocTypes, modules, apps, permissions, workflows, views. | Unit covered. |
@framekit/runtime |
Application services and ports for documents, audit, outbox, customization, naming, realtime, migration planning, checksums, destructive guards, and migration apply records. | Atomicity, concurrency and journaled saga recovery with PostgreSQL fencing covered. |
@framekit/auth |
Password hashing, signed sessions, refresh/logout, revocation, lockout, API tokens, auth audit, user/role admin, and provider-independent login ports. | Identity lifecycle, OIDC, native TOTP/recovery MFA and recent-authentication controls covered. WebAuthn remains outside this release. |
@framekit/nitro |
Nitro/H3 adapter for generated framework APIs, cookie transport, auth/admin routes, operations authorization, rate limiting, telemetry hooks, and health dependency checks. | In-process, built, forged-header, cross-tenant, and least-privilege checks covered. |
@framekit/openapi |
OpenAPI 3.1 generator from Framekit metadata and framework routes. | Unit covered. |
@framekit/db |
Postgres adapters for documents, users, roles, API tokens, session revocations, audit, outbox, custom fields, views, naming series, and migration history. | Postgres integration, migrations, schema inspection, component soak and crash recovery covered; deployment capacity requires qualification. |
@framekit/jobs |
Queue port, BullMQ adapter, outbox dispatcher, scheduled job registry. | Unit and Redis/BullMQ integration covered; sustained load/fault evidence remains deferred. |
@framekit/realtime |
Event bus contract and in-memory publisher/subscriber for document events and SSE routes. | Durable replay and full-stack authorization paths covered; sustained load evidence remains deferred. |
@framekit/sdk |
HTTP client for auth lifecycle, provider login, metadata, documents, audit, outbox, customization, views, migrations, realtime, and admin APIs. | Endpoint parity and standalone-consumer verification covered. |
@framekit/cli |
App/module/DocType scaffolding, generated SDK types, and executable migration workflows. | CLI and packed consumer proof include Desk installation and configuration-preserving upgrade. |
@framekit/storage |
Context-bound AES-GCM keyrings and durable PostgreSQL/S3 attachments. | Encryption, rotation, leases, cleanup races and restore checks covered. |
@framekit/desk-assets |
Installable Desk assets with versioned runtime configuration. | Packed installation and browser checks covered. |
@framekit/desk |
React Desk UI generated from metadata, auth/admin/operations/customization surfaces. | Build, mocked browser, and real full-stack Chromium/Firefox journeys covered. |
apps/desk React metadata-driven admin UI
examples/crm Nitro CRM example app
packages/* Framework packages
docs/ Architecture, deployment, and roadmap docsThe intended production target is a Nitro Node server with private or managed Postgres and Redis services. The current release is a beta with durable saga recovery, native MFA, component load/restore evidence, relational schema inspection, packaged Desk, and production storage adapters. Release promotion still requires hosted security/CI evidence and qualification against the operator’s actual infrastructure and application. See the maturity roadmap.
docker compose up --builddocker-compose.yml is a local/reference stack, not a production deployment template. Its Postgres and Redis ports bind only to 127.0.0.1. Set DATABASE_URL and FRAMEKIT_POSTGRES_PASSWORD explicitly in .env; neither has a default. The URL must use the appropriate host (postgres inside Compose, your configured host for host-side commands) and a percent-encoded password. Production credentials belong in the platform secret manager. See database configuration.
CRM requires DATABASE_URL and uses Postgres for:
- Documents
- Users
- Audit events
- Outbox events
- Custom fields
- View metadata
- Naming series
Nitro can also emit provider-specific outputs through NITRO_PRESET. Keep long-running work behind queue/outbox ports for serverless deployments.
See docs/deployment.md. See docs/security.md before exposing a deployment to untrusted traffic. See docs/observability.md for lifecycle, health, telemetry, and redaction contracts. See docs/compatibility.md for supported runtimes, services, and browsers.
Copy .env.example only for local development. Production deployments start from .env.production.example and provision blank secrets through the deployment platform; do not reuse the Compose defaults:
cp .env.example .envImportant variables:
DATABASE_URL=
REDIS_URL=redis://localhost:6379
FRAMEKIT_AUTH_SECRET=<provision-at-least-32-random-characters>
FRAMEKIT_ALLOWED_ORIGINS=https://desk.example.com
FRAMEKIT_ADMIN_EMAIL=ops@your-company.example
FRAMEKIT_ADMIN_PASSWORD=<provision-with-a-secret-manager>
VITE_FRAMEKIT_API_URL=http://localhost:3000pnpm --filter @framekit/cli framekit create-app alpha-suiteScaffold commands refuse to overwrite generated paths by default. Use --dry-run to inspect every planned write and --force to replace only the listed scaffold files.
create-app is intentionally a server starter. It includes:
package.jsonnitro.config.tsroutes/[...].tssrc/app.ts.env.example.env.production.exampleDockerfile- A starter
NoteDocType
Use framekit create-app my-app --desk to install Desk at /desk/, or framekit install-desk public/desk for an existing app. See Desk distribution. The starter uses memory adapters for development and refuses production startup until durable runtime and authentication adapters are configured; the CRM composition is the production integration reference.
Runnable, copyable SDK examples are available for React, Vue, Svelte, Solid,
and vanilla TypeScript under examples/frontends. Each
template connects to the CRM example, demonstrates bearer login/logout, checks
health and metadata, lists customers, and creates customers with idempotent SDK
mutations.
Start the API and one frontend in separate terminals:
pnpm dev
pnpm dev:frontend:reactSwap react for vue, svelte, solid, or vanilla. Use
pnpm verify:frontends to typecheck and build all five. These examples are
frontend starters, not a promise that framekit create-app packages the full
Desk application. The local CRM demo accepts admin@example.com /
admin12345; templates keep that development credential and the returned token
in memory only.
Every iteration should pass:
pnpm audit:allCurrent verification status:
- Merged #42 baseline:
pnpm audit:allpassed lint, typecheck, coverage tests, and builds. - Unit/in-process suite: 161 passed and 18 skipped; runtime 37/37 and Nitro 22/22.
- Coverage: 68.15% statements, 62.08% branches, 68.93% functions, and 70.62% lines.
- Coverage gates enforce at least 60% statements/functions/lines and 50% branches across public package source.
- Production build passes for packages, Desk, and CRM example.
- Split CI covers package-local tests, coverage, Node 22/24 exports, Postgres 16/17, Redis 7/8, built smoke, standalone consumption, browsers, CodeQL, dependency audit, and SBOM generation. Live PG16/Redis8, built smoke, standalone, mocked browser 7/7, and Chromium/Firefox full-stack 8/8 evidence passed on that baseline.
- In-process Nitro smoke covers auth lifecycle, provider login, OpenAPI, diagnostics, document CRUD, uniqueness, filters, cursor/projection, auth admin, password reset/change, customization, migrations, outbox, realtime history, and security/operations headers.
Framekit follows a clean architecture boundary:
coreandruntimeare inward modules.- Nitro, React, Postgres, Redis, BullMQ, and Docker are outer adapters.
- Source dependencies point inward.
- Framework details are swappable behind ports.
Current clean architecture score: about 8.5/10. The remaining gaps are mostly release hardening and broader adapter coverage, not core dependency direction.
See docs/architecture.md.
Revision checks, atomic Postgres mutations, durable uniqueness, and retry semantics are documented in docs/consistency.md.
Postgres query pushdown and stable opaque cursor semantics are documented in docs/querying.md.
Framekit is currently assessed as a beta: 88% implemented toward a production-ready 1.0. Exact decimals, computed fields, declarative validators, ordered child records, managed attachments, localization, and typed settings are implemented. All feature issues are closed; #60 is the remaining reviewed reconciliation. See component scores, verification evidence, and deliberate production boundaries in docs/maturity-roadmap.md.
Framekit is licensed under the Apache License 2.0.
The public API reference, versioned upgrade example, and current qualification record describe the expanded framework contracts and release boundaries.