Security and privacy
How Infra protects resident data on its Supabase stack. Every control below exists in the product today, and each names the repo file behind it.
Controls in the product today.
Each row names the repo file behind it. None of this is a certification.
Postgres row-level security
The database filters every query by role.
Row-level security is switched on across the schema, in 33 migration files, with default-deny policies. A resident query returns only that resident's own reports. A staff query is scoped to the city, and contractors see only the work assigned to them.
The check lives in Postgres, not in app code. Access is decided by the database on every query.
In the repo: supabase/migrations/20260527_001_initial_schema.sql (reports_select_own, reports_select_staff), 20260709_053_contractors.sql. Covered by tests/rls.
Supabase Auth and roles
Sign-in is handled by Supabase Auth.
Residents can file a report without an account through anonymous sign-in. Staff sign in with OAuth and carry their role in app_metadata, which the proxy reads on every request.
The client never decides who staff are. SAML single sign-on is scaffolded in the repo and marked as coming, not enabled.
In the repo: src/components/report/ensure-anon-session.ts, src/proxy.ts, src/app/onboard/actions.ts, src/lib/auth/sso.ts (scaffold).
On-device photo privacy
Faces and plates are blurred before upload.
Blur runs on the resident device. The blurred copy is the only photo the public bucket ever holds. The original goes to the restricted photos-raw bucket, which staff alone can read.
Originals are deleted by a nightly job after the retention window: 30 days by default, configurable per city.
In the repo: src/lib/privacy/blur.ts, src/app/report/page.tsx, supabase/migrations/20260709_046_retention_settings.sql (raw_photo_ttl_days default 30).
Private vehicle frames
Lens frames never leave a private bucket.
Lens frames are unblurred street footage. They stay in the private video-frames bucket, and staff open one frame at a time after a city-scoped check derived from the report itself.
Each view uses a signed URL that expires after 10 minutes. A leaked link rots on its own.
In the repo: src/app/staff/evidence-actions.ts (SIGNED_URL_TTL_SECONDS = 600), src/app/city/[slug]/video/actions.ts.
Signed webhooks
Every delivery carries a signature you verify.
Each webhook POST carries an X-Civic-Signature header: an HMAC-SHA256 of the raw body. Your endpoint recomputes it with the shared secret and compares in constant time, so forged events fail closed.
const expected = createHmac("sha256", secret)
.update(body, "utf8").digest("hex");
// compare expected with X-Civic-Signature
// using timingSafeEqualIn the repo: src/lib/webhooks/dispatch.ts (signPayload, verifySignature), src/lib/webhooks/deliver.ts.
Headers and least data
Pages deny framing, and reports carry little.
The proxy sets a per-request content security policy with frame-ancestors none. Static headers add X-Frame-Options DENY, nosniff content types, a narrow permissions policy, and HSTS with preload.
Reports carry a photo, a location, and a category. No account is needed to file one, and Open311 photo URLs are ignored unless they pass the same blur check.
In the repo: src/proxy.ts (buildCsp), next.config.ts (headers), src/app/api/open311/v2/requests/route.ts.
How this compares to a typical 311 setup.
A typical 311 or CRM system does access checks in app code and stores what residents upload. It handles tickets well. Infra moves both checks closer to the data: the database filters rows, and photos are redacted before they arrive.
| Capability | Infra | Typical 311 / CRM system |
|---|---|---|
| Photo privacy before upload | On-device blur, 30-day raw TTL | Stored as uploaded |
| Access decided by the database | RLS policies, default deny | Checks in app code |
| Webhook authenticity | HMAC-SHA256 header | ◐ Partly |
| Change history on reports | Append-only event log | ◐ Partly |
| Independent security audit | Not yet | Varies |
Not yet.
No third-party security audit has been completed. We claim no SOC 2, HIPAA, or ISO certification, for Infra or for our vendors. SAML single sign-on is scaffolded in the repo and marked as coming.
The controls above are in the product today. See our privacy promise for what we collect. When an independent audit happens, the result will be stated here.
Questions from city teams.
Do we have to replace our 311 or work-order system?
No. Infra is built to sit beside it. Reports can arrive through Open311 or an import, and report events leave through signed webhooks. Adapters for Cityworks and Accela are coming, not built.
What is the difference between Atlas and Lens?
Infra Atlas runs every report from intake to crew: residents report, the city works the queue, teams fix. Infra Lens finds damage before reports exist by scanning video from city vehicles. One runs the queue, the other feeds it.
Do we need both?
No. Each works alone. Lens results land in Atlas, or go straight to your current system through signed webhooks.
Can we turn on only some parts?
Yes. AI triage, duplicate merge, crew routing, incident and FEMA cost tracking, liability checks and resident intake are separate. Parts are switched on per deployment during setup.
What happens to resident photos?
Faces and license plates are blurred on the device before upload. The unblurred original is kept in a restricted bucket and removed after a retention window, 30 days by default.
How accurate is the classifier?
We do not publish an accuracy figure yet. Staff can correct any classification and corrections are stored. Ask us to run a trial on your own ticket export.
Has Infra passed an independent security audit?
Not yet. Our controls are documented internally and we walk through them during evaluation.
Do residents need an account?
No. A report can be anonymous and each one gets a public tracking link.
Can Infra find problems before residents report them?
Partly, today. Infra Lens scans city dashcam video for road damage and Infra Atlas reads National Weather Service alerts to estimate storm-driven reports. Coming next, Lens adds public traffic cameras and opens incidents from weather, earthquake and wildfire alerts.
Start with Atlas, Lens, or both.
Tell us which system you use and which parts matter. We will map the connectors with you.