> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets & Configuration

> Where deployment configuration lives, and which secrets matter for each delivery surface.

This page documents secret names and configuration boundaries. It does not contain
secret values.

## 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 named `vercel-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_TOKEN`
* `VERCEL_ORG_ID`
* App-specific `VERCEL_PROJECT_ID` values such as `VERCEL_PLATFORM_PROJECT_ID`
  and `VERCEL_APPS_PROJECT_ID`
* Infrastructure deployments use `VERCEL_INFRASTRUCTURE_PROJECT_ID` in the
  `vercel-preview-infrastructure` and `vercel-production-infrastructure` GitHub
  Environments
* QR deployments use `VERCEL_QR_PROJECT_ID` in the `vercel-preview-qr` and
  `vercel-production-qr` GitHub Environments

### Turborepo remote cache

Remote-cache identity is repository-wide rather than app runtime
configuration:

* Store a dedicated, least-privilege Vercel team cache token as the repository
  secret `TURBO_TOKEN`. Rotate it independently from deployment tokens and
  revoke the previous token after trusted canaries pass.
* Store the Vercel team slug as the repository variable `TURBO_TEAM`. Workflows
  temporarily accept `secrets.TURBO_TEAM` as a migration fallback; remove that
  secret after the variable is confirmed.
* Leave `TURBO_API` unset for Vercel-managed remote caching.
* Do not configure `TURBO_REMOTE_CACHE_SIGNATURE_KEY` until artifact signing is
  deliberately enabled and rolled out.
* Optional repository variables `ACTIONS_CACHE_NOTICE_PERCENT`,
  `ACTIONS_CACHE_WARNING_PERCENT`, and `ACTIONS_CACHE_CRITICAL_PERCENT` override
  the weekly report's 80/90/100 thresholds. Cache size and retention are not
  variables; the report discovers both from GitHub's repository API.

Only pass these values as inputs to
`.github/actions/run-with-turbo-remote-cache/action.yml`. The action places them
on the wrapped command step, not the workflow, job, `GITHUB_ENV`, image layer,
or deployment artifact. Never pass `TURBO_TOKEN` to pull-request or Dependabot
jobs; secretless jobs use the task-family GitHub cache fallback.

### 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_URL`
* `PRODUCTION_SUPABASE_PUBLISHABLE_KEY`
* `PRODUCTION_SUPABASE_SECRET_KEY`
* `ENCRYPTION_MASTER_KEY`

Turborepo cache identity is the repository-level configuration described above,
not a Vercel app runtime secret. Do not duplicate it into every project's
runtime environment.

Individual workflows may also consume other application-specific secrets depending on
the deployed app.

### 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 as
  `SEPAY_WEBHOOK_API_KEY`.
* SePay web runtimes also require an app origin through `WEB_APP_URL`,
  `NEXT_PUBLIC_WEB_APP_URL`, or `NEXT_PUBLIC_APP_URL` so 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`, and `SEPAY_API_BASE_URL` when 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_SECRET` when set; otherwise it
  falls back to the required `SEPAY_OAUTH_CLIENT_SECRET`.
* Polar (inventory storefront checkout + workspace subscriptions) requires
  `POLAR_ACCESS_TOKEN` (platform-level org token) and `POLAR_WEBHOOK_SECRET`
  (webhook signature verification) on `apps/pay`. Set `POLAR_SANDBOX=true` to
  target Polar's sandbox, and the optional `POLAR_CURRENCIES` to allowlist
  storefront currencies. Configure Polar to deliver webhooks to
  `https://pay.tuturuuu.com/api/payment/webhooks`; `apps/web` no longer owns
  payment API or webhook routes. See the Polar storefront integration runbook
  for details.
* Square Terminal (Inventory + Storefront pay-at-terminal checkout) stores
  Square application credentials, OAuth/manual tokens, webhook signature keys,
  locations, terminal ids, and webhook notification URL overrides encrypted from
  Inventory settings. Do not configure Square credentials as deployment secrets.
  See the Square Terminal integration runbook for the complete setup and smoke
  checklist.

### Supabase migrations

* `SUPABASE_ACCESS_TOKEN`
* `STAGING_DB_PASSWORD`
* `STAGING_PROJECT_ID`
* `STAGING_DB_URL`
* `PRODUCTION_DB_PASSWORD`
* `PRODUCTION_PROJECT_ID`
* `PRODUCTION_DB_URL`

### Modal deployment

* `MODAL_TOKEN_ID`
* `MODAL_TOKEN_SECRET`
* `MODAL_ENVIRONMENT` as a GitHub Actions variable

### Mobile store beta deployment

`mobile-deploy-stores.yaml` uses the `mobile-store-beta` GitHub Environment and
runs only from `production` pushes that touch `apps/mobile/**`,
`scripts/mobile-deployment/**`, the workflow file, `ci-check.yml`, or
`tuturuuu.ts`. Keep this environment branch-restricted to `production`.

GitHub Environment secrets:

* `MOBILE_DEPLOYMENT_CI_TOKEN`: issued from the root workspace mobile deployment
  vault and scoped to `production` mobile deployment.

If `MOBILE_DEPLOYMENT_CI_TOKEN` is not set yet, the mobile store workflow's
credentials preflight emits a notice and skips the Android and iOS publish jobs.
Set the secret when the deployment vault is ready; invalid non-empty tokens still
fail during bundle fetch so real misconfiguration remains visible.

No Firebase, signing, store API, or mobile build secret values should be stored
in GitHub Environment secrets or variables. Those resources live in the
`apps/infrastructure` mobile deployment vault at `/internal/mobile-deployment`,
which is root-workspace-only and requires `manage_mobile_deployment_vault`.

apps/web deployment requirements:

* `ENCRYPTION_MASTER_KEY`: required before uploads, activation, and CI bundle
  fetches can decrypt the per-version deployment data key.
* Root workspace Drive/R2/Supabase storage must be available. File resources are
  stored as encrypted ciphertext blobs under the reserved
  `.tuturuuu/mobile-deployment-vault` prefix; normal Drive routes deny that
  prefix.

Vault resources required before activation:

* Manage all non-file values in the vault's **Secrets** panel. Build-time
  secrets are rendered into `apps/mobile/.env.github` during CI; built-in
  signing and store secrets are exported separately for the Android and iOS
  release steps. The expected production build-time keys are
  `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`,
  `API_BASE_URL`, `TURNSTILE_SITE_KEY`, `TURNSTILE_BASE_URL`,
  `GOOGLE_WEB_CLIENT_ID`, `GOOGLE_IOS_CLIENT_ID`,
  `MOBILE_TASK_DESCRIPTION_EDITING_ENABLED`, and
  `MOBILE_CALENDAR_INTEGRATIONS_ENABLED`. Custom secrets are allowed when they
  use uppercase `A-Z0-9_` names, do not collide with built-in secret names, and
  have single-line UTF-8 values.
* CI file payload keys such as `MOBILE_ANDROID_GOOGLE_SERVICES_JSON_B64` and
  `MOBILE_IOS_GOOGLE_SERVICE_INFO_PLIST_B64` are rejected as secrets; upload
  those payloads through the file resources below.
* Android files: production `google-services.json`, upload keystore, and Google
  Play service-account JSON.
* Built-in Android secrets: `ANDROID_KEYSTORE_ALIAS`,
  `ANDROID_KEYSTORE_PASSWORD`, `ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD`,
  `GOOGLE_PLAY_PACKAGE_NAME=com.tuturuuu.app.mobile`, and
  `GOOGLE_PLAY_TRACK=internal`.
* iOS files: production `GoogleService-Info.plist`, Apple distribution `.p12`,
  App Store provisioning profile, and App Store Connect `.p8` private key.
* Built-in iOS secrets: `APPLE_BUNDLE_ID=com.tuturuuu.app.mobile`,
  `APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD`, `APPLE_TEAM_ID`,
  `APP_STORE_CONNECT_API_KEY_ID`, and `APP_STORE_CONNECT_ISSUER_ID`.

After every resource is uploaded, activate the ready draft version and issue a
CI token. Store only that token in the `mobile-store-beta` GitHub Environment as
`MOBILE_DEPLOYMENT_CI_TOKEN`.

### Package publishing

Package publishing uses **npm trusted publishing** (GitHub OIDC), so **no
`NPM_TOKEN` secret is stored**. The `publish-npm` job in each
`release-*-package.yaml` workflow requests `id-token: write`, downloads the
prepared tarball, and runs `npm publish` while npm exchanges the OIDC token for a
short-lived publish credential.

* Each publish job is bound to a per-package GitHub Environment
  (`ui-release-production` for `@tuturuuu/ui`, `types-release-production` for
  `@tuturuuu/types`), and the matching npm trusted publisher must reference this
  repository, the exact workflow filename, and that environment.
* No npm registry token (`NPM_TOKEN` or `NODE_AUTH_TOKEN`) is set on these
  environments. Adding one would be unnecessary and would weaken the
  build-vs-publish job split.

See the trusted-publishing details in the
[GitHub Actions runbook](/build/devops/github-actions-runbook).

## 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
  internal `SRH_TOKEN` value for the bundled `serverless-redis-http` container.
* Watcher-managed Infrastructure projects do not inherit the integrated Docker
  Redis runtime. They start with Redis disabled, strip generic
  `UPSTASH_REDIS_REST_*` and Docker-specific `DOCKER_UPSTASH_*` values, and
  receive Redis only from project-scoped
  `MANAGED_PROJECT_<PROJECT_ID>_UPSTASH_REDIS_REST_URL` and
  `MANAGED_PROJECT_<PROJECT_ID>_UPSTASH_REDIS_REST_TOKEN` variables.
* `SRH_TOKEN` is the container's internal environment variable. The user-facing
  override surface is `UPSTASH_REDIS_REST_TOKEN` if 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_TOKEN` during
  Compose interpolation. Use the Docker web helper or export a strong token
  before enabling the production `redis` profile directly.
* Redis and `serverless-redis-http` host ports must stay loopback-bound. Do not
  publish those sidecars on all host interfaces or through Cloudflare Tunnel.
* `apps/web` uses Redis for defense-in-depth one-time state such as CLI
  refresh-token replay protection. If `UPSTASH_REDIS_REST_URL` and
  `UPSTASH_REDIS_REST_TOKEN` are unavailable, CLI refresh requests continue
  after JWT validation and user lookup, while confirmed Redis-backed replays are
  still rejected.
* `docker compose config` expands env values; treat its output as sensitive.

## Supabase RPC Authorization Hardening

* Treat every new `SECURITY DEFINER` function in `public` as externally callable until proven otherwise.
* In the same migration that creates or replaces the function, enforce both:
  1. in-function authorization checks (`auth.uid()` plus workspace membership/permission gate), and
  2. explicit execute privileges (`revoke all ... from public`, then grant only required roles such as `authenticated`/`service_role`).
* Do not rely only on `apps/web` page 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`, and `grant execute` before merge.

## Change Management

When a new deployment flow is added:

1. Add its secret names here.
2. Add the workflow or runtime page to the relevant devops doc.
3. Keep the boundary clear between repo config, GitHub Actions config, and machine-local config.
