orfc
The orfc Handbook

The orfc Handbook

orfc handbook

Everything we know about shipping orfc.

A working handbook for the people building, deploying, and reviewing on orfc — five sections, in-page navigation, no link jumping. Click an item in the sidebar to switch.

Sections
5
CLI
v0.4.0
Tests
70 passing
Latency
42ms p50

What's in here

Architecture. How the CLI, web app, sanitizer, and Postgres talk to each other — system diagram, stack, the four invariants we don't break.

API reference. Every endpoint orfc exposes — plans, comments, notify — with auth, status codes, and an end-to-end example.

Deployment. The pipeline from git push to orfc.dev, env vars, and the migration trip-wire that bit us once.

Changelog. Recent @orfc/cli releases.

"Documents that ship don't need to be markdown. orfc treats HTML as a first-class citizen — render it sanitized, preserve the author's theme, comment on it the same way you would on prose."

— design note · v0.4 release
orfc handbook · 02

Architecture

A Next.js web app, a Postgres store, a TypeScript CLI, and a single sanitization choke-point that keeps user-authored HTML safe to render.

@orfc/cli orfc push / pull / edit Node 18+ · Commander Browser /p/[slug] · /dashboard React 18 · Next App @orfc/web Next.js 14 · Vercel /api/plans /api/comments /api/notify sanitize-html render-time sanitization Postgres (Neon) Drizzle ORM plans plan_versions comments

Stack

Frontend. Next.js 14, React 18, Tailwind. App Router with server components for the public read path, client components for the editor and comment UI.

Database. Postgres on Neon serverless, JSON-file fallback in local dev so the CLI stays demo-able offline.

CLI. Node 18+, Commander, TypeScript. Single binary at @orfc/cli. Reads ~/.orfc/config.json for credentials.

Auth + mail. NextAuth, Resend, Slack webhooks. Email-OTP login for both web and CLI.

Invariants

1. Every write goes through /api/plans. The CLI is a thin client.

2. Updates always snapshot the previous version into plan_versions — nothing is overwritten in place.

3. Sanitization happens at render, not at write. Stored content is the author's exact bytes; what the browser sees is filtered.

4. Comment anchors are DOM-based (block index + text snippet), so they survive the markdown ↔ HTML render-mode change.

orfc handbook · 03

API reference

Every endpoint orfc exposes. The CLI is built on these — there's nothing it can do that you can't reach with curl and a Bearer token.

Auth

Web requests use a NextAuth session cookie. CLI requests use a Bearer token issued by orfc login:

curl https://orfc.dev/api/plans -H "Authorization: Bearer orfc_live_…"

Plans

MethodPathDescription
GET/api/plansList the caller's plans. Optional ?folder= and ?tag= filters.
POST/api/plansCreate a plan. Body: title, content, contentType, accessRule, folderPath, tags.
GET/api/plans/{id}Fetch one plan. 401/403 if access rules don't match.
PUT/api/plans/{id}Update. Optimistic concurrency via expectedVersion.
DELETE/api/plans/{id}Author-only. Cascades.
GET/api/plans/{id}/versionsList previous versions.
GET/api/plans/{id}/diffLine-LCS diff. 5,000-line cap.

Comments & notifications

MethodPathDescription
GET/api/plans/{id}/commentsList comments. Polled every 15s.
POST/api/plans/{id}/commentsAdd a comment with anchorText + block index.
PATCH/api/plans/{id}/comments/{cid}Toggle resolved. Plan author or comment author only.
POST/api/notifyEmail + Slack notify. URL must match app domain.

Example: publish HTML

curl https://orfc.dev/api/plans \
  -H "Authorization: Bearer $ORFC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q2 platform plan",
    "content": "<h1>orfc Q2 …</h1>",
    "contentType": "html",
    "accessRule": "anyone"
  }'
orfc handbook · 04

Deployment

From git push to orfc.dev. Vercel handles build + edge, Neon handles Postgres, schema migrations are still a manual step (until they're not).

step 1 git push main · feat/* step 2 Vercel build turbo · ~90s ⚠ MANUAL db migrate npm run db:push step 4 Edge deploy atomic step 5 Smoke check /dashboard 200 step 6 Live orfc.dev

Environment variables

KeyRequiredUsed by
DATABASE_URLprodNeon connection string. Empty in dev → JSON file fallback.
NEXTAUTH_SECRETallSession signing.
NEXTAUTH_URLprodCallback URL base. https://orfc.dev in prod.
RESEND_API_KEYprodOTP email + review notifications.
APP_URLoptURL embedded in API responses.

Migration trip-wire

Schema-touching PRs need db push before merge, not after. Vercel auto-deploys main on merge, so a code-and-schema PR that skips the db step ends up deployed against an old schema and the API blows up everywhere. Until the migration is wired into the deploy pipeline, run it first.

Running a migration

# Option A — drizzle migrate (tracks applied migrations)
npm run db:migrate

# Option B — drizzle push (diffs schema.ts vs DB, no journal)
npm run db:push

# Option C — Vercel-managed env
vercel env pull .env.production.local
npx -y dotenv-cli -e .env.production.local -- npx drizzle-kit migrate
orfc handbook · 05

Changelog

Recent releases. Versions track @orfc/cli; the web app rolls forward continuously off main.

v0.4.0
2026-05-10
CURRENT

HTML content type, folder tree, theme toggle

CLI orfc push design.html detects content type from extension or sniff. HTML docs render through sanitize-html (after a brief detour through isomorphic-dompurify), inline SVG and styles preserved. Dashboard sidebar with folder tree + tag chips. --folder / --tag on push. Theme toggle in plan header for every viewer. Comment popover shows the snippet. Forced ::selection highlight.

v0.3.0
2026-04-28

Security pass + test infrastructure

OTP via crypto.randomInt. SSRF defense on Slack webhooks. Plan GET enforces access rules. CSP + baseline headers. Vitest across cli + web with 63 security-focused tests on day one. CLI push --update applies --access / --viewers.

v0.2.0
2026-04-12

Inline comments + version history

Highlight any text → leave a threaded comment, anchored to the snippet. Real-time poll for new comments (15s). Every push --update snapshots the previous version with diff view. Web editor with Cmd+S save, replacing the CLI-only edit path.

v0.1.0
2026-03-22

Initial public release

CLI: push, pull, list, delete, login. Markdown render via react-markdown + remark-gfm. Mermaid block support. Access rules: authenticated, anyone, viewer-list. Postgres on Neon. OTP login via Resend.