# Engineering

## Decisions

### Astro over Next.js

The site is mostly static, SEO-critical content read by recruiters and peers on commutes, not an app that needs client-side routing state.

Astro 5 with React islands only where interactivity is real (chat, forms, theme toggle), instead of Next.js.

**What it cost/bought:** Gave up Next's larger ecosystem and app-router conveniences. Bought near-zero client JS on every content page by default — a budget Next would need deliberate work to hit, since its defaults ship a client-first runtime whether a page needs one or not.

### Git-based CMS over a hosted one

No evidence yet that a plain git-plus-editor workflow can't keep up with actual publishing cadence, before paying for a hosted CMS to solve a problem that might not exist.

Content lives as git-versioned MDX/JSON, read through one ContentRepository port, edited three equivalent ways — direct file, Claude Code, or a local Keystatic UI.

**What it cost/bought:** Gave up a hosted UI's polish and multi-editor collaboration. Bought a $0 CMS with the swap to Sanity or Payload staying a single new adapter file, not a page-level rewrite, if the workflow ever does hit a ceiling.

### Workers AI first, Anthropic as fallback

The chatbot needs a model provider, and a paid API as the default breaks the $0/month budget the moment the site gets any real traffic.

A provider router tries Cloudflare Workers AI first, free and colocated with the rest of the stack, and falls back to Anthropic only if that call errors — never the other way around.

**What it cost/bought:** Workers AI quality trails frontier models on nuanced questions. The tradeoff: a chatbot that costs nothing at normal traffic, with the upgrade to Claude Haiku sitting behind one config change in src/config/llm.ts, not a rewrite.

### Cloudflare's free tier as the ceiling, not a starting point

Domain already owned; every other cost (hosting, embeddings, rate-limit storage, email) had to fit inside a tier that won't get bumped by a personal site's real traffic, not just look cheap on a demo.

Pages/Workers for hosting, KV for rate limiting, Vectorize for embeddings, Workers AI for the chatbot — one provider, one free tier, for everything that isn't the domain itself.

**What it cost/bought:** Gave up a multi-vendor stack that might optimize any one piece slightly better. Bought a $0/month recurring bill regardless of how many features get added, because they all share the same headroom instead of each adding its own bill.

### The hero moved from decorative to data-true

An early hero concept was a generic animated gradient mesh with an optional pointer-parallax dot grid: motion for its own sake, no connection to what the site is actually about.

Replaced it with a living-blueprint diagram generated at build time from the real competency matrix — nodes are skill domains weighted by real depth, edges are roles that touched them. Not decorative randomness.

**What it cost/bought:** More build complexity than a static gradient. The hero now changes only when the underlying career data changes — the diagram is a claim about real experience, not a mood board.

### A hand-written fetch transport over the MCP SDK's own

The MCP server's Cloudflare Worker transport needed to implement the protocol's Transport interface, and the SDK ships one, StreamableHTTPServerTransport, for exactly this.

Traced that class into node_modules and found it's typed and implemented directly against Node's IncomingMessage/ServerResponse, which don't exist in the Workers runtime. Wrote FetchTransport instead: the same interface, implemented directly over the standard Fetch API.

**What it cost/bought:** Gave up the SDK's official, more-tested transport implementation. Bought a Worker that actually runs, verified with a real `wrangler dev` handshake, instead of one that fails at runtime reaching for a Node built-in that isn't there.

## Why this stack

- **Astro 5:** Islands architecture ships near-zero client JS on static content by default.
- **React (islands only):** Used only where a component genuinely needs client-side state — chat, forms, toggles.
- **TypeScript, hexagonal ports & adapters:** core stays framework-free; swapping an adapter never touches a page.
- **Tailwind CSS v4:** Token-driven styling; every color and spacing value traces to one CSS custom-property file.
- **Cloudflare Pages + Workers:** Hybrid output: pages prerender to the CDN, /api/* runs as Workers functions.
- **Cloudflare Workers AI + Vectorize:** Free-tier chatbot provider and embedding index, with Anthropic as a config-swappable fallback.
- **Astro content collections (git-based CMS):** content/ is the CMS — MDX/JSON, versioned in git, edited three equivalent ways.
- **Keystatic:** Local content-editing UI mirroring the same zod schemas Astro's collections already validate.
- **Cloudflare KV:** Rate-limit storage for /api/contact and /api/chat, free tier, no separate database.
- **GSAP, Lenis, OGL (motion stack):** MIT-licensed; loaded lazily per page so content pages never pay for motion they don't use.
- **Model Context Protocol (packages/mcp):** Publishes the same content and chatbot to AI agents as typed tools, not scraped HTML.

## Changelog

### 2026-07-04 — Site scaffolded on Astro 5

Design system, layout shell, and Home page stood up from an approved spec — hexagonal core, adapters, and a content-collection CMS from day one, not bolted on later.

### 2026-07-04 — Journey and Dossier ship

The scroll-driven career narrative and the recruiter-scannable executive dossier land as the first two real content pages.

### 2026-07-05 — Projects, Writing, and the chatbot land in one push

Project deep-dives, the writing engine with RSS and publish-kits, and a RAG chatbot with a multi-provider router all ship.

### 2026-07-05 — Redaction gate becomes CI-enforced

What started as a hand-checked rule — no employer-tied financial figures or headcounts on the public site — became an automated script scanning content, the chat index, and the built site on every commit.

### 2026-07-05 — The hero rebuilt as a living blueprint

Replaced an early decorative gradient-mesh concept with a data-true diagram generated from the real competency matrix, then reworked twice more for full graph connectivity and a three-tier renderer.

### 2026-07-05 — Accessibility becomes a visible, first-class control

A floating control center ships — reduce motion, high contrast, larger text — backed by a documented accessibility statement, not just a compliance checkbox in a footer.

### 2026-07-05 — Architecture audit closes 13 duplication findings

A full pass over every content-loading path, locale touchpoint, and formula in the codebase found 13 duplicated or divergent pieces of logic. Most got a single shared implementation; the rest were kept as documented, deliberate exceptions — turned into two ADRs and a permanent test guard against regression.

### 2026-07-05 — Site goes bilingual

Portuguese routing, i18n foundation, and localized pages ship under /pt/, with English-only content (articles, project deep-dives) clearly marked rather than machine-translated.

### 2026-07-05 — AI-ready surfaces added

Markdown twins, an llms.txt file, and a JSON Resume endpoint ship — so an AI agent can read this site as cleanly as a human does, without scraping rendered HTML.

### 2026-07-06 — Cross-engine E2E and CI quality gates land

A Playwright suite covering Chromium, WebKit, and mobile-WebKit, plus a GitHub Actions workflow running check, test, redaction-gate, and build on every push — no more relying on manual verification before merge.

### 2026-07-06 — The MCP server ships

The site's content and chatbot become callable as typed Model Context Protocol tools — both a local stdio package and a Cloudflare Worker transport, with a layered rate-limit and abuse-prevention shell in front of every tool call.

### 2026-07-06 — Repo made AI-agent-legible

AGENTS.md, the architecture map, and a shared voice guide land so any AI coding agent, not just the one that built it, can pick up this repo and follow its own rules.

### 2026-07-09 — Galaxy backdrop and brand glyph ship

A site-wide WebGL galaxy layer lands behind all page content, tuned for both themes: dense glowing stars in dark mode, near-invisible ink specks in light. The owner's raster brain glyph replaces the generated SVG mark throughout — favicon, OG image, and chat launcher.

### 2026-07-09 — /reading section launches

A public log of books, articles, and papers, each with the owner's verdict and rationale. Filter chips by type and domain; four verdict levels (foundational / worth your hours / situational / skip unless) with per-entry reasoning.

### 2026-07-09 — Projects page reframed around delivered value

Each project card now leads with its north star and concrete outcomes before exposing technical detail. Selfwright and felipetavares-dev entries gain expandable deep-dives.

### 2026-07-10 — Chat launcher redesigned as avatar

The chat entry point changed from a pill button to a 56px circle showing the owner's brand glyph with a green online-status dot — consistent with the brand identity throughout the site.

### 2026-07-10 — Experience content revamp

All seven roles rewritten from an owner interview: AI/GenAI leadership added across roles, titles corrected (Finance Consultant/Business Architect; Order-to-Cash Solution Lead), PwC location updated to Amsterdam NL, Siemens dual-city display (Lisbon PT + Munich DE).

### 2026-07-10 — PT-BR archived for v1 launch

All /pt/* routes removed from the build by renaming the directory to _pt/ (Astro ignores underscore-prefixed directories). Files stay versioned; the language switcher is removed. Bilingual v2 restores them once the English content is fully QA'd and stable.

### 2026-07-10 — Pre-launch polish and voice pass

Em-dash sweep across all published prose; section spacing unified site-wide via a shared Section.astro scale; hero kinetic type reserves minimum height on mobile to prevent layout jumps; contact copy, credibility framing, and writing subtitle all revised against the voice guide.

