Active · May 25, 2026
daeseon.ai
This site. Bilingual blog + private admin dashboard for drafts and distribution.
- Role
- Solo
- Stack
- Next.js 15 · TypeScript · Tailwind · MDX · Vercel
The blog you're on. Built from scratch so the constraints (writing tone, admin features, distribution) are mine, not a template's.
What it does
- Bilingual posts (EN default, KO at
/ko) withtranslationKeycross-linking. - MDX with Format A (multi-register) and Format B (project recap) writing conventions baked into the editor.
- Private admin (
/admin) with password gate, JWT session cookie, post editor that commits to GitHub. - RSS per language, hreflang sitemap, robots-blocked admin routes.
Why
I've been writing in private docs for years and not shipping any of it. This site exists to break that loop.
What's still missing
- Real per-post view analytics (deferred until there's traffic to look at).
- Crosspost wiring — webhook slot exists, target tool is the separate
crosspost-botproject.
Project log
Chronological record of troubleshooting, retros, and updates while building this.
MDX broke on `$\mathbb{R}^d$` with `R is not defined`
TroubleshootMay 25, 2026 · 1 min
Curly braces in math notation are JSX expressions to MDX. The build crashed on a sample embeddings post.
Stack and storage: Next.js 15 + GitHub commit-as-database
Tech retroMay 25, 2026 · 1 min
Why I picked Next.js 15 + Vercel + GitHub Contents API for storage instead of a database.
Why I split content into post / note / knowledge / log
Tech retroMay 26, 2026 · 2 min
One bucket for everything fails three different audiences. Four content types with different visibility defaults each.
EROFS on every Vercel publish — production fs is read-only
TroubleshootMay 26, 2026 · 2 min
Admin publish crashed with EROFS. Cause: I wrote to disk first, then committed to GitHub. Production fs is read-only.
Why publish-to-live used to take 60s, and how I got it to 3-5s
Tech retroMay 26, 2026 · 2 min
Production fs is a frozen build snapshot. Reading content through fs.readFile meant 60s of staleness per publish. Moved reads to GitHub Raw.
Hobby photos on a dev portfolio: when they help and when they don't
UX retroMay 26, 2026 · 1 min
I considered a 추억-style photo gallery on /about. Decided against. Kept a small slot for conference/maker/workspace shots only.
Vercel refused to build with next-mdx-remote@5.x (CVE)
TroubleshootMay 26, 2026 · 1 min
First production build was blocked by Vercel's security scanner. Solved with a one-line dep bump.
Sidebar width: 16rem felt empty, 13rem felt cramped, 14rem stuck
UX retroMay 26, 2026 · 2 min
The hub layout (left sticky profile / right content) needed two rounds of width tuning before it stopped looking off.
Live site returned 401 to everyone (Vercel Authentication on by default)
TroubleshootMay 26, 2026 · 1 min
Production URL was unreachable until I disabled Vercel's default deployment protection. No code change.
Client component pulled node:fs into the browser bundle
TroubleshootMay 27, 2026 · 1 min
Vercel build failed with `You may need an additional plugin to handle node: URIs`. LogTimeline.tsx (client) imported lib/logs.ts (server), pulling node:fs into webpack's client bundle.
Cross-repo log aggregation: each repo keeps its own, the portfolio pulls
Tech retroMay 27, 2026 · 3 min
Added `logSourceRepo` to project frontmatter so each project's log timeline can be fetched from its own separate repo. Pull-on-demand with 30s ISR cache, no polling.
Domain typo: daseon.ai vs daeseon.ai
TroubleshootMay 27, 2026 · 1 min
Project was bootstrapped with daseon.ai (one letter short). The real registered domain is daeseon.ai. Found at Vercel domain connection time.
Image upload UX: from a tiny button to a real dropzone
UX retroMay 27, 2026 · 1 min
Admin image upload worked the whole time, but I couldn't reliably find it. Fixed the discoverability instead of the mechanism.
Designing the project-log system (this thing you're reading)
Tech retroMay 27, 2026 · 3 min
Why I added a fourth content type for project logs, dual-wrote to a machine-facing reference and a human-facing timeline, and built explicit anti-hallucination rules.
Stop hook: from reminder to enforcement (blocking + self-terminating sentinel)
Tech retroMay 27, 2026 · 3 min
The original Stop hook nudged with a systemMessage, which Claude could ignore. Upgraded to decision:block + reason with a commit-hash sentinel that terminates the loop once a log entry exists.