Kapable starter template: Tenant CRM / Records (auth, data, store, SSE)
- TypeScript 85.6%
- CSS 10.8%
- JavaScript 3.6%
Forked from kapable-starter-kit. Demonstrates the data-app credential model (server-only KAPABLE_ORG_KEY sk_live_ via kapableOrg factory): - kapable-data: crm_contacts + crm_deals tables (auto-bootstrapped), full CRUD, search, deal stages with semantic-token pills - kapable-store: crm-attachments bucket, server-proxied upload + download - SSE: /api/stream proxy holds the org key, browser EventSource glows live rows - impeccable UI: records table, detail drawer, empty state, errors->toast, a11y Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012A2i4rdsaVGinMTZBa8Ls7 |
||
|---|---|---|
| app | ||
| public | ||
| .gitignore | ||
| .npmrc | ||
| bun.lock | ||
| DESIGN.md | ||
| package.json | ||
| react-router.config.ts | ||
| README.md | ||
| seed.ts | ||
| tsconfig.json | ||
| vite.config.ts | ||
Kapable Starter Kit
The on-brand fork-point for Kapable v2 apps. Every starter/template app forks this repo, then builds its own routes on top.
What you get out of the box:
- React Router 7 SSR + TypeScript, with the
/healthresource route the deploy pipeline gates on (keep it). - Kapable theme system — the canonical
--kp-*token set fromkapable-theme.css,[data-theme="dark|light"]on<html>, FOUC-free first paint (the in-<head>script +kapable-theme.js), and a theme toggle wired towindow.KapableTheme.cycle(). Tailwind v4 is bridged to the same tokens (bg-surface,text-fg,border-line,text-accent, …). @kapable/sdkwired server-side inapp/lib/kapable.server.tswith explicit per-service base URLs (never the bareapi.kapable.aidefault for everything). Session (kses_) read from the request; tokens never reach the client bundle.- Error → toast on every fetch (sonner), a skip-to-content link, a
global
:focus-visiblering, 44px touch targets, and a branded error boundary.
Develop
bun install
bun run dev
Build + run (what the platform does)
bun run build
bun run start # react-router-serve on :3000
Calling the SDK
All SDK calls are server-side (loaders/actions). Always pin the client to the service you're calling — each has its own base URL:
import { kapable } from "~/lib/kapable.server";
export async function loader({ request }) {
const data = kapable("data", { request }); // data.kapable.ai
const { data: rows } = await data.data.listRows("my_table");
return { rows };
}
| Service | Base URL | Notes |
|---|---|---|
| auth, ai, data, comms, board, billing, store, harbor | dedicated subdomain | own Caddy host block |
| wiki, knowledge, secrets, warrant, projects, herald | https://api.kapable.ai |
path-routed gateway (no dedicated subdomain — the subdomain falls through to launchpad) |
api.kapable.ai reaches every service via /v1/* and is the safe universal
choice. Prefer the caller's kses_ session over a bare sk_live_ for writes.
Add a route
- Create
app/routes/<name>.tsx. - Register it in
app/routes.ts— RR7 404s unregistered routes silently.
Theme tokens
Defined in public/kapable-theme.css. Use var(--kp-bg), --kp-surface,
--kp-text, --kp-accent, --kp-border, --kp-danger/success/warn/info, or
the Tailwind aliases. A single data-theme flip recolors everything.