Personal portfolio built with Next.js 16, React 19, TypeScript, Tailwind CSS 4, and shadcn-ui. The project now runs on the Bun toolchain.
- Next.js 16 (pages router) with React 19
- Tailwind CSS 4 with shadcn-ui + Radix UI primitives
- React Hook Form, Zod validation, Resend mail API
- Bun 1.3 for scripts, installs, and development workflow
- Bun v1.3 or newer
bun install
bun run dev # starts Next.js and exposes it at https://lyra.tailb44a3.ts.net/bun run dev– start the Next.js dev server and expose it through Tailscale Serve athttps://lyra.tailb44a3.ts.net/bun run dev:local– start the Next.js dev server without configuring Tailscale Servebun run dev:tailnet:status– show the active Tailscale Serve configurationbun run dev:tailnet:off– disable the HTTPS proxy on port 443bun run lint– lint the project with Oxlintbun run test– run unit tests with Vitestbun run test:run– run the unit test suite once for CI/local verificationbun run typecheck– run TypeScript without emitting build outputbun run check– run lint, typecheck, unit tests, and a production buildbun run build– create a production buildbun run start– serve the production build locally
- Build command:
bun run build - Output directory:
.next - Required env:
RESEND_API_KEY(and optionalCONTACT_TO_EMAIL/CONTACT_FROM_EMAILfor contact form delivery) - Optional env:
CONTACT_RATE_LIMIT_ENDPOINTandCONTACT_RATE_LIMIT_ENDPOINT_TOKENto delegate contact-form rate limiting to a durable service. The endpoint receives{ key, maxRequests, windowMs }, must return{ allowed: boolean }, and must answer within 2 seconds or the request fails closed. CONTACT_RATE_LIMIT_KEY_SECRETis required wheneverCONTACT_RATE_LIMIT_ENDPOINTis set; without it the contact API fails closed instead of sending client-address hashes derived from a public fallback. See.env.examplefor the full variable list.