Full-stack architecture from zero.
A monorepo with four independent sub-projects: static portfolio, headless storefront, e-commerce backend, and CMS. Each with its own stack, pipeline, and deployment. All built from scratch with Claude Code as copilot.
Four pieces, one ecosystem.
CuevasLab is a monorepo with four sub-projects that work independently but share a domain, visual identity, and pipelines. The separation allows each piece to evolve at its own pace without blocking the others.
web/ — Portfolio
Static HTML + CSS + vanilla JS. No framework. Custom design system with dark/light mode, i18n (EN/ES), contact form with reCAPTCHA, and mini-game arcade. Deployed on Vercel.
storefront/ — Store
Next.js with App Router and TypeScript. Headless storefront connected to Medusa.js. 6 languages, 300+ tests (Vitest + Playwright). Server Components by default. Deployed on Vercel with staging at preprod.shop.cuevaslab.es.
shop/ — Backend
Medusa.js (Node.js) as headless e-commerce engine. PostgreSQL 15 + Redis 7. Docker Compose with Nginx reverse proxy and Let's Encrypt SSL. Admin at shop-backoffice.cuevaslab.es. Deployed on Hetzner VPS.
cms/ — Content
Strapi v5 as headless CMS. Manages homepage content (5 blocks, 6 languages) and static page layouts with dynamic zones. Docker Compose on the same VPS as shop/. Admin at cms.cuevaslab.es.
Two providers, zero unnecessary complexity.
The infrastructure is split in two: Vercel for static/SSR applications and a Hetzner VPS for services that need Docker and persistence. No Kubernetes, no orchestrators — Docker Compose is enough for this scale.
- web/ — Static portfolio
- storefront/ — Next.js SSR/ISR
- Edge Functions (CV gate)
- Serverless Functions (contact, arcade stats)
- Vercel Analytics + KV (Upstash Redis)
- shop/ — Medusa.js (Docker)
- cms/ — Strapi v5 (Docker)
- PostgreSQL 15 + Redis 7
- Nginx reverse proxy + Let's Encrypt SSL
- Ubuntu — SSH deploy from CI
Domains
cuevaslab.es
Main portfolio — Vercel
shop.cuevaslab.es
Production storefront — Vercel
preprod.shop.cuevaslab.es
Staging storefront (develop branch) — Vercel
shop-backoffice.cuevaslab.es
Medusa.js admin — Hetzner VPS
cms.cuevaslab.es
Strapi admin — Hetzner VPS
Five pipelines, fully automated.
Each sub-project has its own GitHub Actions pipeline, triggered by path filters. No monolithic pipeline — each change only triggers what it affects. Vercel auto-deploy is disabled for storefront; everything goes through CI.
main
web/**
npm ci → build → Vercel deploy
main
storefront/**
validate → Vercel deploy (prod) → E2E → Lighthouse
develop
storefront/**
validate → Vercel deploy → alias preprod → E2E → Lighthouse
main
cms/**
Docker build+push → SSH deploy VPS
main
shop/**
Docker build+push → SSH deploy VPS
Merge gates: nothing reaches production without passing checks.
Three strict gates protect the main branch. The flow follows Gitflow: feature branches → develop → release → main. Each step has a quality barrier that must be cleared before moving forward.
Green local tests
Before merging to develop: npm test, tsc --noEmit, and next lint must pass. If they fail, fix first. No exceptions.
Green CI on develop
Before merging to main: the staging pipeline must have passed on the latest develop commit. This includes deploy, E2E, and Lighthouse. The only exception is hotfixes.
Mandatory version tag
Every merge to main carries a semver tag (vX.Y.Z). This enables historical traceability of metrics: unit tests, E2E, and Lighthouse per release.
Technologies chosen with purpose.
Every technology decision has a reason. I didn't pick what's most popular, but what best fits the project goals: learn, demonstrate full-stack capability, and maintain it as a one-person team.
Frontend
- Next.js — App Router, Server Components, ISR
- TypeScript — type safety across the entire frontend
- Vitest — 290+ unit tests
- Playwright — 40+ E2E tests
- Tailwind CSS — utility-first styling
Backend
- Medusa.js — headless e-commerce engine
- PostgreSQL 15 — primary database
- Redis 7 — cache and sessions
- Strapi v5 — headless CMS
- Node.js — backend runtime
Infrastructure
- Docker Compose — VPS orchestration
- Nginx — reverse proxy + SSL
- Vercel — static + SSR deploy
- GitHub Actions — 5 CI/CD pipelines
- Hetzner — Ubuntu VPS
Observability
- Vercel Analytics — web metrics
- Google Tag Manager — event tracking
- Microsoft Clarity — session recordings
- Lighthouse CI — performance metrics
- Custom dashboard — historical trends
Conscious trade-offs.
Every architecture is a set of trade-offs. These are the most relevant decisions I made and why.
Monorepo without monorepo tools
I don't use Turborepo or Nx. With 4 independent projects and path triggers in CI, the extra complexity isn't justified. Each sub-project has its own package.json and lifecycle.
Docker Compose instead of Kubernetes
For a one-person project, K8s is over-engineering. Docker Compose + SSH deploy is simple, predictable, and sufficient. If the project scaled to a team, migrating to K8s would be a natural step.
Vercel auto-deploy disabled
All deployment goes through GitHub Actions. This allows including validation (tsc, lint), E2E, and Lighthouse in the pipeline before code reaches production. Full control over what gets deployed and when.
Static portfolio, no JS framework
The portfolio doesn't need React or Next.js. HTML + CSS + vanilla JS is faster, simpler to maintain, and proves that not everything needs a framework. The design system lives in a single CSS file.
Staging on Vercel, not on VPS
The staging storefront uses a Vercel alias (preprod.shop.cuevaslab.es) instead of a second VPS. Zero cost, same infrastructure as production, and the CI pipeline manages it automatically.
Let's talk
Drop me a note — questions, feedback, or just want to say hi.