Architecture

How it works under the hood.

For the technical stakeholders who need to know before they sign off.

The product

Envoy Recruit is a web application at app.envoyrecruit.com. Customers sign in with an email magic link, describe the work they want done, and the platform either drafts it for review or executes it against connected systems. There is no native app to install, no admin tenant consent, no browser extension. Any modern browser works.

Tenant isolation

The trust boundary is built from four cooperating pieces. Each one would be enough to defend the platform on its own; together they make data exfiltration a multi-failure event.

1. Per-tenant database and per-tenant key

Each customer organization gets a dedicated Postgres Flexible Server database inside our Azure subscription. The database does not share storage with any other customer. Encryption at rest uses a customer-managed key (CMK) stored in a per-tenant Azure Key Vault. We can rotate or destroy that key on customer request; doing so renders all snapshots of the customer's data unreadable, including any retained backups.

The application connects to the database as a least-privilege role (envoy_app) with no SUPERUSER and no BYPASSRLS attributes. Administrative migrations run as a separate role and are limited to the CI/CD pipeline.

2. Row-level security in the database

Every tenant-scoped table — templates, jobs, candidates, documents, audit log — has Postgres row-level security enabled and forced. The policy on each table requires a session-local setting (app.org_id) to match the row's organization_id. The application wraps every tenant query in a transaction that sets that variable; without it, the policy returns zero rows and rejects writes.

This means a missing tenant-scoping check in application code fails closed at the database layer — no data is returned, rather than the wrong data.

3. Redaction on every AI call

Before any prompt leaves our infrastructure for a model provider (Anthropic primary, OpenRouter fallback), sensitive values in the input are redacted. They are detected by two parallel paths — a hardcoded regex catalog and Azure AI Language NLP — and replaced with typed placeholders:

  • "Bryant Herrman" becomes <<CANDIDATE_NAME_0>>
  • "bcherrman@gmail.com" becomes <<EMAIL_0>>
  • "$185,000" becomes <<SALARY_0>>
  • "Acme Supply Co" becomes <<CLIENT_NAME_0>>
  • SSNs, phone numbers, addresses, work-auth status, client account IDs, and 25+ other pattern types are detected and replaced

The model processes the redacted message and returns a response using the same placeholders. We rehydrate them server-side before writing anything back to the database or showing it to the recruiter. The model provider — Anthropic, on our API tier — never sees raw values, and per their API terms does not train on API customer data.

This is architectural protection, not a policy promise. Even if a model accidentally echoes a placeholder back at us, no raw value travelled.

4. LLM audit log

Every AI call writes a row to a per-tenant audit table. The row contains: timestamp, module that initiated the call, model and tier, placeholder counts per category, total tokens in and out, latency. It does not contain the prompt, the response, the placeholders themselves, or any raw values.

The audit log is the artifact you hand to your auditor, your hiring client's compliance team, or anyone who asks "what did the AI see?" It answers that question without ever having had a copy of the answer to spill.

Authentication and tenancy

Authentication runs through NextAuth 5. Sign-in is by email magic link (Resend) on day one; Microsoft Entra ID and Google SSO are available behind feature flags for firm deployments. The session is a JWT with a membershipId claim that pins the request to exactly one organization. Every protected route in the application reads that claim and resolves the tenant context before any database query.

Cross-tenant access is impossible at the application layer (the JWT only resolves one membership), the database layer (row-level security blocks the read), and the storage layer (blob containers and key vaults are scoped per tenant).

Document handling

Document upload flows to a per-tenant Azure Blob Storage container, encrypted at rest with the same customer-managed key as the database. Resumes, JDs, and other files never live outside that container. OCR for PDFs and DOCX runs via Azure Document Intelligence; that service operates on the document but does not retain it.

What the platform sends out

Three categories of network call leave the customer's tenant:

  • To Anthropic (or OpenRouter fallback): redacted prompts, expecting a redacted response. Never raw data.
  • To Azure AI Language: redacted text for NLP-based PII detection, when Azure has not already redacted it via regex. Microsoft does not retain or train on these calls per the Azure Cognitive Services data policy.
  • To Azure Document Intelligence: the document itself for OCR, when uploaded. Microsoft does not retain or train on these calls.

Off-boarding

When a customer cancels, the customer-managed key is destroyed at the cancellation date. The tenant database, blob container, and any retained backups become permanently unreadable from that moment, even though the underlying bytes may persist on disk for the storage provider's standard retention window. The tenant resources themselves are deprovisioned after 30 days, allowing a re-subscribe window with full data recovery if the customer changes their mind before the key is destroyed.

Service tiers

Tiers govern capacity and scope, not data security. Every tier gets the same per-tenant database, the same customer-managed key, the same redaction before every AI call, the same audit log.

  • Starter: Independent recruiter or 2 to 10 person staffing shop. Standard processing.
  • Professional: Multiple recruiters in one firm. Faster processing, priority support.
  • Enterprise: Custom integrations, dedicated onboarding, SLA, optional region / residency selection.

Questions about the architecture?