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 and concurrency paths covered; durable long-running saga coordination remains deferred.
@framekit/auth Password hashing, signed sessions, refresh/logout, revocation, lockout, API tokens, auth audit, user/role admin, and provider-independent login ports. Identity lifecycle and OIDC flows covered; native WebAuthn/TOTP remains deferred.
@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, atomicity, query pushdown, and executable migration paths covered; production-scale load evidence remains deferred.
@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 smoke and standalone consumer proof covered; the Desk template remains intentionally un-packaged.
@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: production-depth gates are present, while the remaining 1.0 work is operational hardening and explicit production boundaries—durable saga coordination, native MFA, load/soak evidence, deeper schema-drift detection, packaged Desk, and production secret/object-storage adapters. 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. It defaults to the local framekit password. To override it, set both FRAMEKIT_POSTGRES_PASSWORD (the raw password used by Postgres) and FRAMEKIT_POSTGRES_URL (the CRM connection URL with its password percent-encoded); for example, p@:/#ss becomes p%40%3A%2F%23ss in the URL. For production, provision unique credentials through the platform secret manager and point DATABASE_URL and REDIS_URL at private or managed services rather than exposing the bundled stores.

When DATABASE_URL is set, the CRM example 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=postgresql://framekit:framekit@localhost:5432/framekit
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

It does not scaffold the React Desk. Run the repository Desk separately or build a frontend against @framekit/sdk; a packaged Desk template is deferred until its assets, configuration, and upgrade contract can be shipped as one supported unit.

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.

About

Scaffold TS Framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages