← Todos los proyectos

yesid.dev

Mi propio sitio, llevado como un proyecto de cliente: el CMS es la fuente de verdad, el edge sirve contenido generado y cada afirmación está asegurada por un test.

Most portfolios describe work. This one has to survive it: the site is edited, built, tested and shipped by the same pipeline I would set up for a client, so the case study and the deliverable are the same artifact.

The shape is simple. Content lives in Directus on a Neon Postgres instance. At build time, export-fallbacks.ts regenerates 21 typed TypeScript modules from live CMS state and records each one in a SHA-256 manifest. SvelteKit prerenders every page in English and French, and Vercel serves the result. Visitors never wake the CMS: 0 calls per visit.

flowchart LR
  directus["Directus CMS"] --> export["export-fallbacks.ts"]
  export --> cache["21 typed content modules"]
  cache --> manifest["SHA-256 manifest"]
  cache --> svelte["SvelteKit prerender (EN + FR)"]
  svelte --> vercel["Vercel edge"]

That boundary is enforced, not promised. On Vercel the export is live-or-die: if the CMS cannot be reached, the build fails instead of shipping stale content. Locally a fallback is allowed, but it prints a banner you cannot miss and the manifest records which modules came from cache. A pre-commit hook and a CI check both reject hand-edits to generated files. I edit the CMS, or nothing.

The services page draws a metro line with four stations: Databases & SQL, Pipelines & Automation, Dashboards & Analytics, Websites & E-commerce. This build stops at every one of them, not as a demo but as load-bearing structure.

  • `Databases & SQL`: the content sits in a Neon Postgres instance behind Directus. The schema ships as versioned snapshots, tags and tech stack are real M2M relations instead of denormalized JSON, and autosuspend tuning keeps the database bill close to zero between visits.
  • `Pipelines & Automation`: a publish in the CMS fires a deploy hook, the build pulls live content, regenerates every module and hashes it into a manifest. The scripts that can write to the CMS all refuse to touch prod by accident.
  • `Dashboards & Analytics`: the metrics at the top of this page are not marketing copy. Test counts, locale coverage and byte budgets come out of commands that can be rerun, and the important ones are pinned as failing tests. That is the same discipline I want in any dashboard: numbers with receipts.
  • `Websites & E-commerce`: the storefront is the site you are reading. Bilingual by default, prerendered in English and French, light and dark themes, and a `prefers-reduced-motion` contract checked end to end. The e-commerce half of this station gets proven on client work instead.

The metro is not a paint job either. The NEXT STOP chrome, the terminus board and the little delay dashboard in the hero all read their labels from the same CMS pipeline as the rest of the copy, so even the set dressing is bilingual and covered by the tests.

Metrics rot fast on portfolio sites, so here is where mine come from. Every suite below was green the day this page was written, and the counts are the test reporter's output, not a guess.

código sh
cd apps/web && bunx vitest run        # 1,871 tests, 170 files
cd apps/cms && bun test               # 729 tests, 69 files
bun run --cwd packages/shared test    # 84 tests
bun run --cwd packages/tokens test    # 43 tests
cd apps/web && bunx playwright test   # 424 e2e tests, 37 files

That is 3,151 tests between a content edit and production. The Playwright end-to-end suite runs sharded three ways in CI against a hermetic local preview: no deployed URL, no edge quota spent, just the build under test.

The bilingual promise is a failing test, not a policy. An integrity walker visits every visitor-facing string in the generated content and locks the counts:

código ts
// apps/web/src/lib/content/integrity.test.ts
const LOCKED = { TOTAL: 650, WITH_FR: 650, NO_FR: 0, ES_WITHOUT_FR: 0 };
// 650 visitor-facing strings walked. 650 carry French. Zero debt.
// Strip one translation and the suite goes red before the push.

The same reflex guards the rest of the build:

  • `svelte-check` warnings are locked at `0`. The gate went from 46 to zero without a single suppression, and CI fails if one grows back.
  • Content schemas live once in `packages/shared` as `Zod` schemas, imported by both the web app and the CMS scripts, so the two ends of the pipeline cannot drift apart quietly.
  • The interactive stack engine stays code-split behind a pinned 25 KB gzip budget, re-measured after every build.
  • OG share cards are minted from the canonical wordmark SVG at 1200x630, with a hard 150 KB budget per card.
  • CI is cost-aware on purpose: PR-only triggers, a shared turbo remote cache, cached browsers and a skip label for docs-only changes. I burned through the free GitHub Actions minutes once. Once.

None of this is exotic. It is ordinary digital infrastructure, pointed at my own site first. If you want to know what working with me looks like, this page is the answer: the pipeline that built it is the pitch.

yesid.dev is the one project where I am both the client and the contractor. It is a bilingual SvelteKit site edited in Directus, regenerated into typed TypeScript modules at build time, and served prerendered from the Vercel edge with 0 CMS calls per visit.

It is also the working proof for all four services. The content lives in a Postgres database I tune myself, a pipeline rebuilds the site on every publish, the numbers in this case study are measured rather than estimated, and the storefront is the site itself.

3,151 tests que cuidan el build
0 llamadas al CMS por visita
650 cadenas bilingües, aseguradas por un test
100% contenido desde el CMS
0 advertencias toleradas en CI
SvelteKitSvelte 5TypeScriptTailwind CSSGSAPDirectusNeonBunTurboVercelGitHub ActionsPlaywrightVitest
Sitio en vivo Repo privado (por ahora)

Construyamos algoque se mueva.

Base de datos, pipeline, tablero, sitio web: donde se atasca la cosa, ahí empezamos.