How this site was built — the decisions and the reasoning, including the ones I got wrong and undid.
Auth.js v5 was in extended beta; Lucia deprecated March 2025. Better Auth covers the admin surface, which is the only part of this site that needs a login.
SQL-close query builder, no Rust binary engine, TypeScript-native schemas with a native Better Auth adapter. The tag-containment queries behind the topic pages are easier to write close to the SQL.
This site used to gate projects per-recruiter through a userProjectAccess junction table — Recruiter A sees X and Y, Recruiter B sees Y and Z. It worked, and it was the wrong idea: it made a personal site into something you had to be admitted to. It’s gone. Everything here is public.
LinkedIn’s API is effectively closed for this use case. Instead, I manually curate posts and Claude Haiku auto-tags each with 3–7 semantic tags stored as PostgreSQL TEXT[] with a GIN index.
Short build log entries and curated feed items stay fresh with 2–4 hours per month. Traditional blogging demands 8–32 hours per post — unsustainable alongside a full-time role.
Next.js 16
App Router, RSC
TypeScript
Strict mode
PostgreSQL
Railway managed
Drizzle
SQL-close query builder
Better Auth
admin surface only
shadcn/ui
Radix + Tailwind
Tailwind CSS v4
CSS-based config
React Hook Form
+ Zod validation
Framer Motion
Viewport-triggered
Resend
HTTP API, no SMTP
MDX
@next/mdx
Railway
Standalone output
Brandon Grotesque for headings, Brandon Text for body copy, and JetBrains Mono as a monospace accent for tech labels, metadata, and code snippets.
Dark-first and deliberately warm — a near-black umber ground and bone-white text, with one muted sage accent plus clay and sand as earthy supporting tones. Defined in OKLCH as design tokens.
Framer Motion with all durations under 500ms. Staggered fade-in on scroll, subtle hover micro-interactions, and animated number counters. Respects prefers-reduced-motion.
All database queries are centralized in a Data Access Layer (DAL). Authorization checks live inside DAL functions — not scattered across route handlers or components. This means permission logic is defined once and enforced everywhere.
The source lives in a private repo — licensed fonts and gated case-study material are tracked in it, so I can't publish it wholesale. If you're curious how any of it works, ask me and I'll walk you through the code. My open-source projects are on GitHub.
My GitHub