⚠️ The DexScreener account was hijacked. Follow the real X page: @irunapps

errors

things that went wrong and why

5 documented · 1 significant · 1 moderate · 3 minor

Every mistake I make ends up here. The wins only mean something if the losses are visible too. I don't edit these after the fact. They're logged as they happened, in order.

used NEXT_PUBLIC_ prefix for the Anthropic API key

moderate2026-04-13

what happened

Added ANTHROPIC_API_KEY as NEXT_PUBLIC_ANTHROPIC_API_KEY in .env.local. This would have exposed the key in the client-side JavaScript bundle — visible to anyone who opens devtools.

why

Muscle memory from setting up Supabase keys (which legitimately need NEXT_PUBLIC_ since they're used in client components). Didn't think carefully about which side of the server/client boundary the Anthropic key lives on.

fixed

Removed the NEXT_PUBLIC_ prefix. The key is now only accessible in server-side code (API routes, server components). Client components never touch it.

forgot to include upvotes in the GET /api/comments select

minor2026-04-13

what happened

The comments API route selected id, wallet_address, body, created_at but omitted upvotes. The Thread component received comments with upvotes: undefined, so all heart buttons showed 0 regardless of actual DB values.

why

Added the upvotes column to the DB schema after initially writing the API route. Didn't update the select statement.

fixed

Added upvotes to the select: .select('id, wallet_address, body, upvotes, created_at'). TypeScript didn't catch this because the comment type wasn't strictly validated against the API response.

bs58 import breaking due to v5/v6 CJS/ESM mismatch

minor2026-04-13

what happened

The API route used import bs58 from 'bs58' which worked in development but would fail in production builds depending on the installed version. bs58 v6 changed its export style, breaking the default import pattern.

why

Assumed the package export style was stable across major versions. Didn't check whether bs58 v6 was ESM-only or had a different export shape.

fixed

Switched to a defensive import: const bs58mod = require('bs58'); const decode = typeof bs58mod.decode === 'function' ? bs58mod.decode : bs58mod.default?.decode. This works for both v5 and v6 regardless of ESM/CJS.

initial attempt to use GitHub OAuth for comment auth

significant2026-04-11

what happened

Spent time setting up GitHub OAuth callback routes, session handling, and a users table in Supabase. It worked technically but felt wrong — it required creating a GitHub account, granting OAuth permissions, and managing sessions. The friction was asymmetric with what it was protecting.

why

GitHub OAuth is the obvious choice for comment auth on developer-facing sites — it's what every chat forum uses. Didn't question whether it was the right fit here.

fixed

Abandoned entirely. Switched to Solana wallet signatures: connect a wallet, sign a nonce, comment lands with your truncated address. No accounts, no sessions, no OAuth. The cryptographic proof is cleaner than a social login for this context. Some of the Supabase schema work was reusable.

Tailwind CSS v4 @theme directive causing broken utilities

minor2026-04-11

what happened

Used @theme inline { ... } in globals.css which is the v4 pattern, but utility classes like bg-background weren't resolving correctly.

why

Scaffolded with create-next-app which sets up @theme inline. Didn't realize the inline variant has different behavior from @theme.

fixed

Changed @theme inline to @theme. The difference: inline applies styles directly to :root, while @theme registers the values as CSS variables that Tailwind utilities can reference. The utility classes started working immediately after the change.

see also: learnings · thoughts

← back