Skip to content

Repository files navigation

[WIP] Framekit

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.

What Is Included

  • 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.

Quick Start

corepack enable
corepack prepare pnpm@11.9.0 --activate
pnpm install
pnpm dev

The CRM example API runs at:

http://localhost:3000

Run the Desk UI in another terminal:

pnpm dev:desk

The 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" }

Useful Commands

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.ts

API Overview

System, 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}/transition

Framework records:

GET  /api/audit
GET  /api/outbox
POST /api/outbox/{id}/dispatch
POST /api/outbox/{id}/fail

Customization:

GET  /api/custom-fields
POST /api/custom-fields
GET  /api/views
POST /api/views

Example 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.ts

Core Concepts

DocType 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 Map

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.

Repository Layout

apps/desk          React metadata-driven admin UI
examples/crm       Nitro CRM example app
packages/*         Framework packages
docs/              Architecture, deployment, and roadmap docs

Deployment

The 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 --build

docker-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.

Environment

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 .env

Important 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:3000

Creating A New App

pnpm --filter @framekit/cli framekit create-app alpha-suite

Scaffold 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.json
  • nitro.config.ts
  • routes/[...].ts
  • src/app.ts
  • .env.example
  • .env.production.example
  • Dockerfile
  • A starter Note DocType

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.

Frontend framework templates

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:react

Swap 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.

Verification

Every iteration should pass:

pnpm audit:all

Current verification status:

  • Merged #42 baseline: pnpm audit:all passed 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.

Architecture

Framekit follows a clean architecture boundary:

  • core and runtime are 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.

Roadmap Status

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.

License

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.

About

Scaffold TS Framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages