How this site is built
This site is a demo too: a static site on Cloudflare, an API on the edge and demos that really run. Every piece has a reason I wrote down. Here's the map, why it's built this way and how I know it works.
The architecture
Tap or focus a piece to see what it does and where it was decided.
Your browser
Pages from Cloudflare's network, and /api/* on the same domain
Cloudflare
SQL over HTTPS and Resend's API
Data and email
The browser calls them directly, with CORS
Render, free plan
Design only, outside production
The exported workflow is built into the site
Static site
Cloudflare Pages
Astro renders every page to HTML at build time, in Spanish and English. The interactive parts are Preact islands that load only their own JavaScript. Cloudflare Pages serves it from its network, for free, with a strict Content Security Policy (CSP): no unsafe-inline, no unsafe-eval.
Edge API
Hono on Pages Functions
The contact form, the quote calculator, the admin login, the assistant, the agent and the automation answer at /api/*, on the site's own domain: free, with no cold start and no CORS. The free plan gives about 10 ms of CPU per request, so no expensive password hashes: the admin panel signs in with a one-time code.
Decided in
Workers AI
Gemma 4
The assistant, the code reviewer and the agent with tools use Gemma 4 through the Workers AI binding: free (10,000 neurons a day), with no API key or card. A shared daily limit protects that quota, and the agent calls its tools with native function calling.
@cf/google/gemma-4-26b-a4b-it
Decided in
Turnstile
Bot check
It checks that there's a person on the other side. It protects the contact form, the admin login, the assistant and the live automation. The edge verifies every token with Cloudflare, and if Turnstile doesn't answer, the API returns 503 instead of letting the request through.
Decided in
Neon Postgres
Over HTTP
It stores leads, admin sessions, quotas and the access log. Every statement travels as an HTTPS request with Neon's serverless driver and Drizzle, with no TCP connection to open. Whatever must commit together goes in a single statement or a batch.
Decided in
Resend
It sends the notice for every new lead and the admin login's one-time codes (6 digits, 10 minutes, 5 attempts). Locally, the same emails land in Mailpit.
Decided in
API Playground
NestJS on Render
NestJS is the core of my profile and Cloudflare Workers can't run it reliably, so it lives in a Docker container on Render's free plan. It sleeps when idle and the demo tells you while it wakes up. It answers in the page's language.
Decided in
Python migrator
FastAPI on Render
It gives the same result as the in-browser migrator and adds what the browser doesn't do well: Excel, bigger files and encoding detection. Everything stays in memory, no files are stored. The contract is Zod, exported to JSON Schema, and a parity test compares Python with TypeScript.
Decided in
n8n
To design the workflow
The "Contact → qualified lead" workflow is designed in n8n and exported to the repository, but n8n doesn't run in production: the edge runs it with the same rules in under 1 ms. A recording of a real n8n (2.45.2) checks in CI that both answer exactly the same.
Decided in
Key decisions
Every decision is written down with its context and the alternatives I ruled out. These are the ones you notice most.
DEC-002Supply chain: exact versions and 14 days
Exact versions and nothing published less than 14 days ago, in Python with uv too. Only a security patch can skip the rule, and it gets recorded.
Read DEC-002 on GitHub (in Spanish) (opens in a new tab)DEC-003Monorepo and stack
pnpm and Turborepo, Astro with Preact islands, NestJS and FastAPI: it's the stack I really work with, and every piece is part of what the site proves. Next.js was ruled out: more JavaScript in the browser, with no gain for a mostly static site.
Read DEC-003 on GitHub (in Spanish) (opens in a new tab)DEC-014A hybrid API
What every visitor uses runs on Cloudflare Pages Functions: free, with no cold start and no CORS. NestJS stays on Render only for its demo, where waiting for it to wake up is fine.
Read DEC-014 on GitHub (in Spanish) (opens in a new tab)DEC-017Its own login for the /admin panel
Email and a one-time code instead of a password, because a secure hash doesn't fit in Workers' free CPU. Short-lived tokens in HttpOnly cookies, with rotation and reuse detection.
Read DEC-017 on GitHub (in Spanish) (opens in a new tab)DEC-018A free model for the AI Assistant
Gemma 4 on Workers AI is free and asks for no key or card. The Claude adapter is still in the code: with an Anthropic key, the assistant switches without touching anything else.
Read DEC-018 on GitHub (in Spanish) (opens in a new tab)DEC-019A strict Content Security Policy
Hashes of every script and style in a <meta> tag, with no unsafe-inline or unsafe-eval. An E2E test opens the pages and the demos and fails if the browser reports a violation.
Read DEC-019 on GitHub (in Spanish) (opens in a new tab)DEC-023The automation workflow runs on Cloudflare; n8n is for designing it
n8n on Render's free plan took 70 to 112 s to wake up. Now it designs the workflow and the edge runs it, with a parity test against a real n8n.
Read DEC-023 on GitHub (in Spanish) (opens in a new tab)DEC-024The site in English
The whole site in English, demos included, under /en/ with translated paths. No redirect based on the browser: search engines see both versions and no Spanish URL changed.
Read DEC-024 on GitHub (in Spanish) (opens in a new tab)DEC-027The API talks to Neon over HTTP
Opening TCP and TLS to Neon on every request cost more than the query. With the HTTP driver every statement is a request; in exchange, anything atomic goes in one statement or a batch.
Read DEC-027 on GitHub (in Spanish) (opens in a new tab)DEC-029A share image for every page
Every page has its own share image, drawn at build time with Satori and sharp from its own tags: it costs nothing per visit and always says what the page says.
Read DEC-029 on GitHub (in Spanish) (opens in a new tab)DEC-031The /admin/ panel as a lead CRM
The admin panel tracks every lead: statuses with a history written in the same statement, internal notes, filters in the URL and a CSV protected against formula injection.
Read DEC-031 on GitHub (in Spanish) (opens in a new tab)DEC-032Visitors by /64 network and the limits from the OWASP review
The OWASP review left rules for every new route: bodies up to 64 KB, IPv6 limits per /64 network and logs without personal data.
Read DEC-032 on GitHub (in Spanish) (opens in a new tab)DEC-033An AI agent with tools in the Lab
Native function calling with four read-only tools and limits per run. Prices can only come from a tool.
Read DEC-033 on GitHub (in Spanish) (opens in a new tab)
Quality in numbers
These numbers come from the repository itself every time the site builds, so they don't go stale. The ones that depend on a measurement say when they were measured.
Automated tests
2,312test casesin 213 files; CI runs them on every push and pull request
- WebsiteVitest, 113 files1,280
- E2E and accessibilityPlaywright and axe, 38 files325
- Edge APIVitest with PGlite, 37 files447
- ContractsVitest, 10 files105
- API PlaygroundVitest, 7 files62
- Workflow engineVitest, parity with n8n, 2 files27
- Python migratorpytest, 6 files66
Counted in the code at build time. A case that repeats for each page, language or data row counts once, so more of them run: the E2E tests go through every page of the build on mobile and desktop.
Lighthouse
- Performance on mobile
- 98–99
- Performance on desktop
- 100
- Accessibility, best practices and SEO
- 100
- Layout shift while loading (CLS)
- 0.011
Measured on November 8, 2026 against aimweb-9hc.pages.dev: 13 pages in both languages, median of 3 runs, Lighthouse 13.5.0. Not counting /admin/, which is private and not indexed.
Latency
- 0.13 s
- Median of the API in production, with Neon over HTTP. Before, 1.6 to 2.5 s per request.Measured on November 8, 2026, DEC-027: The API talks to Neon over HTTP (opens in a new tab)
- < 2 s
- From click to result in the Live automation: the API answers in about 40 ms, Turnstile included, and the workflow runs in under 1 ms.Measured on November 7, 2026, DEC-023: The automation workflow runs on Cloudflare; n8n is for designing it (opens in a new tab)
Security review
0 critical or high findings
- 4 medium, 3 fixed
- 8 low or informational, 2 fixed
A review against the OWASP Top 10:2025 of the edge, the website, both Render APIs and the supply chain, on November 8, 2026. Every fixed finding has a test that failed before the change.
Read the full report (in Spanish) (opens in a new tab)Stack
The versions come from the repository's manifests at build time: always exact (DEC-002).
- Website
- Astro 7.3.8
- Preact 10.29.8
- Tailwind CSS 4.3.3
- TypeScript 5.9.3
- Satori 0.63.2
- sharp 0.35.5
- Edge API
- Cloudflare Pages Functions
- Hono 4.13.13
- Drizzle ORM 0.45.4
- @neondatabase/serverless 1.2.0
- Zod 4.6.7
- jose 6.2.13
- AI
- Cloudflare Workers AI
- Gemma 4
- Demos on Render
- NestJS 12.2.0
- FastAPI 0.161.1
- Python 3.12
- uv
- Docker
- Automation
- n8n 2.45.2
- Testing and quality
- Vitest 5.0.3
- Playwright 1.63.0
- axe-core 4.14.0
- PGlite 0.5.11
- pytest
- Lighthouse 13.5.0
- Biome 2.5.15
- Monorepo
- pnpm 10.26.1
- Turborepo 2.11.7
Open source
This site is open source.
The code, the tests, the CI and every decision with its alternatives are in the repository. The numbers on this page are worked out from it.
See the repository on GitHub (opens in a new tab)Got an idea? Tell me about it.
Write to me with no strings attached, wherever you are. I'll reply with specific questions and, if it's a fit, a written proposal.