Full-stack · monorepo · portfolio
Two SaaS apps, built from schema to deploy, by one engineer.
Boardly, a realtime collaborative kanban with DnD, optimistic locking, and a static CSP (rolled back from nonce + strict-dynamic per ADR-0040 to fix Vercel platform-script hydration; grade A on securityheaders.com). Knowlex, a multi-tenant RAG (Auth.js + Membership demo allow-list per ADR-0061, v0.5.12) over pgvector HNSW with streamed Gemini 2.5 Flash and numbered citations (hybrid retrieval Postgres FTS + RRF behind HYBRID_RETRIEVAL_ENABLED per ADR-0063, v0.5.14; live demo currently EMERGENCY_STOPPED per ADR-0067 — BYOK runbook in root README). Both in one Turborepo, deployed on Vercel Hobby, zero dollars per month.
Boardly
Realtime collaborative kanban
- Drag-and-drop with LexoRank positions + optimistic locking via version column
- Pusher Channels for realtime fanout with best-effort side-effect policy
- Token-hashed invitations + three-layer rate limit + @mentions + notifications bell
- Full ⌘K command palette, WIP limits, labels, assignees, due dates, activity log
Knowlex
Grounded AI knowledge retrieval
- Paste text → chunked + embedded (gemini-embedding-001, truncated to 768-dim) → stored in pgvector
- Ask a question → cosine-kNN retrieval → Gemini 2.5 Flash answer with numbered citations
- Env-guarded: missing GEMINI_API_KEY returns a clean 503, never a crash — corpus stays intact
- Standalone apps/knowledge Next app, own Prisma migration, own Vitest, own Vercel project
Ten decisions worth drilling into
Each of these is captured as a one-page Architectural Decision Record in docs/adr/. The author can whiteboard any of them in an interview.
Four-tier RBAC
OWNER > ADMIN > EDITOR > VIEWER via a single roleAtLeast comparator
Optimistic locking
version column + updateMany, bumped client-side on success
LexoRank positions
Reorder touches one row, not N
Token-hashed invitations
Only SHA-256 stored; accept requires email match
3-layer rate limit
Global + per-workspace + per-user, each with distinct error codes
Full-replace set semantics
PUT labels/assignees; diffs + side-effects for additions only
Cross-workspace guards
Label / assignee writes validated against the card's workspace
Best-effort side effects
Log / broadcast / email fail without aborting the business write
URL as state
Filters + search in query string — shareable, refresh-safe, composable
Env-guarded integrations
Pusher, Resend, Gemini all degrade gracefully when unset
Tech stack
- Next.js 16
- TypeScript 5
- React 19
- Prisma 7
- PostgreSQL (Neon)
- Auth.js v5 (JWT)
- Pusher Channels
- Vercel AI SDK
- Gemini 2.5 Flash
- cmdk (⌘K)
- @dnd-kit
- Tailwind 4
- Vitest
- Playwright
- Resend
- Vercel Hobby
Every service above is free-tier; no credit card on file. The apps degrade gracefully when an integration key is missing.