Personal website of Daniel Castro. Static-first Next.js app, hosted on Vercel.
- Next.js 16 (App Router) and React 19
- TypeScript (strict)
- Tailwind CSS v4
- Biome (lint and format)
- MDX loaded from
content/inlib/content(gray-matter, Zod,next-mdx-remote) - Vitest and Testing Library
- Playwright (
chromium,mobile, andwebkit) - Vercel
Requires pnpm 11.5.2 and Node.js 24 (.nvmrc and engines.node 24.x).
pnpm install
cp .env.example .env
pnpm devEnvironment variables are optional; the site runs locally without them. NEXT_PUBLIC_POSTHOG_KEY enables analytics only in Production (NEXT_PUBLIC_VERCEL_ENV=production); see the gate in lib/analytics.ts. The PostHog host is fixed in code. Privacy limits and the event list live in docs/analytics.md.
pnpm dev— Next.js development serverpnpm build— production buildpnpm start— serve the production buildpnpm test— unit tests (Vitest)pnpm test:e2e— Playwright. Untagged tests run inchromium(Desktop Chrome).@mobileruns inmobile(Pixel 7).@smokeruns inwebkit(Desktop Safari).pnpm lint— Biome checkpnpm format— Biome check and writepnpm typecheck—tsc --noEmit
Install Chromium and WebKit once before the first local E2E run. CI uses the Playwright image, which already includes the browsers, and does not install them:
pnpm exec playwright install chromium webkit
pnpm test:e2e
pnpm test:e2e -- --project=mobile
pnpm test:e2e -- --project=webkitpnpm test:e2e builds and starts the app (pnpm build && pnpm start) via Playwright's webServer.
app/— Next.js App Router (routes, layouts, and styles)content/— source content (posts/,community/), loaded bylib/contentpublic/— static files, includingmedia/for posts, personal photos, icons, illustrations, and documentslib/— shared TypeScript modulescomponents/— UI by responsibility:views/(pages),layout/(shell, header, footer, container),mdx/(MDX blocks),ui/(controls and icons). Providers and route infra stay at the root (theme-provider,interface-language-provider,json-ld,route-error-boundary).e2e/— Playwright tests (chromium,@mobile,@smoke)
@/foo resolves to <repo>/foo via compilerOptions.paths in tsconfig.json. Example: @/lib/site → lib/site.ts. There is no ~/* alias.
Trunk-based: feature branch → pull request → main → Vercel. Direct pushes, force-pushes, and deleting main are blocked. The GitHub Actions check ci must be green before merge. Reviews are not required in V1 (solo project).