Project Overview
Zorzal Morazán is a registration and attendance platform for a university with several campuses. Staff schedule sessions, students register and check in, and the information that used to live in spreadsheets now flows in and out of Google Sheets. I designed and built it end to end. The interface is in Spanish.
What it does
- Student accounts: sign in with email and password, Google Sign-In or a magic link, with the graduation status of each student kept alongside.
- Sessions and check-in: staff schedule sessions and students register for them. Check-in works on a phone even without a connection, using an access code that belongs to each session.
- Admin console: three roles (super admin, system admin and area admin) limited to a campus and an academic area, with an audit log, a background job queue and settings.
- Google Drive and Sheets: rosters are imported and exported, folders are scanned and the platform learns equivalences between spellings and headers.
- Notifications: email and Telegram, with address checks, a dispatch ledger and a daily sending quota.
- Demo campuses: seeded sample campuses for demonstrations, which can be reset on demand.

Check-in that survives a bad connection
Check-in happens at the venue, on a volunteer’s phone, where the signal is not always good. Opening the screen with the session’s access code downloads the roster of registered students once; after that every check-in is saved on the device straight away and sent when the network allows, in order and without duplicates. Because the roster is already on the phone, someone who is not registered is rejected at the door.

How it is built
- API: ASP.NET Core on .NET 10 with EF Core and PostgreSQL. The domain project has no dependency on EF or ASP.NET, and controllers stay thin.
- Web: a React 19 single-page app with Vite, TypeScript, Tailwind CSS v4 and TanStack Query, deployed on Vercel.
- Database: append-only migrations applied with dbmate, plus reference-data seeds.
- Resilience: the API runs in Docker with a streaming-replica fallback, and the interface switches to a read-only mode when the fallback answers.
- Testing: integration tests run against a real, migrated PostgreSQL in a container, and every page and state of the app is browsable in Storybook with mocked data.