How this is built.
A living page, kept current. The long version — every decision and the reasoning behind it — is in the post, which is dated and will age. This will not.
The stack
- Framework
- Next.js 16, App Router, React 19
- Language
- TypeScript, strict, no any
- Styling
- Tailwind CSS 4
- Database
- Neon Postgres with pgvector
- Hosting
- Vercel
- Package manager
- Bun
- Search
- Hybrid — vector plus keyword, fused by rank
- Comments
- Not open yet
Why the search works the way it does
Every essay is chunked, embedded, and stored in Postgres. A query runs two searches at once — one over the embeddings for meaning, one over the text for wording — and the two ranked lists are fused. Pure vector search misses a post when you remember the exact phrase; pure keyword search misses it when you only remember the idea. Each result on the lab page says which half caught it.
What the stages mean
Posts carry a stage instead of pretending every piece arrived finished. A digital garden grows unevenly; the label says how much weight to put on a given piece.
- Seedling
- A thought I am still having. Expect to disagree with it later.
- Budding
- The argument holds, the edges do not.
- Evergreen
- I stand behind this and keep it current.
Rules I kept
- No stock photography passed off as my own. The photography page stays empty until there are real photographs on it.
- No metric without a method. If a number cannot be sourced it does not go on the page.
- Nothing ships that has not been run. Rendered, not read.