Operations

This section covers everything required to keep the SONAN DIGITAL CRM running reliably in production. It is written for the engineering and operations team โ€” the people responsible for deploying, monitoring, maintaining, and responding to incidents on the platform.


Audience

Role Relevant Pages
Engineers All pages
Operations / DevOps Manual, Environment, Monitoring, Cron Jobs, Incident Response, Maintenance
Team Leads / Admins Onboarding guides, Manual (overview sections)

Pages in This Section

Operations Manual

The authoritative system overview. Covers what the CRM is, who uses it, the full infrastructure table, versioning and branching strategy, deployment frequency, support responsibilities, and escalation contacts. Start here if you are new to the platform.

Environment Configuration

Complete listing of all environment variables used by the application โ€” names, descriptions, where to find each value, which are public vs. server-only, and how to set up a local .env.local for development.

Secrets Management

How application secrets are stored, who has access, rotation schedules for every secret, the emergency rotation procedure for compromised credentials, and recommendations for upgrading to a secrets manager.

Monitoring & Logging

How to use Sentry for error tracking, how to access Vercel function logs, recommended UptimeRobot checks, alert escalation paths, cron job monitoring, and the weekly monitoring review checklist.

Cron Jobs

Documentation for all scheduled background jobs: the invoice overdue check, recurring invoice generation, and the appointments cron. Covers authentication, Vercel config, local testing, and what to do when a job fails.

Incident Response

The incident classification table (P1โ€“P4), the end-to-end response process from detection through post-mortem, escalation paths, and ready-to-use communication templates for P1 client outages.

Maintenance Schedule

Checklists for monthly, quarterly, and annual maintenance tasks โ€” dependency updates, security audits, RLS policy reviews, secret rotation, backup testing, and more.

Client Onboarding

The 8-step admin procedure for onboarding a new client: creating their CRM record, setting up portal access, assigning an account manager, and briefing the client. Includes a quick-reference checklist and common issue fixes.

Employee Onboarding

The step-by-step admin procedure for onboarding a new team member โ€” sending the invite, configuring their role and MFA, assigning projects, and briefing on time logging. Also covers the offboarding checklist.


๐Ÿ’ก
First time here?

Read the Operations Manual first for a full system overview, then review Environment Configuration to understand how the application is configured across environments.


Operations Manual

This document is the authoritative reference for operating the SONAN DIGITAL CRM in production. It covers system purpose, infrastructure, versioning, deployment, support responsibilities, and escalation contacts.


1. System Overview

The SONAN DIGITAL CRM is a multi-tenant web application built to manage the full client lifecycle for a digital agency. It serves two classes of users:

  • Admin / Staff users โ€” the agency's internal team. They use the CRM to manage leads, clients, projects, tasks, time logs, proposals, invoices, contracts, and support tickets.
  • Client users โ€” agency clients who log in to a self-service portal to view proposals, sign contracts, pay invoices, track project progress, and submit support requests.

The application is a single Next.js 15 codebase deployed on Vercel. All data lives in a Supabase PostgreSQL database, with row-level security (RLS) enforcing tenant isolation. Authentication is handled by Supabase Auth. File uploads (contracts, attachments) go to Supabase Storage. Transactional emails are sent via Resend. Payments and subscriptions are handled by Stripe. Errors are tracked in Sentry.

The system is designed to be always-on โ€” clients interact with the portal and expect real-time access to invoices and project status. Any unplanned downtime directly impacts client trust.


2. Infrastructure

Service Provider Region Plan URL / Identifier Criticality
App hosting Vercel Global Edge (CDN) Team sonan-digital.vercel.app + custom domain Critical
Database Supabase (PostgreSQL) us-east-1 Pro Supabase project dashboard Critical
Auth Supabase Auth Same project Included in Pro โ€” Critical
Storage Supabase Storage Same project Included in Pro โ€” High
Email delivery Resend Global Scale plan resend.com dashboard High
Payments Stripe Global Standard dashboard.stripe.com High
Error tracking Sentry Global Team sentry.io โ€” SONAN DIGITAL org High
DNS / CDN Cloudflare Global Free/Pro Cloudflare dashboard High
Docs portal Cloudflare Pages Global Free Separate Cloudflare Pages project Low
โ„น๏ธ
Edge Runtime

All Next.js routes and pages use export const runtime = 'edge'. This means API routes run on Vercel's Edge network โ€” not Node.js lambdas. Keep this in mind when debugging: function logs appear under the Edge Logs filter in the Vercel dashboard, not Function Logs.


3. Versioning

The CRM follows semantic versioning (MAJOR.MINOR.PATCH):

Increment When to use
PATCH Bug fixes, copy changes, minor UI tweaks
MINOR New features, non-breaking API changes, new CRM modules
MAJOR Breaking changes, major architectural overhauls, multi-tenant schema changes

Current version: v1.0.0

Version is tracked in package.json. On each release, tag the commit in Git:

git tag -a v1.2.0 -m "Release v1.2.0: recurring invoices, wiki module"
git push origin v1.2.0

4. Branching Strategy

Branch Purpose Deploys to
main Production code Vercel Production environment
dev Staging / preview Vercel Preview environment
Feature branches Work in progress Vercel Preview (per-branch)

Rules:

  • Never commit directly to main for non-emergency changes.
  • All changes go through a pull request: feature/* โ†’ dev โ†’ main.
  • dev is used for QA and client-facing preview URLs before production release.
  • Emergency hotfixes can be pushed directly to main with a post-merge PR for review โ€” document in the incident report.
โš ๏ธ
FUSE-mounted workspace

The development environment uses a FUSE-mounted filesystem. Always follow the FUSE-safe git commit pattern (documented in CLAUDE.md) to avoid blob truncation. Never use git add directly on mounted paths โ€” use the git plumbing workflow via /tmp.


5. Deployment

Deployment is triggered automatically by a push to the relevant branch:

Event Result
Push to main Production deployment on Vercel
Push to dev Preview deployment on Vercel
Open PR Ephemeral preview deployment for that PR

Deployment frequency: As needed. There is no fixed release schedule โ€” features and fixes are deployed when ready and tested on dev.

Deployment checklist before merging to main:

  • [ ] All new API routes include export const runtime = 'edge'
  • [ ] Database migrations have been applied to the Supabase production project
  • [ ] Any new environment variables have been added to Vercel (Production + Preview)
  • [ ] The change has been tested on the dev preview environment
  • [ ] No new TypeScript errors (npx tsc --noEmit)
  • [ ] Sentry is not reporting new errors from the preview environment

Rollback: Vercel retains all previous deployments. To roll back, go to the Vercel dashboard โ†’ Deployments โ†’ select the last known-good deployment โ†’ "Promote to Production". This is the fastest recovery path for bad deployments.


6. Support Responsibilities

Area Responsible Party Notes
Application bugs Engineering team Triaged via Sentry; P1/P2 get immediate response
Database / schema changes Engineering team Via Supabase SQL editor; must update RLS policies
Email delivery issues Engineering team + Resend support Check Resend logs first; escalate to Resend support if delivery is failing at provider level
Payment issues Engineering team + Stripe support Check Stripe dashboard for webhook failures; Stripe has 24/7 support for payment disputes
Client portal access issues Admin team (first line) โ†’ Engineering (second line) Admins can resend invites and reset passwords; engineering handles auth bugs
Infrastructure / hosting Vercel support Raise a support ticket via Vercel dashboard for platform-level issues
SSL / DNS Cloudflare support Auto-renewed SSL; DNS changes via Cloudflare dashboard
Sentry / error tracking Engineering team Weekly review cadence

7. Escalation Contacts

โ„น๏ธ
Note

Replace the placeholder names and contacts below with actual team members.

Role Name Contact Escalation Trigger
Primary Engineer {{ PRIMARY_ENGINEER_NAME }} {{ PRIMARY_ENGINEER_EMAIL }} All P1/P2 incidents
Tech Lead / CTO {{ TECH_LEAD_NAME }} {{ TECH_LEAD_EMAIL }} P1 incidents, security breaches
Operations Manager {{ OPS_MANAGER_NAME }} {{ OPS_MANAGER_EMAIL }} Client-facing P1/P2 communication
Vercel Support Vercel team vercel.com/support Platform / hosting failures
Supabase Support Supabase team supabase.com/support Database / auth failures
Stripe Support Stripe team support.stripe.com Payment processing failures
Resend Support Resend team resend.com/support Email delivery failures
๐Ÿšจ
P1 Response

For a full production outage (P1), contact the Primary Engineer and Tech Lead simultaneously โ€” do not wait for the Primary Engineer to be unreachable before looping in the Tech Lead.


Environment Configuration

This page documents all environment variables used by the SONAN DIGITAL CRM, how they are organized across environments, where to find their values, and how to set up a local development environment.


1. Vercel Environments

The application runs in three Vercel environments. Each has its own set of environment variable values:

Environment Branch URL Purpose
Production main https://yourdomain.com Live system โ€” real clients, real payments
Preview dev + all PRs Auto-generated Vercel preview URL QA and staging โ€” safe to test with real Stripe test keys
Development Local machine http://localhost:3000 Engineer local development
โš ๏ธ
Production vs. Preview secrets

Production and Preview environments should use different Stripe keys. Production uses Stripe live keys (sk_live_...). Preview/Development should use Stripe test keys (sk_test_...). Using live keys in preview environments risks accidental real charges.

To manage environment variables, go to the Vercel Dashboard โ†’ Project โ†’ Settings โ†’ Environment Variables.


2. Environment Variable Reference

Supabase

Variable Value Scope Description
NEXT_PUBLIC_SUPABASE_URL {{ SUPABASE_PROJECT_URL }} Public The Supabase project URL, used by both the client and server SDK. Found in Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ Project URL.
NEXT_PUBLIC_SUPABASE_ANON_KEY {{ SUPABASE_ANON_KEY }} Public The Supabase anonymous (public) key. Used by the browser client. This key is safe to expose โ€” it is restricted by RLS. Found in Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ Project API keys โ†’ anon public.
SUPABASE_SERVICE_ROLE_KEY {{ SUPABASE_SERVICE_ROLE_KEY }} Server only The Supabase service role key. Bypasses RLS โ€” used for admin operations only. Found in Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ Project API keys โ†’ service_role secret. Never expose this key client-side.

Email โ€” Resend

Variable Value Scope Description
RESEND_API_KEY {{ RESEND_API_KEY }} Server only API key for sending transactional emails via Resend. Found in Resend Dashboard โ†’ API Keys.

Payments โ€” Stripe

Variable Value Scope Description
STRIPE_SECRET_KEY {{ STRIPE_SECRET_KEY }} Server only Stripe secret key used for creating payment intents, managing subscriptions, and other server-side Stripe API calls. Found in Stripe Dashboard โ†’ Developers โ†’ API keys โ†’ Secret key. Use sk_live_... for Production, sk_test_... for Preview/Dev.
STRIPE_WEBHOOK_SECRET {{ STRIPE_WEBHOOK_SECRET }} Server only Signing secret for verifying Stripe webhook payloads. Found in Stripe Dashboard โ†’ Developers โ†’ Webhooks โ†’ select the webhook endpoint โ†’ Signing secret.
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY {{ STRIPE_PUBLISHABLE_KEY }} Public Stripe publishable key used in the browser to initialize Stripe.js. Found in Stripe Dashboard โ†’ Developers โ†’ API keys โ†’ Publishable key. Use pk_live_... for Production, pk_test_... for Preview/Dev.

Background Jobs

Variable Value Scope Description
CRON_SECRET {{ CRON_SECRET }} Server only A long random string (minimum 32 characters) used to authenticate requests to cron job endpoints. Generate with openssl rand -hex 32. Must match the Authorization: Bearer header sent by Vercel Cron.

Error Tracking โ€” Sentry

Variable Value Scope Description
NEXT_PUBLIC_SENTRY_DSN {{ SENTRY_DSN }} Public The Sentry Data Source Name (DSN) for your project. Used to report errors from both client and server code. Found in Sentry Dashboard โ†’ Project Settings โ†’ Client Keys (DSN).
SENTRY_AUTH_TOKEN {{ SENTRY_AUTH_TOKEN }} Server only Sentry authentication token with org:ci scope โ€” used during the build process to upload source maps. Found in Sentry Dashboard โ†’ Settings โ†’ Auth Tokens. Required for production-quality stack traces.

3. Public vs. Server-Only Variables

Prefix Exposure Risk if leaked
NEXT_PUBLIC_ Bundled into client JavaScript โ€” visible to anyone Low (these are designed to be public)
No prefix Never sent to the browser โ€” server/edge only High โ€” treat as secrets
๐Ÿšจ
Never expose server-only variables

Variables without the NEXT_PUBLIC_ prefix must never be referenced in client components ('use client'), passed as props to client components, or logged anywhere. If you accidentally expose SUPABASE_SERVICE_ROLE_KEY or STRIPE_SECRET_KEY client-side, rotate them immediately.


4. Where to Find Each Value

Variable Location
NEXT_PUBLIC_SUPABASE_URL Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ Project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ anon public key
SUPABASE_SERVICE_ROLE_KEY Supabase Dashboard โ†’ Project Settings โ†’ API โ†’ service_role key
RESEND_API_KEY Resend Dashboard โ†’ API Keys โ†’ Create API Key
STRIPE_SECRET_KEY Stripe Dashboard โ†’ Developers โ†’ API keys โ†’ Secret key
STRIPE_WEBHOOK_SECRET Stripe Dashboard โ†’ Developers โ†’ Webhooks โ†’ [endpoint] โ†’ Signing secret
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY Stripe Dashboard โ†’ Developers โ†’ API keys โ†’ Publishable key
CRON_SECRET Generated locally: openssl rand -hex 32
NEXT_PUBLIC_SENTRY_DSN Sentry โ†’ Project Settings โ†’ Client Keys (DSN)
SENTRY_AUTH_TOKEN Sentry โ†’ Settings โ†’ Auth Tokens โ†’ Create New Token (scope: org:ci)

5. Startup Validation

The application performs implicit validation at build time via TypeScript and at runtime via the Supabase and Stripe SDK initializers. If a required variable is missing:

  • NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY missing โ†’ Supabase client will throw during initialization. The application will fail to render.
  • SUPABASE_SERVICE_ROLE_KEY missing โ†’ createServiceClient() will throw on first admin API call.
  • STRIPE_SECRET_KEY missing โ†’ Stripe SDK initialization will throw; all payment routes will return 500.
  • CRON_SECRET missing โ†’ Cron endpoints will return 401 for all requests.
  • SENTRY_AUTH_TOKEN missing โ†’ The build will succeed but source maps will not be uploaded. Stack traces in Sentry will show minified code.

To verify all variables are loaded in a Vercel deployment:

  1. Go to Vercel Dashboard โ†’ Project โ†’ Deployments โ†’ select the deployment.
  2. Click View Build Logs โ€” any missing NEXT_PUBLIC_ variable will appear as undefined in the build output.
  3. Click View Function Logs and trigger an authenticated API request โ€” check for undefined or initialization errors in the log output.

6. Local Development Setup

Create a .env.local file in the project root. This file is git-ignored and should never be committed.

# .env.local โ€” Local development only. Never commit this file.

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGci...

# Resend (use a test API key or the real key for local testing)
RESEND_API_KEY=re_...

# Stripe โ€” use TEST keys for local development
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

# Cron protection
CRON_SECRET=your-local-random-secret-at-least-32-chars

# Sentry (optional for local dev โ€” can be omitted)
NEXT_PUBLIC_SENTRY_DSN=https://...@sentry.io/...
SENTRY_AUTH_TOKEN=sntrys_...

Starting the dev server:

npm install
npm run dev
# App available at http://localhost:3000
๐Ÿ’ก
Stripe webhooks locally

To test Stripe webhooks in local development, install the Stripe CLI and forward events to your local server:

stripe listen --forward-to localhost:3000/api/stripe/webhook

The CLI will print a webhook signing secret (whsec_...) โ€” use that as your local STRIPE_WEBHOOK_SECRET.

โ„น๏ธ
Supabase local vs. cloud

You can use the shared Supabase cloud project for local development (easiest setup) or run a local Supabase stack with supabase start. For most development work, pointing local dev at the cloud dev/staging project is sufficient.


Secrets Management

This page documents how application secrets are stored, who has access to them, the rotation schedule for each secret, the procedure for emergency rotation, and recommendations for upgrading the secrets infrastructure.


1. Where Secrets Are Stored

All secrets are stored as Vercel Environment Variables, which are:

  • Encrypted at rest using Vercel's infrastructure-level encryption.
  • Scoped per environment (Production, Preview, Development).
  • Never written to disk or committed to version control.
  • Accessible only to authenticated Vercel team members with the appropriate role.

Rules that must never be broken:

  • No secret is ever written into source code.
  • No .env file containing real secrets is ever committed to git. .env.local is in .gitignore โ€” verify this before any git add ..
  • Secrets are never logged, printed, or included in error messages.
  • Secrets are never passed as URL query parameters.
๐Ÿšจ
If a secret appears in git history

If a secret is accidentally committed to git โ€” even on a private repo โ€” treat it as compromised. Immediately follow the Emergency Rotation Procedure for that secret. Removing it from git history (via git filter-branch or BFG) does not guarantee it was not already read or cached.


2. Secrets Inventory

Secret Name Provider Purpose Rotation Recommended Last Rotated
SUPABASE_SERVICE_ROLE_KEY Supabase Admin database access, bypasses RLS Every 6 months {{ DATE_LAST_ROTATED }}
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase Browser client (public, restricted by RLS) On suspected compromise {{ DATE_LAST_ROTATED }}
RESEND_API_KEY Resend Transactional email sending Every 12 months {{ DATE_LAST_ROTATED }}
STRIPE_SECRET_KEY Stripe Payment API (live) Every 12 months {{ DATE_LAST_ROTATED }}
STRIPE_WEBHOOK_SECRET Stripe Webhook payload verification On endpoint URL change {{ DATE_LAST_ROTATED }}
CRON_SECRET Self-generated Cron job endpoint authentication Every 6 months {{ DATE_LAST_ROTATED }}
SENTRY_AUTH_TOKEN Sentry Source map upload during CI Every 12 months {{ DATE_LAST_ROTATED }}
โ„น๏ธ
Note

NEXT_PUBLIC_SUPABASE_URL and the Stripe publishable key are not secret โ€” they are intentionally public and do not need rotation unless the project or account changes.


3. Rotation Schedule

SUPABASE_SERVICE_ROLE_KEY โ€” Every 6 months

This key bypasses all RLS policies and has full database access. It is the highest-risk secret in the system.

  1. Go to Supabase Dashboard โ†’ Project Settings โ†’ API.
  2. Scroll to Project API keys โ€” click the service role key's Reveal button.
  3. Click Reset (Supabase will generate a new key; the old key becomes invalid immediately).
  4. Copy the new key and update it in Vercel (see rotation steps below).
  5. Trigger a Vercel redeploy to load the new value.

STRIPE_SECRET_KEY โ€” Every 12 months or on suspected compromise

  1. Go to Stripe Dashboard โ†’ Developers โ†’ API keys.
  2. Click Roll key next to the secret key. Stripe lets you set a 24-hour delay before the old key is invalidated โ€” use this window to update and test before the old key expires.
  3. Update STRIPE_SECRET_KEY in Vercel.
  4. Redeploy and verify Stripe API calls succeed.

RESEND_API_KEY โ€” Every 12 months or on suspected compromise

  1. Go to Resend Dashboard โ†’ API Keys.
  2. Create a new API key.
  3. Update RESEND_API_KEY in Vercel.
  4. Redeploy and send a test email to confirm delivery.
  5. Delete the old API key from the Resend dashboard.

CRON_SECRET โ€” Every 6 months

  1. Generate a new secret locally: bash openssl rand -hex 32
  2. Update CRON_SECRET in Vercel (Production and Preview).
  3. Update the secret in vercel.json under the cron authorization header if it is stored there (it should not be โ€” the cron routes read it from the environment).
  4. Redeploy and verify a cron manual trigger works.

STRIPE_WEBHOOK_SECRET โ€” On endpoint URL change

The webhook signing secret is tied to the registered endpoint URL in Stripe. If the production URL changes:

  1. Go to Stripe Dashboard โ†’ Developers โ†’ Webhooks.
  2. Add the new endpoint URL.
  3. Copy the new signing secret.
  4. Update STRIPE_WEBHOOK_SECRET in Vercel.
  5. Delete the old webhook endpoint from Stripe.

SENTRY_AUTH_TOKEN โ€” Every 12 months

  1. Go to Sentry โ†’ Settings โ†’ Auth Tokens.
  2. Create a new token with org:ci scope.
  3. Update SENTRY_AUTH_TOKEN in Vercel.
  4. Delete the old token.

4. Emergency Rotation Procedure

Use this procedure when a secret is known or suspected to be compromised โ€” leaked in logs, committed to git, exposed in an error message, or accessed by an unauthorized party.

Treat every suspected compromise as a confirmed compromise. Do not wait for confirmation.

Step-by-Step

  1. Revoke the old key immediately in the provider dashboard โ€” do not wait.
  2. Supabase service role key: Supabase Dashboard โ†’ API โ†’ Reset
  3. Stripe key: Stripe Dashboard โ†’ Developers โ†’ API keys โ†’ Roll key (set 0 delay)
  4. Resend key: Resend Dashboard โ†’ API Keys โ†’ Delete
  5. Cron secret: Skip to step 2 (self-generated, just replace it)
  6. Sentry token: Sentry โ†’ Settings โ†’ Auth Tokens โ†’ Revoke

  7. Generate the new key/secret in the provider dashboard.

  8. Update in Vercel โ€” go to Vercel Dashboard โ†’ Project โ†’ Settings โ†’ Environment Variables:

  9. Update the value for Production, Preview, and Development scopes as applicable.

  10. Trigger a redeploy โ€” in Vercel Dashboard โ†’ Deployments โ†’ click Redeploy on the latest production deployment. The new environment variable is picked up immediately.

  11. Verify the application works โ€” check the feature that uses the rotated secret (e.g., send a test email after rotating RESEND_API_KEY, make a test payment after rotating STRIPE_SECRET_KEY).

  12. Check for unauthorized activity โ€” review provider dashboards for any suspicious API calls during the window when the key may have been compromised:

  13. Supabase: Database โ†’ Logs
  14. Stripe: Dashboard โ†’ Developers โ†’ Events
  15. Resend: Dashboard โ†’ Emails โ†’ Sent

  16. Document the rotation โ€” update the Last Rotated date in the Secrets Inventory table above, and record the incident in the incident log with: date discovered, suspected exposure window, scope of potential access, and actions taken.

  17. Notify the team โ€” send an internal notification to all engineers noting the rotated secret and confirming the old key is no longer valid.

๐Ÿšจ
Do not delay revocation

Every minute a compromised key remains active is a minute it can be used. Revoke first, then sort out the replacement. It is acceptable to have a brief (minutes) service degradation while a new key is set up โ€” it is not acceptable to leave a compromised key active while you investigate.


5. Vault and Secrets Manager Options

Current Setup: Vercel Environment Variables

Vercel's built-in environment variables are encrypted at rest and access-controlled by Vercel team roles. This is appropriate for small teams and single-project setups.

Limitations: - No audit log of who accessed a secret's value. - No automatic rotation. - Rotation requires a manual redeploy.

If the team expands beyond ~5 engineers or begins handling particularly sensitive client data, consider migrating to a dedicated secrets manager:

Tool Pros Cons
Infisical Open-source option; self-hostable; Vercel integration; audit logs Requires setup and maintenance if self-hosted
Doppler Seamless Vercel sync; per-environment scoping; access logs; auto-rotation hooks Paid for team features
HashiCorp Vault Industry standard; very powerful Complex setup; overkill for this scale

For the current scale, Vercel environment variables remain appropriate. Re-evaluate when the team adds a dedicated DevOps role.


6. Access Control

Access to Vercel environment variables is controlled by Vercel team roles:

Role Can view secret values Can edit secrets Can delete secrets
Owner Yes Yes Yes
Member (Admin) Yes Yes Yes
Member (Developer) No (masked) No No
โš ๏ธ
Principle of Least Privilege

Only team members who actively need to rotate or manage secrets should have Owner or Admin roles on the Vercel project. Engineers who only deploy code can work with Developer access.

To review current team access: Vercel Dashboard โ†’ Team Settings โ†’ Members.