Security
Where the data lives, and who can see it
DoorKnockHQ is a multi-tenant field product. Each campaign is an organization. Voter files, door results, and notes stay inside that organization.
Where data lives
Campaign data is stored in Postgres hosted by Supabase. Rows are scoped to the organization. The browser does not hold a database service-role key. Server-side edge functions use a privileged server role to perform writes after they have authenticated the caller.
Who can see it
Access is by organization role:
- Admin — campaign setup, import, billing, team, and results for the organization.
- Captain — a squad-scoped role between admin and walker.
- Walker — the field surface. A canvasser signs in with a per-canvasser access code, sees assigned turf, and records door activity under that code. Codes expire. When the shift ends, that access ends.
A code admits one canvasser. It is not a shared org password and it is not a path to another organization’s file.
Retention
After the field term, data remains available in read-only mode. Export or delete it at any time.
Retention default (S43): data is retained while the organization is read-only. Deletion happens on request, or after 24 months archived with 30 days’ notice.
Edge-function authentication
Privileged HTTP functions sit behind a JWT check when the function is meant to be called by a signed-in user. Some functions use a different check — an access-code HMAC, a Stripe signature, or an internal service-role call — and those are listed in a deploy manifest so a default “verify JWT” flip cannot silently change them. The browser never ships the server role. This page does not publish keys, webhook secrets, or project identifiers.
Advisor findings we accept
Automated database advisors flag three PostGIS catalog items. We treat them as accepted catalog findings, not as unpatched product holes. We do not claim they are “fixed.”
spatial_ref_sys— RLS is off on this PostGIS reference table. It is not voter, interaction, or organization data. Enabling RLS there is how you break map transforms.postgisinstalled inpublic— the extension lives in the default schema for this project. Relocating it on a live geometry workload is the higher-risk move.st_estimatedextentexecutable byanon— a PostGIS planner function, not an application RPC. We do not revoke it as an “advisor cleanup.”
Draft copy. READY_FOR_COPY_REVIEW. Not a SOC report and not a penetration-test certificate.