Adrian RomoAdrian Romo

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.

Designed, built, and maintained by me. GitHub