Workspaces and members
Nerve isolates data by workspace. Every API key, provider credential, notification template, subscriber record, and delivery event belongs strictly to one workspace.
Tenant boundary isolation
Tenant isolation is enforced in depth across every layer of the architecture:
- Database row-level security: The database itself enforces workspace scoping on every query; a query that is not scoped to exactly one workspace returns nothing. No application bug can expose one workspace's rows to another.
- Namespaced caches: Rate-limit and idempotency state is partitioned per workspace, so one workspace's traffic cannot affect another's limits or deduplication.
- Per-tenant circuit breakers: Upstream provider failures are tracked per workspace and provider, ensuring one workspace's provider error never trips breakers for another tenant.
Roles and permissions (RBAC)
Every user in a workspace holds one of three roles, governed by an immutable RBAC matrix:
| Action | Owner | Admin | Member |
|---|---|---|---|
| Manage Billing & Paystack Subscription | Yes | No | No |
| Delete Workspace / Transfer Ownership | Yes | No | No |
| Manage Team Members & Invites | Yes | Yes | No |
| Create & Revoke API Keys | Yes | Yes | No |
| Configure Provider Credentials & Test | Yes | Yes | No |
| Create, Update, & Delete Templates | Yes | Yes | No |
| View Messages, Timeline, & Analytics | Yes | Yes | Yes |
| Export Subscriber Data (NDPR Access) | Yes | Yes | Yes |
| Preview Template Rendering | Yes | Yes | Yes |
Owner protection
A workspace must always have at least one owner. Demoting or removing the final owner is rejected by the control plane with 400 BAD_REQUEST.
Immediate session revocation
When a user is removed from a workspace, all active sessions for that user scoped to that workspace are immediately revoked in the database.
Inviting team members
Team members are invited via email through the dashboard or control plane:
curl -X POST https://console.nervly.io/console/invites \
-H "Cookie: nerve_session=$SESSION_COOKIE" \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "engineer@example.com",
"role": "admin"
}'
- 7-day expiration: Invite tokens are 32 cryptographically secure random bytes valid for exactly 7 days.
- Token hashing: Raw tokens are stored as SHA-256 hashes in PostgreSQL; tokens are never logged.
- Acceptance flow: Invites can be accepted by existing signed-in users or newly registering users via
POST /auth/invites/accept.