CIVIC ROUTING.
Multi-Actor Case Routing with Evidence Intake
A bilingual citizen-facing platform for structured incident reporting with video evidence, multi-stage workflow routing across reviewers and authorities, and end-to-end audit traceability.

The Problem Space
Public-facing reporting platforms — for civic complaints, regulatory infractions, safety incidents, public grievances — share a hard problem set. Submissions need to be structured enough to be actionable but accessible enough for non-technical citizens. Video evidence has to upload reliably from mobile devices on inconsistent connections. Geolocation has to be accurate and verifiable. Internal reviewers need triage tools that don't drown them in submissions. Downstream authorities need their own clean interface, separated from the rest of the system. Every step has to be auditable so a contested case is forensically defensible months later. And in regions where Arabic is a primary language, the whole experience has to work bilingually with right-to-left layout — not as an afterthought, but as a first-class concern.
Most platforms that attempt this end up either too technical for citizens or too rough for institutional use. We built this platform to demonstrate the production-grade middle.
What We Built
An end-to-end civic reporting platform supporting three distinct actor roles, a multi-stage case lifecycle, routing across reviewers and authorities, and full audit logging — bilingual (Arabic + French) with right-to-left support for the Arabic experience.
The platform handles the complete workflow: a citizen submits a structured report (multi-step form with declarant identity, incident metadata, geolocation, video evidence, signed declaration) → an internal reviewer triages, validates, or rejects with reason → validated cases are dispatched to the appropriate authority for decision → the authority records its decision → reviewer finalizes or escalates → outcome recorded. Each transition is logged, each actor sees only what their role requires, and citizens get a simplified view of progress without internal routing details.
Functional Scope
Three role types with isolated interfaces. Citizens (submission and personal history), Internal Reviewers (triage, validation, routing, full audit access), Authorities (case review, decision recording). Each role has its own dashboard, its own routes, and its own data visibility rules — enforced at the API layer, not just the UI. Reviewer and Authority sessions are never interchangeable; tokens cannot cross role boundaries.
Multi-stage case lifecycle with strict transitions. Pending → Under Review → Validated / Rejected → Dispatched → Decided → (optional escalation) → Closed. State transitions are enforced server-side against an explicit transition map; no state can be skipped or reversed except through explicit paths with audit.
Three-step guided submission form. Step 1 — declarant identity with national ID format validation. Step 2 — incident metadata: typed selector with legal classification displayed bilingually, interactive map placement with Nominatim reverse geocoding, address autocomplete with regional bias, video upload, free comment, and incident time validation. Step 3 — full recap, signed declaration checkbox, CAPTCHA verification before submission.
Direct-to-cloud video upload architecture. Videos do not transit the application server. The client requests a signed upload signature from the API, uploads directly to Cloudinary via XHR with live progress tracking, and the application stores only the resulting cloud reference. Supports MP4/MOV/AVI/MKV up to 500 MB.
Interactive geolocation with reverse geocoding. Leaflet map for visual placement, Nominatim API for reverse geocoding on every click, and address-search autocomplete biased to the operating region. Server persists both raw coordinates and the resolved human-readable label.
Bilingual UI with RTL as a first-class concern. Arabic and French side-by-side in every form label, status badge, type selector, and email template. Arabic is the primary language and displays right-to-left; French displays left-to-right. Composable bilingual primitives (BilingualLabel, BilingualSelect, BilingualBadge) ensure no duplicated French/Arabic component code anywhere.
Append-only audit log on every consequential action. Every state transition, every reviewer decision, every authority action records actor identity, role, timestamp, action type, and contextual detail. The log renders chronologically in case detail views — providing forensic defensibility if a case outcome is later contested.
Technical Highlights
Direct-upload media architecture. Video files are uploaded directly from the browser to the CDN via signed upload signatures. The application server never sees the video bytes. This pattern is non-obvious to implement correctly — signature lifecycle management, failure handling on partial uploads, cleanup paths on case rejection — but it's what makes the platform scale without storage costs hitting the application layer.
State machine enforced at the API layer. Every state transition validated server-side against an explicit transition map. UI buttons are derived from the allowed transitions for the current actor + current state — not hardcoded — so workflow changes propagate without UI rewrites.
RTL-aware UI primitives. Bilingual components render French and Arabic side-by-side with justify-content: space-between, automatically reversed under RTL. Status, type selectors, and form labels all use composable bilingual primitives rather than duplicated FR/AR versions. The HTML dir attribute switches at the layout root.
Production layout edge cases handled. Map container isolation: isolate so Leaflet's internal z-index stack doesn't bleed through the fixed application header. invalidateSize() triggered on form-error state changes to prevent the map rendering blank after validation failures. These are the kinds of details that separate a polished platform from a brittle one.
Security-first session model. JWT-based stateless sessions with role information in the token. Middleware enforces auth at the route level; every API route additionally verifies session and role. Sessions expire after 8 hours. CAPTCHA-protected registration and bcrypt password hashing throughout.
Stack
Next.js 14 (App Router) + TypeScript throughout. Prisma v7 ORM with PostgreSQL backend. NextAuth.js v4 for stateless JWT authentication. Cloudinary for video storage with signed direct-upload from the browser. Leaflet.js with OpenStreetMap and Nominatim for interactive geolocation. Cloudflare Turnstile for CAPTCHA. Tailwind CSS with a custom design system. bcrypt for password hashing.
Status & What It Demonstrates
This platform is built to near-production engineering standards as an internal R&D project — bilingual citizen interface, three role-isolated back-offices, complete state-machine-driven workflow, end-to-end video evidence pipeline, and full audit traceability. The architectural patterns it demonstrates transfer directly to client engagements in regulated industries, civic technology, complaint and incident management systems, multi-party workflow tools, and any platform where citizen-facing simplicity has to coexist with institutional-grade auditability.
If you're building a platform where structured submissions have to flow cleanly across roles and stay defensible at every step, we should talk.
BUILDING
SOMETHING LIKE THIS?
Production reliability. Multi-actor workflows. AI integration. Complex state. If your project shares these characteristics, we should talk.