Portal da Câmara — The Digital Front Door of a City Council
The official portal of the Câmara Municipal de Parnamirim (RN, Brazil): news, events, galleries, full legislature management, RG appointment scheduling, a transparency portal with multi-format export, and a SAPL mirror — four-time winner of Brazil's national transparency prize (Selo Diamante).
- Problem: a city council of about 270k citizens needed one place for news, legislative data, citizen services and legally required transparency.
- Stack: Laravel 12 + PHP 8.4, Vue 3 + Inertia dashboard, Blade + Bootstrap public site, MySQL, shared hosting.
- Key decision: mirror the national legislative system (SAPL) into local tables instead of calling it on every page view.
- Outcome: four-time winner of the Selo Diamante de Transparência Pública, with 100% uptime over the last two years.
The problem
A city council is a small government with a large public surface. The Câmara Municipal de Parnamirim (Rio Grande do Norte, Brazil) has to publish news and events, show who its councilmen are, offer services, and above all comply with Brazilian transparency law.
The old portal was a static shell. Legislative information was either hand-maintained text or lived in an external system that citizens had to leave the site to use.
The new portal helped the council win the Selo Diamante de Transparência Pública, the top tier of Brazil’s national transparency programme. Parnamirim has now won it four times, most recently in 2025 with a 95.17% score. Of 8,019 institutions evaluated nationwide, only 370 reached the Diamond tier.
News up front, citizen services one click away, and accessibility controls (contrast, font size, sign language) on every page.
What it does
- Institutional content: news, events, photo galleries and site-wide search.
- Legislative profiles: councilmen, the board of directors, committees and parliamentary fronts, with full history.
- Transparency portal: structured pages with one-click export in seven formats (CSV, DOCX, Excel, HTML, JSON, PDF, TXT).
- ID card scheduling: citizens book a slot, and staff approve, reschedule or block slots from a dashboard.
- Legislative school: events, plus certificates that can be generated, imported in bulk and publicly verified.
Constraints
- Legal compliance is a feature: the transparency law, the audit courts’ criteria, LGPD (Brazil’s GDPR) and accessibility.
- An external source of truth: legislative data officially lives in SAPL, the national legislative system.
- No history: the board of directors was a single text field, overwritten every year.
- Shared hosting: no containers, no autoscaling, one server.
Key decisions
1. Mirror SAPL, don’t proxy it
Problem. Calling SAPL during page requests would make the portal’s speed and uptime depend on an external API it doesn’t control.
Options. Proxy every request (fresh but fragile), cache the responses (still fragile when the cache is empty), or mirror the data locally.
Decision.
- A nightly job copies SAPL into local tables, and public pages read only from the local database.
- Synced rows carry a SAPL ID. Manually entered rows don’t, and the sync can only update rows that have one, so manual edits are safe by design.
- Nothing is deleted. Removed records are deactivated, because in a legislature history is the point.
- Each of the 13 resources syncs on its own, so one failing endpoint marks the run as partial instead of stopping it.
Why it holds. Public pages never fail or slow down because of SAPL. This is the decision I’m proudest of.
2. Make the legislature the backbone of the data
Problem. Councilmen were a flat table, and when the 2023 board was typed in, the 2022 board was gone.
Decision. A real domain model: legislatures with date ranges, mandates, sessions, boards, committees, fronts and parties. Each mandate records the councilman’s party at the time. The old text field was converted into proper records by a migration that can be safely re-run, and that can also be reversed.
Why it holds. Every page can answer “who was it, and when?”, which is what a public legislative record exists for.
The board of directors, tied to a legislature instead of a text field.
3. Migrate the dashboard one module at a time
Problem. The most interactive admin screens kept pushing Livewire past its limits.
Decision. Rebuild the admin dashboard with Vue 3 + Inertia, one module at a time. Routing, validation and authorization stay in Laravel. The public site stays server-rendered Blade, which is fast, accessible and easy for any PHP developer to maintain.
Why it holds. A modern dashboard on the stack I use everywhere else, with no second app to deploy and no risk to the public site.
4. Treat transparency as a product
Problem. The award evaluators score how accessible, clear and easy to navigate the data is, and they click through the portal to check.
Decision. Structured categories with timestamps, and one export engine that renders the same data in seven formats.
Why it holds. The scoring criteria are designed into the feature, not bolted on.
Structured categories, not a folder of PDFs.
5. Quality gates and a human in the loop
Problem. On shared hosting a bad release can’t simply be rolled back, and it can stop citizens from booking ID cards.
Decision.
- Every push runs static analysis (Larastan) and 3,000+ tests.
- Production deploys need a version tag, or a manual trigger where someone types
yes. - The deploy script puts the site in maintenance mode, migrates, rebuilds caches and brings it back.
- A separate staging site tests changes before production.
Why it holds. A fragile manual SSH routine became a repeatable, approved procedure.
Hard problems solved
- An unfriendly API. SAPL’s pagination and filters behave unusually, and its data includes orphaned records. Each quirk got its own tested helper, and bad rows are logged and skipped.
- Matching records safely. Hand-entered and synced councilmen are only linked by an explicit action after a dry-run report, never by guesswork.
- Protecting edited photos. The sync only downloads a councilman’s photo when no hand-edited version exists.
- Privacy by design. Citizens book with their CPF, not an account. The SAPL token stays out of the database, so the audit log can’t copy it.
ID card scheduling: book or check an appointment with just a CPF.
Trade-offs
- Mirroring means data can be up to a day old. In return, pages never depend on SAPL being up.
- Two frontend stacks during the migration, until the last Livewire module moves.
- One deployable monolith: right for a small team, with module boundaries that leave a way out later.
- Shared hosting: near-zero cost and 100% uptime over two years, paid for with careful deploy scripts instead of autoscaling.
Result
The portal is live at camaraparnamirim.rn.gov.br and is the council’s daily channel for communication and services. It holds the Selo Diamante, which made Parnamirim a four-time transparency champion in Rio Grande do Norte and the only institution in the city with the seal. Every release passes 3,000+ tests before someone types yes.