Behind the site
Colophon
How this site is built — the stack, pipelines, and engineering decisions behind adrianromo.me.
This site is a working product, not a static brochure. Everything below ships from a single Next.js codebase that I design, build, and operate myself — it doubles as a live case study of how I approach backend systems.
Stack
Next.js 14 (App Router) with TypeScript and Tailwind CSS, backed by Prisma on Postgres. Deployed on Vercel; a Docker Compose stack reproduces the full environment locally with one command.
Content pipeline
Posts and projects live in Postgres and render through a unified/remark/rehype markdown pipeline. Search uses Postgres full-text search. Open Graph images are generated per route, the RSS feed and sitemap are built from the same data, and the resume PDF is rendered server-side with PDFKit.
AI assistant
The chat widget is a retrieval-augmented assistant: site content is chunked and embedded into pgvector, retrieved per question, and answered with OpenAI models. It ships with prompt-injection defenses, per-IP and per-visitor rate limits, a daily token budget, and automated re-indexing via cron.
Internationalization
English, Spanish, and German. Source content is written in English; an LLM translation pipeline generates the other locales and detects staleness with content hashes. Every page emits canonical and hreflang metadata.
Security
A locked-down Content-Security-Policy (per-request nonces on the admin surface), hardened security headers, Zod validation at every boundary, Redis-backed rate limiting, a honeypot-protected contact form, and an admin area behind credentials plus WebAuthn passkeys.
Operations
Plausible provides cookie-less, privacy-friendly analytics. CI runs linting, formatting, type checks, and tests on every commit. Database migrations deploy automatically with each release.