Pauta
Municipal political transparency: citizens report an urban problem, track its resolution, and get closer to the people who represent them
About the project
Pauta was born out of a concrete gap: most people don't know who their city councilors (vereadores) are or what they propose, and complaints about the city end up as venting that never reaches whoever could actually fix them. The platform links the three ends, citizen, urban issue, and representative, into a single flow. A citizen photographs an infrastructure problem and submits it along with the location. A vision LLM automatically suggests the category, falling back to manual review as a safe default when confidence is low. The report becomes a geolocated point on the map and a post in the neighborhood feed, where it can be tracked through to resolution, with relevant updates delivered via internal notification, push, or email. The candidate recommendation feature, matching politicians to citizens by issue affinity, is the part still under construction: the API contract and the vector search are already in place, and the embeddings pipeline was developed in parallel by the recommendation team. The chosen approach is semantic, using embeddings and cosine similarity over submitted proposals, replacing the original idea of a traditional classifier.
How it works
The Next.js frontend sends the report with photo and coordinates. The FastAPI backend stores the image in Supabase Storage and calls Cloudflare Workers AI's vision LLM to classify the category; if confidence isn't high enough, the case goes to manual review instead of getting a guess. The point's geometry is persisted with GeoAlchemy2 in PostgreSQL with PostGIS, and shows up on the map via react-leaflet and in the community feed. Notifications follow the outbox pattern: the backend writes the event to a table and a Celery worker consumes it, creating the internal notification and firing off push via Firebase or email via Resend. This design avoids losing events when an external service fails. For recommendations, the bills each lawmaker has introduced become embeddings aggregated into a track record profile, compared by cosine similarity in pgvector, with grouping via clustering and a justification generated by an LLM. Authentication is handled by Supabase, with the token validated on the backend using a public key, and the feed stays accessible to visitors without an account.
Architecture
- 01
FastAPI backend with SQLAlchemy, GeoAlchemy2, and Alembic
- 02
Next.js frontend with App Router, React, and react-leaflet for the map
- 03
Single PostgreSQL database: PostGIS for geometry and pgvector for embeddings
- 04
Photo classification by a vision LLM on Cloudflare Workers AI, with manual review as a fallback
- 05
Event outbox notifications, consumed by a Celery worker with Redis
- 06
Delivery via push with Firebase and email with Resend
- 07
Supabase for JWT authentication and photo storage
- 08
Recommendation pipeline in Python, separate from the backend
Features
- Report an urban problem with photo and location
- Automatic category classification by a vision LLM, with manual review as a fallback
- Geolocated map with PostGIS and status tracking
- Neighborhood community feed, open to visitors without an account too
- Internal, push, and email notifications from an event outbox
- User interest profile to steer what they receive
- Candidate recommendations by affinity, with vector search in pgvector
- JWT authentication validated on the backend, with hardened cookies and headers
Tech stack
- Backend
- Python 3.12 · FastAPI · SQLAlchemy · Celery
- Frontend
- Next.js 16 · React 19 · TypeScript · Tailwind v4 · react-leaflet
- AI/ML
- Cloudflare Workers AI · sentence-transformers · Groq
- Database
- PostgreSQL · PostGIS · pgvector · Supabase
- Infrastructure
- Redis · Docker