Data pipelines · Offline-first mobile
Observador de Concursos
A Brazilian public-exam intelligence platform connecting source monitoring, document change tracking, and an offline-first mobile app.
- Scope
- Backend, data pipelines & mobile sync
- Built with
- FastAPI, PostgreSQL, Celery, React Native

The problem
Exam announcements are spread across institutional portals. Dates move, documents change, and candidates need to keep up even when their connection is unreliable.
Bring collection, versioning, and candidate access into one system. A catalog of 99 source definitions feeds background collectors; the mobile app keeps its own local copy and reconciles changes when it reconnects.
Engineering decisions
Track changes explicitly
SHA-256 fingerprints and version records separate a changed notice from one already processed. Historical executions help distinguish an empty result from a failing portal.
Give slow work its own lane
Celery and Redis handle scheduled crawling, parsing, and retries. FastAPI exposes structured records and synchronization checkpoints.
Work through a lost connection
The React Native and Expo client caches data in SQLite. Favorites and alerts enter a local outbox and reconcile against the backend after reconnection.
A thread you can
follow all the way.
Scheduled workers collect public notices using HTTP, browser automation, and PDF parsing. Redis queues the work and retries. A recorded execution distinguishes an unavailable portal from one with no new notices.
What shipped
A containerized API, worker, scheduler, PostgreSQL, and Redis stack, plus an offline-first companion client. The repository includes connector fixtures, idempotency checks, synchronization verification, and operational documentation. 99 is the configured source catalog, not a claim that every portal is live.
Read the sourceEvidence from a pilot
A system you can inspect.
The documented pilot followed real records from the API to the web client. Search, filters, details and revision history were inspected, with remaining gaps recorded alongside the results.
- selections synced to the client
- 32
- sources represented in the pilot
- 31
- stored versions
- 48
The data reached the interface
Login, session refresh, checkpoints, 32 detail records and revisions passed through the web proxy. The browser displayed the 32 selections; filtering for open applications reduced that recorded result to eight.
The same notice must not multiply
The repository includes a controlled idempotency test: the first collection creates one record and version; a second collection with identical data creates neither. This is a fixture-based test, separate from the live pilot.
Offline reconciliation has its own verification path
Dedicated scripts cover favourites, alerts and reopening the app. They provide a way to inspect the intended roundtrip, but the September pilot did not test a disconnected network, native devices or new offline actions.
These are dated pilot results, not a live availability dashboard. They do not certify all 99 configured sources. The report also records missing locations, empty structured-publication data and confusing date and change labels.