
Mis Centros Educativos
- Next.js
- React
- TypeScript
- PostgreSQL
- Prisma
- Supabase
- Docker
About this project
Every year, tens of thousands of public-school teachers in the Community of Madrid compete for permanent postings in a process known as el concursillo — a transfer contest where applicants rank schools by preference, often with nothing more than a spreadsheet and a paper list to go on. Mis Centros Educativos turns that into a searchable, filterable map: every school in Madrid, filterable by territorial zone (DAT), type (CEIP, IES, FP, EOI…), ownership, and special attributes like bilingual programs or hard-to-staff status — plus a real commute-time calculation from the teacher’s own address, by car, bike, on foot, or public transit.
It’s a free, public tool I designed, built, and operate solo — product, application code, and infrastructure. It currently covers more than 3,500 schools and has been used by over 100 teachers preparing their own concursillo.
Key features
- Zone and type filters — the five DAT territorial zones, every school type, ownership (public/concertado), and special attributes (bilingual sections, hard-to-staff schools, split vs. continuous schedule).
- Real commute times — enter a home address once and get actual travel-time estimates to every school by car, bike, on foot, or public transit (metro, bus, cercanías).
- Personal shortlist, tied to your account — save schools, drag-and-drop to reorder by preference, and export the final list to Excel for contest day. The list persists on your account, not just the current session.
- Community ratings — teachers and families can vote on qualitative traits for each school (like family involvement), building a crowdsourced picture of what a school is actually like beyond the official records.
- Fuzzy name search — find a school by name or official code, typo tolerant, in Spanish.
- SEO-ready landing page — a static marketing page separate from the authenticated app, with structured data (WebSite + FAQPage) for search visibility.
Technical highlights
Stack: Next.js 16 (App Router) + React 19 + TypeScript strict, Tailwind CSS 4, Prisma 7 over PostgreSQL (Supabase), Supabase Auth (magic link), Vitest + Testing Library + Playwright for e2e.
Self-hosted routing. Rather than pay per-request for a commercial directions API, travel times are computed by self-hosted OpenRouteService and OpenTripPlanner 2 containers, built from real OpenStreetMap and CRTM transit data for the Madrid region. Geocoding runs through Photon.
Operational maturity. A structured JSON logger, a debounced email
alerting system to avoid noisy false positives, and a /api/health endpoint
that checks both database connectivity and TLS certificate expiry, with
DNS-01 ACME issuance through Cloudflare.
What I learned
Running this alone — from provisioning the VPS to writing the FAQ copy — let me put the full range of what I know to work on one project: architecture, backend, infrastructure, and product decisions, all under one roof. The clearest lesson was around self-hosting versus a SaaS API for the routing engine — owning OpenRouteService and OpenTripPlanner myself instead of paying per request gave me control over cost and data, in exchange for owning the operational complexity. Knowing when that trade-off is worth it is something I’d now weigh with much more confidence on the next project.