Access control — ZevSend¶
Who can access what. The hard rules — implemented in code — are detailed below; the soft rules (employee onboarding, key rotation cadence, etc.) sit with the DPO office and platform security pages.
Customer-facing¶
- Customers see only their own teams. A customer's API request must include a team context (via the active session); the team-membership check runs in middleware before any controller / resolver.
- Within a team, the team owner has every permission. Member roles (today: simple member; finer-grained roles will be added when customer demand justifies the complexity) get scoped read / write on team resources.
- API keys carry per-key scopes — including optional domain pinning so a key restricted to one domain cannot dispatch from a sibling domain on the same team.
- API key env separation is server-enforced: the setup wizard mints only test keys (and only when the team has zero active keys); the
/api-keyspage mints only live keys (and only when an admin-approved domain exists on the team).
Admin (engineering / ops)¶
- All admin access goes through the admin panel at the
admin.*host. Same ZevID OAuth flow as the customer dashboard, additionally gated by an RBAC permission list. - Each admin endpoint declares its required permission via
@RequireAdminPermission(...). The decorator is the enforcement; permissions are not optional comments. - Sensitive admin mutations (plan change, invoice mark-paid) additionally require the
x-admin-mfa-tokenheader, verified server-side against ZevID before the resolver runs (theAdminMfaGuard). - Domain review (
DOMAINS_REVIEW) is separate from the suspension permissions (TEAMS_SUSPEND) so an ops teammate handling brand approvals doesn't automatically get the ability to take a team offline. - Display-name + sender-id reviews ride the same
DOMAINS_REVIEWpermission today (small surface). - Every admin write produces an
admin_actionsrow.
Production database¶
- Direct DB access is held by the lead engineer (Daniel Arowolo) only. Day-to-day operations go through the application or admin panel, never raw SQL.
- The application runtime connects via a scoped Postgres user. Migrations apply via a dedicated migration step on deploy (
MIGRATIONS_RUN_ON_BOOT=trueis the supported path; the migration connection uses an unpooled Neon URL so DDL doesn't split across pooled sessions).
Production infrastructure¶
- Coolify (Hetzner Ashburn) — host-level access held by the lead engineer.
- AWS SES (production account) — IAM credentials scoped to the
zevsend-defaultconfiguration set; held in deploy-platform secrets. - AWS SNS topic for SES feedback — subscription endpoint pinned to
prod.zevsend.com/webhooks/aws-sns; signature-verified per request. - Redis (BullMQ) — connection credentials held in deploy-platform secrets.
Cross-product (ZPIP) access¶
- Inbound ZPIP calls (other Zev products asking ZevSend to send mail on the user's behalf) require:
- A valid ZPIP service+user token from ZevID
- A user-consent grant for the requested scope (e.g.
zevsend.send) - The target resource (the from-domain) belonging to the user named in the token
- Outbound ZPIP calls ZevSend makes (e.g. to ZevCloud's
dns.records.writescope when provisioning DKIM on a zevcloud-managed domain) carry HMAC-SHA256 signatures and a per-scope consent token resolved at ZevID.
Reviews¶
Permission membership reviews are not yet on a fixed cadence — at our current size the admin headcount is one. When ops grows, the review cadence will be formalised (default candidate: quarterly).