General Rules
- Store hosted deployment credentials in environment-scoped GitHub Actions secrets.
- Store Vercel app runtime and build-time configuration in the Vercel project environment, not workflow-wide GitHub Actions environment variables.
- Store local web runtime configuration in
apps/web/.env.local. - Do not commit tokens, keys, passwords, or rendered env dumps.
- Do not edit checked-in compose files to inject per-environment secrets.
Local And Self-Hosted Web
| Location | Purpose |
|---|---|
apps/web/.env.local | Docker build secret input and runtime env file for the web app |
| Shell environment | Optional overrides such as DOCS_PORT, SUPABASE_SERVER_URL, or UPSTASH_REDIS_REST_* when you intentionally override the Docker helpers |
tmp/docker-web/prod/ | Generated local deployment state for blue/green rollout |
GitHub Actions Secrets By Area
Vercel-hosted web apps
Vercel workflows use GitHub Environments namedvercel-preview-<app> and
vercel-production-<app>. Keep the deployment secrets on those environments,
not as workflow-level env: entries. Production environments should require
reviewers and restrict deployment branches to production; preview environments
should require review whenever branch pushes can run repository-controlled code
with deployment credentials.
VERCEL_TOKENVERCEL_ORG_ID- App-specific
VERCEL_PROJECT_IDvalues such asVERCEL_PLATFORM_PROJECT_IDandVERCEL_APPS_PROJECT_ID - QR deployments use
VERCEL_QR_PROJECT_IDin thevercel-preview-qrandvercel-production-qrGitHub Environments
Production and preview app configuration
These values belong in the Vercel project environment for each app and target. Do not export them from GitHub Actions workflows. The Vercel deploy workflows run repository code during install and build, so workflow-wide production runtime secrets are a supply-chain exposure path.PRODUCTION_SUPABASE_URLPRODUCTION_SUPABASE_PUBLISHABLE_KEYPRODUCTION_SUPABASE_SECRET_KEYENCRYPTION_MASTER_KEY- Optional Turborepo remote-cache credentials such as
TURBO_TOKENandTURBO_TEAM
Integration-specific runtime secrets
- SePay OAuth requires
SEPAY_OAUTH_CLIENT_ID,SEPAY_OAUTH_CLIENT_SECRET,SEPAY_OAUTH_TOKEN_ENCRYPTION_SECRET, and a webhook auth secret such asSEPAY_WEBHOOK_API_KEY. - SePay web runtimes also require an app origin through
WEB_APP_URL,NEXT_PUBLIC_WEB_APP_URL, orNEXT_PUBLIC_APP_URLso OAuth callbacks and webhook provisioning can generate stable platform URLs. - SePay workspace enablement is controlled by the workspace secret
ENABLE_SEPAY_INTEGRATION=true. - SePay runtime overrides may optionally set
SEPAY_OAUTH_AUTHORIZE_URL,SEPAY_OAUTH_BASE_URL, andSEPAY_API_BASE_URLwhen targeting non-default environments. - SePay OAuth state is stored in a short-lived HttpOnly callback cookie and is
HMAC-signed. The signer uses
SEPAY_OAUTH_STATE_SECRETwhen set; otherwise it falls back to the requiredSEPAY_OAUTH_CLIENT_SECRET.
Supabase migrations
SUPABASE_ACCESS_TOKENSTAGING_DB_PASSWORDSTAGING_PROJECT_IDSTAGING_DB_URLPRODUCTION_DB_PASSWORDPRODUCTION_PROJECT_IDPRODUCTION_DB_URL
Modal deployment
MODAL_TOKEN_IDMODAL_TOKEN_SECRETMODAL_ENVIRONMENTas a GitHub Actions variable
Package publishing
NPM_TOKENfor npm publication
Docker-Specific Notes
- The Docker web helper auto-generates a stable local Redis token and injects
UPSTASH_REDIS_REST_TOKEN,UPSTASH_REDIS_REST_URL, and the matching internalSRH_TOKENvalue for the bundledserverless-redis-httpcontainer. SRH_TOKENis the container’s internal environment variable. The user-facing override surface isUPSTASH_REDIS_REST_TOKENif you intentionally replace the helper-generated value.- The local dev compose file keeps a dev-only fallback token for direct local
use, but production Redis compose requires
UPSTASH_REDIS_REST_TOKENduring Compose interpolation. Use the Docker web helper or export a strong token before enabling the productionredisprofile directly. - Redis and
serverless-redis-httphost ports must stay loopback-bound. Do not publish those sidecars on all host interfaces or through Cloudflare Tunnel. apps/webuses Redis for security-sensitive one-time state such as CLI refresh-token replay protection. IfUPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKENare unavailable, CLI refresh requests fail closed instead of minting new sessions.docker compose configexpands env values; treat its output as sensitive.
Supabase RPC Authorization Hardening
- Treat every new
SECURITY DEFINERfunction inpublicas externally callable until proven otherwise. - In the same migration that creates or replaces the function, enforce both:
- in-function authorization checks (
auth.uid()plus workspace membership/permission gate), and - explicit execute privileges (
revoke all ... from public, then grant only required roles such asauthenticated/service_role).
- in-function authorization checks (
- Do not rely only on
apps/webpage or API RBAC checks for tenant isolation when an RPC is exposed through the Data API. - During review, grep the migration for
security definer,auth.uid(),has_workspace_permission,revoke, andgrant executebefore merge.
Change Management
When a new deployment flow is added:- Add its secret names here.
- Add the workflow or runtime page to the relevant devops doc.
- Keep the boundary clear between repo config, GitHub Actions config, and machine-local config.