Havara: Security Overview
Effective October 6, 2026
This is a plain-English summary of how Havara protects community data, written so that boards, management companies, and other buyers can understand our security posture without reading the source code. It describes the product as it is built today, not aspirations. Where a control is optional or not yet in place, we say so plainly.
Havara is a multi-tenant mobile app (iOS and Android, built on Expo / React Native) with a web console, for HOA and residents' communities. One person can belong to several communities and switch between them. The backend is a hosted Supabase project (Postgres database, authentication, file storage, and serverless Edge Functions). Anyone can create a bare account, but an account alone grants access to nothing: joining a community requires a board-issued invite or an approved join request. The product is invitation-only at the community layer.
Questions about this document: privacy@havara.app.
Architecture: multi-tenant with Row-Level Security on every table
Havara runs every community on shared infrastructure (a single Postgres database), and keeps communities separated logically rather than on separate servers. The separation is enforced in the database itself:
- Row-Level Security (RLS) is enabled on every table. Each row carries the community it belongs to, and the database only returns rows the requesting user is permitted to see, keyed off their membership and role. A user who belongs to Community A simply cannot read Community B's rows; the database refuses to return them.
- This is enforced server-side, not in the app. The public Supabase "anon" key shipped inside the mobile app grants no special access on its own. It is safe to ship precisely because RLS protects all data behind it. Every query from the app runs under these rules, or through a server-side function that checks membership and role itself.
- Visibility rules are centralized in a small set of database helper functions (for example, checks for "is this user a member of this community" and "can this user see this document"), so access logic lives in one auditable place rather than being re-implemented per screen.
Authentication: email + password, PKCE reset, session storage
- Email + password sign-in is the primary method (Supabase Auth), with an emailed one-time magic link available as a secondary option. Password reset is delivered by an emailed link over a PKCE deep-link flow, which protects the reset exchange against interception on the device. (Sign in with Apple and Google are scaffolded but not offered: the buttons are hidden and the code paths are disabled.)
- Session storage. After sign-in, the app keeps the session (an access token and a refresh token) in its own on-device storage and refreshes it automatically. The app does not add its own encryption to that storage; it relies on the phone's protection of app data. The web console keeps the session in the browser's storage.
- Open signup, invitation-gated communities: stated honestly. Anyone can create an account; we do not claim otherwise. What the invitation gates is access: a fresh account can read no community's data until a board-issued invite code is redeemed or a join request is approved, so an attacker who signs up reaches only an empty shell protected by the same server-side rules as everything else.
Encryption: in transit and at rest
- In transit: all traffic between the app, the backend, and every third-party service uses encrypted HTTPS/TLS connections. The app makes no plaintext HTTP calls.
- At rest: data stored in the database and in file storage is encrypted at rest by the hosting provider (Supabase / Postgres platform). We rely on the provider's platform-level encryption for data at rest rather than implementing our own.
Data isolation: RLS plus community scoping
Isolation is not a single feature; it is the combination of the controls above:
- Every record is scoped to a community and, where relevant, to an audience within that community (a channel, a sub-group, a direct message, or the board).
- RLS evaluates the requesting user's memberships and role on every read and write, so members see content only for communities they belong to and audiences they are part of, with two exceptions, and both reach a direct message too. The first is for moderation. A community's moderators (its administrators and any member the board lets moderate) see a chat message that was reported, or that the chat filter held or flagged, through the moderation queue, even in a direct message or a private group they are not part of, together with who wrote it, where, and the names of its attached files. They see it only while a report on it is open or, once a moderator hid it on that report, for up to 7 days while it stays hidden; a dismissed report no longer shows it. The queue is a server-side function that answers only that community's moderators. The second is a request. Someone on the board (a board member, an admin or a declarant) who can read a message (for a direct message, one who received it) can make it into a request, which every administrator of the community can read.
- Sensitive reads go through tightly scoped server-side functions. For example, the member directory is served through
SECURITY DEFINERfunctions that return only directory-appropriate fields. The underlyingprofilestable stays locked, and sensitive columns such as push tokens are never exposed through those functions. - Privileged operations validate "self-only" or membership access server-side. A user cannot edit another member's profile, and the account-deletion and personal data-export functions act only on the currently authenticated user. The community record export is the one export scoped to a community rather than a person: it answers only that community's administrators and reads under their own access rules (see below).
Backups and recovery
- Supabase, our hosting platform, takes a daily backup of the database and keeps each one for 7 days. We rely on that managed backup rather than running a separate backup system.
- Point-in-time recovery is not enabled. A restore returns the database to the most recent daily backup, so changes made after that backup would be lost.
- A note on deletions and backups: when a member deletes their account, their personal data is removed from the live system immediately, but residual copies may persist in the daily backups taken before the deletion, until those backups expire about a week later.
Access control: board capabilities and least privilege
- Roles. Each membership carries a role: resident, homeowner, board, admin, vendor, platform-level owner, or declarant. What a member can see and do is scoped by their role within each community, independently per community. A declarant is a builder/developer seat used to provision a community before residents move in; it carries board-equivalent administrative access in that community during buildout, enforced by the same server-side rules as board access.
- Least privilege by default. Ordinary members get only the access their membership implies. Board and admin tooling (member management, moderation, join settings, document management) is gated to board/admin roles and enforced in the database, not just hidden in the UI.
- Granular board capabilities. Beyond the role, a membership can carry specific board-granted capabilities, so a community can delegate narrow powers without handing out full admin.
- Guardrails on privileged actions. Server-side checks prevent dangerous states: for example, you cannot remove the last admin of a community, and privileged database functions validate that the caller is actually a member (and, where appropriate, acting only on themselves).
- Moderation and an audit trail. Members can block other members and report content; boards can hide content with case notes. Governance actions (such as invite redemptions and role/membership changes) are written to an audit log so there is an accountability record of who did what.
- Secrets stay server-side. Sensitive operations run only on the server, in Edge Functions and in database functions. The secret keys the service uses to call third-party services (such as the AI providers, OCR, email sending and payments) are held in server-side secret stores, Havara's own and those of the build and push service Expo runs for Havara, and none is embedded in the app bundle that ships to devices. The app carries only client identifiers that are public by design, such as the public Supabase key described above and the crash-reporting address.
- Abuse rate limits. Abuse-prone paths are rate-limited per user. For example, AI "Ask" questions, invite-code redemptions, and chat message inserts are each capped to a reasonable per-user rate to blunt automated abuse.
AI safety: documents-only, permission-filtered, guardrails
The AI "Ask" tab answers questions from a single community's own governing documents (CC&Rs, bylaws, rules, minutes, budgets, policies). It is built to be constrained, not open-ended:
- Documents-only retrieval (RAG). Ask does not browse the web and does not draw on general world knowledge as a source. It retrieves a handful of relevant excerpts from the community's uploaded documents and answers from those.
- Permission-filtered. Each time Ask composes a new answer, retrieval re-applies the asking member's document visibility, so the excerpts that answer is built from come only from documents the member may see at that moment. Answers a member has already received stay in their own Ask history if their access later narrows, and the same first question in a new conversation can replay the member's own earlier answer while the community's set of Ask documents is unchanged.
- Guardrails on the answer. The model is instructed to cite every factual claim to a numbered source excerpt, to answer only from the documents, and to never give legal advice, only describe what the documents say. If nothing relevant is found, it says it does not see the answer in the documents and points the member to the board.
- Boards control what is in scope. A board can remove any document from Ask, which deletes that document's indexed text from retrieval.
- What leaves to AI providers, and what does not. To produce an answer, document text leaves to OpenAI during indexing, scanned PDFs with no text layer leave to AWS Textract for OCR, the member's question leaves to OpenAI (for moderation and search embeddings), and the question plus the retrieved excerpts leave to Anthropic (to compose the answer). No account identifiers are sent in those requests. Havara deletes its staged copy of a scanned PDF after the scan. AWS's service terms allow it to store what Textract processes to provide and maintain the service, and would also let it use that content to improve Textract and other Amazon AI services, and keep some of it in another AWS region, unless an AWS AI services opt-out is in place; Havara has had that opt-out in place since September 23, 2026, covering Textract and every other AI service the policy covers. Per OpenAI's published API data policy (read 2026-07-12), API data is not used to train OpenAI models unless the customer opts in (we have not), and abuse-monitoring logs are retained up to 30 days. Anthropic's Commercial Terms (read 2026-10-02) say Anthropic may not train models on customer content from its services, and Anthropic's published retention terms (read 2026-10-02) say it deletes API inputs and outputs within 30 days, with exceptions those terms list, including content its automated trust and safety systems flag as violating its Usage Policy (inputs and outputs kept for up to 2 years, classification scores for up to 7 years) and retention the law requires.
Account deletion and data export
Account deletion and the personal data export are available in-app and act only on the requesting user. The community record export is for a community's administrators and is described at the end of this section.
- Permanent account deletion. A member can permanently delete their own account from within the app. The deletion function takes no arguments and acts only on the authenticated user, so a user can only ever delete themselves. On deletion, the member's login and personal records are removed: the auth record and profile are deleted, which cascades away per-user records such as memberships, join requests, RSVPs, acknowledgements, reactions, read receipts, chat participation, sub-group memberships, and amenity bookings. The member's uploaded avatar is also deleted from storage.
- By design, content the member authored that others rely on is retained and anonymized, not hard-deleted. Chat messages, announcements and comments, sub-groups they created, AI answers, sent invitations, and audit rows remain in place but are de-linked from the person and shown as an anonymous "Member." This preserves the integrity of threads and feeds for the rest of the community. We disclose this plainly rather than implying everything authored is erased.
- Data export ("Download my data"). A member can export their own data as a single JSON file. The export assembles only rows keyed to that authenticated user: profile, memberships, event RSVPs, announcement acknowledgements and comments, chat messages, emergency-alert responses, join requests, amenity bookings, AI Ask threads and answers, consent records, violation cases in which the member is the named subject (plus their case comments and cure notices), ARC requests and events, general requests and comments, poll votes, and the member's unit record(s).
- Community record export. A community administrator (a board member, an admin or a declarant) can download the community's record from Settings in the web console as one JSON file. The export function runs with the administrator's own permissions, under the same row-level rules as every other screen, so it returns only what that administrator can already read, and it refuses anyone who is not an administrator of that community. It includes the member roster by name with each member's role, home and household role, and the community's governance, compliance, request, money and document records (document names and storage locations, not the files). It never includes chat or direct messages (a request someone made from one with the phone's "Make this a request" is included like any other request, with the message's text), Ask conversations, moderation reports, individual poll votes (only per-option counts) or the audit entries that record who voted in which poll, invitations, email addresses or phone numbers. Every export writes an entry to the community's audit log.
Subprocessor management
Havara uses a small set of third-party services ("subprocessors") to run. The list below reflects what is actually wired into the product. Two entries (PostHog, and TypeSafe) do nothing today: PostHog unless explicitly configured, TypeSafe until its activation is approved. Every other entry in the table below is live and processing today. The table covers the vendors wired into the app itself; the canonical list, read against the app on 2026-09-25, is the Subprocessor List, which also covers Stripe (community billing) and Cloudflare (DNS, TLS, CDN, and hosting for the web console and marketing site).
| Subprocessor | What it does | Data it sees | Region |
|---|---|---|---|
| Supabase | Primary backend: database, auth, file storage, Edge Functions, push orchestration | All account data, memberships, user-generated content, documents and embeddings, AI Ask history, push tokens, notification preferences, audit/moderation records; Supabase's own request and sign-in logs (each request's IP address, user agent and the approximate location derived from it, with the member's user id when signed in and the email address on sign-in events, kept 7 days) | Hosted Supabase project in the United States, region us-east-2 (US East / Ohio) |
| OpenAI | Text embeddings for Ask search, and the moderation service every Ask question is sent to before it is answered (a moderation call that times out or errors lets the question through rather than blocking it). Does not perform OCR; scanned PDFs go to AWS Textract (see the AWS row). (OpenAI does not generate answers or thread titles; titles are derived on the device with no AI call.) | Document text, in chunks, when a document is indexed; and the member's question text, sent twice: once to the moderation endpoint and once to the embeddings endpoint, prefixed on a follow-up by the previous question in that thread. Not the retrieved excerpts, which go to Anthropic. No account identifiers in the request body | US-based API (api.openai.com) |
| Amazon Web Services | Optical character recognition of scanned / image-only PDFs, via Amazon Textract's asynchronous plain-text detection (StartDocumentTextDetection). The PDF is copied to a private, encrypted, public-access-blocked S3 bucket for the duration of the scan and Havara deletes that staged copy after the scan, with a 1-day lifecycle rule as backstop. AWS's service terms allow it to store what Textract processes to provide and maintain the service, and would also let it use that content to improve Textract and other Amazon AI services, and keep some of it in another AWS region, unless an AWS AI services opt-out is in place; Havara has had that opt-out in place since September 23, 2026, covering Textract and every other AI service the policy covers. Documents that already contain selectable text are never sent. | The bytes of scanned PDFs with no text layer, and the text recognized from them. No account or community identifiers are sent; the staged object's key carries the document's internal id. | US-based API (textract.us-east-1.amazonaws.com, s3.us-east-1.amazonaws.com) |
| Anthropic | Generates the cited, documents-only Ask answer from retrieved excerpts | The question, prior turns in the thread, and the retrieved document excerpts; no account identifiers in the request body | US-based API (api.anthropic.com) |
| Expo (EAS / push) | Delivers push notifications; also the build/distribution pipeline | Device push tokens and notification title/body/route (which may include message previews unless the member turns previews off) | US-based service (exp.host) |
| Apple | iOS app distribution (App Store / TestFlight) and APNs push delivery | App distribution metadata and APNs push payloads relayed to iOS devices | US-based service |
| Android push delivery through Firebase Cloud Messaging, and Android app distribution through Google Play | Android push payloads (the same title and body Expo receives, which may include message previews unless the member turns previews off) and app distribution metadata | Google global infrastructure | |
| TypeSafe | Conditional, currently disabled. If Havara switches it on, after 30 days' notice on the Subprocessor List, it would judge how well retrieved excerpts support an Ask answer; nothing is sent to it today | The current question, at most the preceding question, and up to six retrieved excerpts; no account, community or document identifiers | Region to be confirmed before activation |
| Resend (LIVE since 2026-08-05) | Sends email: sign-in emails, community invitations, member email about a member's own account, home and community, email copies of notifications a push did not reach, vendor quote-request relays, announcement email mirroring, and operator alerts. The Subprocessor List has the full list | Recipient email addresses and what each email says: for example the community name and invite code; vendor contact details and, on a quote relay, the requesting resident's phone number and email address; announcement content mirrored to member email | US-based services (api.resend.com, and smtp.resend.com for sign-in emails) |
| PostHog (optional) | Product analytics. Double-gated: requires both an analytics key (not set) and the individual member's in-app opt-in (default off, fail-closed) | Event names with non-PII properties (ids, enums, counts) and a distinct user id; by enforced rule, no email, phone, push tokens, or message bodies | PostHog US cloud by default; EU/self-hosted host is configurable |
| Sentry (LIVE since 2026-08-26) | Crash and error reporting over HTTP, switched on in every production build of the app. Covers uncaught JavaScript errors via a global handler and the errors the app catches and forwards itself. No native SDK, so no automatic breadcrumbs, no performance traces, no device fingerprinting | The error type and message; the stack trace when a real Error was thrown; the event level, environment and release; a caller-supplied call-site scope and context object; the signed-in account's Supabase user id; the approximate location (city, region and country) Sentry derives from the IP address each report arrives from, kept with the report; and, from app versions that do not ask Sentry not to keep it, possibly that IP address, which Sentry keeps only while its project setting against storing IP addresses is off (not yet checked against a stored event). Never message bodies, email, phone or push tokens | Sentry US ingest endpoint (o4511541325004800.ingest.us.sentry.io) |
How we manage this list:
- Resend is LIVE (since 2026-08-05) and Sentry is LIVE (since 2026-08-26); neither is optional in practice any more. Sentry's configuration key was added to the app's production build settings on 2026-08-21 and the first crash events arrived on 2026-08-27. For a period this document described a live crash-reporting processor, one that receives an account identifier, as inert. PostHog alone remains off: no analytics key is set in the app's production build and the per-member in-app opt-in defaults to off and fails closed, so it degrades to a no-op and ships inert. The env-gated design still holds for PostHog, so a deployment can run with a deliberately minimal subprocessor footprint. It stopped being an accurate description of Resend when its keys were set, and of Sentry when its DSN was set.
- A strict, code-enforced rule keeps personal identifiers (email, phone, push tokens, message bodies) out of analytics events.
- We will notify customers before adding or materially changing a subprocessor that handles community data, per the process in our agreement. We commit to at least 30 days' advance notice, by email to affected customers and by updating the published Subprocessor List at https://havara.app/subprocessors, before a new subprocessor processes community personal data, per §7 of our Data Processing Addendum.
Certifications and roadmap
We want to be precise here, because security claims are easy to inflate.
- Havara is not currently SOC 2 certified, and is not ISO 27001, HIPAA, or PCI certified. We do not hold any third-party security certification or completed audit at this time. We will not claim one until it is actually completed.
- Havara runs on SOC 2-compliant infrastructure. Our primary backend, Supabase, maintains its own SOC 2 compliance for the platform we build on. Inheriting compliant infrastructure is not the same as Havara itself being certified, and we will not represent it as such. (Supabase's compliance posture is published at https://supabase.com/security.)
- SOC 2 is on our roadmap. As Havara grows, pursuing a SOC 2 Type II examination is our intended next step in formalizing security assurance. We do not commit to a specific timeframe at this stage.
We deliberately avoid marketing language like "bank-grade," "military-grade," or "unhackable." No system is perfectly secure. What we offer instead is the specific, verifiable set of controls described above, and an honest account of where we are on the path to formal certification.
Provider: Havara LLC, a Georgia limited liability company, 525 Tribble Gap Rd, P.O. Box 724, Cumming, GA 30040 Security contact: privacy@havara.app