Skip to main content
GitHub Actions is the primary automation plane for Tuturuuu.

Workflow Gatekeeping

Every major workflow can be disabled centrally through tuturuuu.ts. The reusable workflow ci-check.yml reads that config and emits should_run, which downstream jobs use before doing real work. For Vercel deployments, ci-check.yml also performs affected-app gating before any install, build, or deploy step starts. It checks the current GitHub event’s changed files against Vercel app metadata and workspace dependency closures from tuturuuu.ts. The changed-file resolver must evaluate the full effective change range:
  • Manual workflow_dispatch runs bypass affected-app gating when the workflow is enabled.
  • Vercel production push workflows first look for the latest successful GitHub Deployment marker for the same workflow and branch, then diff that marker SHA to the current GITHUB_SHA.
  • If no marker is available, push events use the GitHub event payload’s complete commit file list instead of falling back to only the latest commit.
  • Pull request events diff the PR base SHA to the PR head SHA.
  • If the resolver cannot prove the full range, it leaves changed-file state unavailable so Vercel gating defaults open.
Affected Vercel rules:
  • apps/<app>/** runs that app’s preview or production Vercel workflow.
  • packages/<package>/** runs every Vercel app whose transitive workspace:* dependency closure includes that package.
  • apps/*/package.json and packages/*/package.json are dependency changes for their owning workspaces.
  • bun.lock, root package.json, turbo.json, tuturuuu.ts, and .github/workflows/ci-check.yml run every Vercel app workflow.
  • A Vercel workflow file change, such as .github/workflows/vercel-preview-calendar.yaml, runs that specific workflow.
  • If changed files cannot be computed, the Vercel gate defaults open.
bun.lock-only changes intentionally run all Vercel app deploys because ownership is ambiguous without a manifest or source path.

Pull Request Close Cancellation

cancel-pr-runs-on-close.yaml runs on the pull_request_target closed event and cancels active GitHub Actions runs that still belong to the closed pull request. It exists to stop queued or long-running checks after a PR is closed without adding closed triggers to every CI workflow. Because pull_request_target runs with base-repository privileges, keep this workflow narrow:
  • Do not checkout or execute pull request head code.
  • Checkout only the trusted default branch, with persisted credentials disabled.
  • Pin GitHub-owned actions to full commit SHAs.
  • Grant only actions: write and contents: read to the cancellation job.
  • Do not pass repository secrets other than the short-lived GITHUB_TOKEN.
The cancellation script lists active runs by the closed PR head SHA. It cancels matching PR workflow runs and same-repository branch push runs for the PR branch, but never cancels main or production push runs. Runs in contributor forks are outside the base repository token’s authority and are not cancelled by this workflow. The same trusted job paginates through Actions cache entries and deletes only entries whose ref equals the closed pull request’s merge ref (refs/pull/<number>/merge). It never deletes default-branch cache entries.

Main Workflow Groups

Hosted web build and deployment checks

  • vercel-preview-platform.yaml
  • vercel-preview-apps.yaml
  • vercel-preview-calendar.yaml
  • vercel-preview-chat.yaml
  • vercel-preview-cms.yaml
  • vercel-preview-drive.yaml
  • vercel-preview-finance.yaml
  • vercel-preview-inventory.yaml
  • vercel-preview-infrastructure.yaml
  • vercel-preview-learn.yaml
  • vercel-preview-mail.yaml
  • vercel-preview-meet.yaml
  • vercel-preview-mind.yaml
  • vercel-preview-nova.yaml
  • vercel-preview-qr.yaml
  • vercel-preview-rewise.yaml
  • vercel-preview-shortener.yaml
  • vercel-preview-storefront.yaml
  • vercel-preview-tasks.yaml
  • vercel-preview-teach.yaml
  • vercel-preview-track.yaml
  • A matching vercel-production-*.yaml workflow exists for each app above
This list drifts as satellite apps are added; treat .github/workflows/vercel-preview-*.yaml and .github/workflows/vercel-production-*.yaml as the authoritative source. CMS uses the same Vercel deployment pattern as the other satellite apps:
  • preview workflow: vercel-preview-cms.yaml
  • production workflow: vercel-production-cms.yaml
  • project secret: VERCEL_CMS_PROJECT_ID
  • environments: vercel-preview-cms and vercel-production-cms
The Apps gateway uses the same pattern:
  • preview workflow: vercel-preview-apps.yaml
  • production workflow: vercel-production-apps.yaml
  • project secret: VERCEL_APPS_PROJECT_ID
  • environments: vercel-preview-apps and vercel-production-apps
QR uses the same pattern:
  • preview workflow: vercel-preview-qr.yaml
  • production workflow: vercel-production-qr.yaml
  • project secret: VERCEL_QR_PROJECT_ID
  • environments: vercel-preview-qr and vercel-production-qr
Infrastructure uses the same deployment pattern:
  • preview workflow: vercel-preview-infrastructure.yaml
  • production workflow: vercel-production-infrastructure.yaml
  • project secret: VERCEL_INFRASTRUCTURE_PROJECT_ID
  • environments: vercel-preview-infrastructure and vercel-production-infrastructure
Mail uses the same deployment pattern:
  • preview workflow: vercel-preview-mail.yaml
  • production workflow: vercel-production-mail.yaml
  • project secret: VERCEL_MAIL_PROJECT_ID
  • environments: vercel-preview-mail and vercel-production-mail
These workflows:
  • run with default contents: read permissions
  • bind deploy jobs to vercel-preview-<app> or vercel-production-<app> GitHub Environments
  • run preview workflows only through manual dispatch from main, with a required preview_ref input and an actor present in the TRUSTED_PREVIEW_DEPLOY_ACTORS repository variable; vercel-preview-platform.yaml is the exception and also runs on protected main pushes so Supabase staging migrations keep their same-SHA prerequisite signal
  • reject production manual dispatches from non-production branches before install/build/deploy work starts
  • install Bun with .github/actions/setup-bun-with-retry, pinned to the root packageManager Bun version and retried with exponential backoff
  • install dependencies through scripts/ci/run-with-backoff.sh so transient Bun tarball or cache failures retry after cache cleanup
  • build selected shared workspace dependencies before Vercel resolves package exports: @tuturuuu/types, @tuturuuu/supabase, and @tuturuuu/internal-api
  • run vercel pull
  • run vercel build
  • deploy prebuilt artifacts for satellite apps and the hosted platform production workflow
  • treat vercel-preview-platform.yaml as platform build validation only; self-hosted machines own their own Docker apps/web runtime deployment
  • skip production push work when a newer commit already exists on the target branch
  • record non-blocking GitHub Deployment markers after successful Vercel preview builds and production deploys so the next production push can evaluate every change since the last successful run
The platform preview workflow can cross-credit a successful same-SHA production platform build marker. Production does not cross-credit preview markers because it must build and deploy the prebuilt production artifacts. This only applies to the platform workflows; satellite Vercel workflows still build and deploy independently.

Database automation

  • supabase-staging.yaml
  • supabase-production.yaml
These cover staging schema promotion and production schema promotion. Database workflows that install the Supabase CLI use .github/actions/setup-supabase-cli-with-retry after checkout. The local action passes github.token through to supabase/setup-cli@v2, leaves version empty so the repo-pinned Supabase CLI version is used instead of the anonymous latest release lookup, and retries failed setup attempts with bounded exponential backoff.

Docker automation

  • docker-setup-check.yaml
  • rust-backend.yml
docker-setup-check.yaml is the workflow to watch whenever Docker files, compose files, or Docker helper scripts change. rust-backend.yml owns the apps/backend Rust service checks and the migration Cloudflare checks: formatting, locked dependency fetch, Clippy, tests, Cloudflare Worker target validation, smoke reporter unit tests, native binary build, Docker image build, apps/tanstack-web type-check/test validation, and the TanStack route-tree generator/formatter unit test. Keep scripts/generate-tanstack-route-tree.* in this workflow’s path filters so route-tree generation changes run before TanStack/Rust deployment handoff.

TanStack/Rust Cloudflare deployment

rust-backend.yml is also the manually dispatched Cloudflare preview deployment workflow for the migration pair:
  • Rust backend Worker: apps/backend/wrangler.jsonc, Worker name tuturuuu-backend.
  • TanStack Start Worker: apps/tanstack-web/wrangler.jsonc, Worker name tuturuuu-tanstack-web.
The workflow stays switchboard-controlled by the rust-backend.yml entry in tuturuuu.ts. Pull request and push runs are validation-only and use contents: read; they do not require Cloudflare secrets just to type-check, test, lint config, build the Rust Worker bundle, or build the backend Docker image. Manual dispatch inputs:
  • deploy_target: none, backend, tanstack-web, or all.
  • deployment_mode: dry-run or deploy. Keep the default dry-run for the first run in a new account or environment.
Run rust-backend.yml from main for Cloudflare deployments. The deployment preflight requires the dispatch ref to be refs/heads/main and github.actor to be listed in the comma-delimited TRUSTED_CLOUDFLARE_DEPLOY_ACTORS repository variable before it loads CLOUDFLARE_API_TOKEN. Keep that allowlist limited to maintainers who can approve secret-backed Worker deployments. Cloudflare deploy credentials must not be exposed to arbitrary branch code; review or merge deployment changes before dispatching a secret-backed run. The deploy jobs are bound to the cloudflare-workers-preview GitHub Environment. Configure these GitHub values there before expecting deployment jobs to run: If either value is missing, the workflow emits a Cloudflare deployment skipped warning, records setup guidance in the job summary, and skips deploy jobs after CI validation has completed. The warning names only the missing GitHub Environment keys, not their values. A non-empty but invalid or under-scoped token normally surfaces as a Worker secret preflight skip or a Wrangler failure before upload. Worker runtime secrets live in Cloudflare, not GitHub. After the GitHub credential preflight passes, a dedicated Worker secret preflight checks the selected Workers with wrangler secret list. It reads only secret names, never secret values. If Wrangler cannot list names, or if any required name is missing, the workflow emits a warning, writes setup commands to the job summary, and skips the selected deploy job instead of failing later inside a deploy step. Missing-secret warnings use the Missing Worker secrets wording and list only secret names plus bun wrangler secret put ... commands; they never print or infer secret values. Bootstrap missing Worker secrets from a trusted local shell with Wrangler:
Deploy the backend before the TanStack Worker when deploy_target is not all. The TanStack Worker has a BACKEND service binding to tuturuuu-backend, so a frontend-only deployment assumes the backend Worker and its secrets already exist. When deploy_target=all, a skipped backend deployment also keeps the TanStack deployment skipped, even if the TanStack Worker secrets are present. deployment_mode=dry-run compiles and runs Wrangler checks without uploading, but it still uses the same Cloudflare account, token, Worker name, and secret name preflights as deployment_mode=deploy. Treat a dry-run skip as a setup gap, not as a deploy failure. deployment_mode=deploy uploads the selected Worker version only after those preflights pass. When deploy_target=all and deployment_mode=deploy, the post-deploy-smoke job runs only after both Worker deploy jobs succeed. It requires BACKEND_WORKER_ORIGIN, TANSTACK_WEB_WORKER_ORIGIN, and CLOUDFLARE_SMOKE_BACKEND_INTERNAL_TOKEN; missing values fail the full deploy workflow with a warning, an error, and setup guidance in the step summary instead of silently skipping runtime verification. The warning title is Cloudflare smoke inputs missing, and the error title is Cloudflare smoke verification blocked. The job runs:
The JSON report is written under tmp/benchmarks/web-migration/<run-id>-<attempt>/cloudflare-smoke.json, uploaded as the cloudflare-smoke-<run-id>-<attempt> workflow artifact, and summarized in the GitHub step summary. The report must come from the deployed backend and TanStack Worker origins; do not point these variables at local Wrangler or Docker origins in the cloudflare-workers-preview Environment.

Quality and security

  • type-check.yaml
  • turbo-unit-tests.yaml
  • biome-check.yaml
  • codeql.yml
  • codecov.yaml
  • i18n-check.yaml
  • check-migrations.yml
  • check-migration-timestamps.yml
  • branch-name-check.yaml
The test workflows (turbo-unit-tests.yaml and codecov.yaml) run bun setup through scripts/ci/run-with-backoff.sh before executing tests so dependency installation and workspace package builds match the local setup path while surviving transient tarball extraction failures. The Codecov coverage test run also uses the helper with a two-attempt cap so transient runner interruptions such as exit code 130 retry once without masking deterministic test failures. Vercel workflows should invoke Turborepo through bun turbo:local ... after the retried bun install so CI uses the pinned repo dependency instead of resolving a global or downloaded Turbo binary. Cacheable builds, type checks, and tests must be executed through .github/actions/run-with-turbo-remote-cache; trusted jobs pass the dedicated repository TURBO_TOKEN and TURBO_TEAM variable, while pull-request and Dependabot jobs leave both inputs empty and use the task-family local fallback cache. Vercel deploy credentials must stay environment-scoped. Do not put ${{ secrets.* }} values in a Vercel workflow-level env: block, and do not export production Supabase, encryption, or provider secrets from GitHub Actions. Store app runtime and build-time configuration in the Vercel project environment. Remote-cache identity is the narrow exception: it is passed only to the wrapped vercel build step and never written to GITHUB_ENV or a workflow/job environment. The regression test bun test scripts/ci/release-workflows.test.js enforces this for every vercel-preview-*.yaml and vercel-production-*.yaml workflow.

Cache and artifact resources

actions-storage-report.yaml runs weekly and can be dispatched manually. It is read-only: it queries the repository’s live Actions cache policy and current cache/artifact inventories, groups cache bytes by key prefix, and summarizes artifact count, size, age, and largest workflow families. Cache status is informational at 80% of the configured limit, warning at 90%, and critical at 100%. The report does not assume a fixed artifact byte entitlement and does not require an organization billing token. The July 10, 2026 audit found a 10 GB cache maximum and 7-day retention. Target steady-state usage below 9 GB so GitHub does not continuously evict and recreate high-reuse entries. Prefer Bun downloads, package-manager data, task-family Turbo state, native dependencies, shared Rust state, and service-scoped BuildKit layers over final application binaries. Leave managed uv and CodeQL caching to their official actions. All upload-artifact steps must set retention-days and if-no-files-found. Optional failure diagnostics may warn; release and deploy handoffs must fail when absent. E2E diagnostics are failure-only and retained 7 days, package tarballs are retained 1 day, development mobile deliverables 7 days, and production store deliverables 14 days. Preview deploy credentials must not be exposed to arbitrary branch push code. Most preview Vercel workflows are manual-only: run the workflow from main, provide the branch, tag, or SHA in preview_ref, and keep TRUSTED_PREVIEW_DEPLOY_ACTORS limited to maintainers who can approve secret-backed preview builds. The workflow still checks out and builds the requested preview_ref, so reviewers should treat that ref as code that can execute during install/build. Cloudflare Worker manual deployments follow the same trust boundary: run rust-backend.yml from main, keep TRUSTED_CLOUDFLARE_DEPLOY_ACTORS limited to trusted maintainers, and avoid exposing CLOUDFLARE_API_TOKEN to unreviewed branch code. The workflow checks the protected dispatch ref and actor allowlist before loading Cloudflare credentials or running Worker deploy steps. vercel-preview-platform.yaml also runs on protected main pushes. Keep that exception narrow: supabase-staging.yaml is triggered by the platform preview build workflow and production migration requires a successful main staging migration for the same SHA before it can run supabase db push --include-all.

Other delivery surfaces

  • discord-modal-deploy.yml
  • mobile-build-android.yaml
  • mobile-build-ios.yaml
  • mobile-build-macos.yaml
  • mobile-build-windows.yaml
  • mobile-deploy-stores.yaml
  • release-*.yaml package publishing workflows

Operational Rules

Manual dispatch

Use workflow_dispatch when:
  • you need to rerun a deployment intentionally
  • you need to promote a migration outside the normal trigger timing
  • you need to recover from a failed but otherwise understood automation path
Manual dispatch bypasses affected-app gating when the workflow is enabled in tuturuuu.ts. Disabled ci entries still skip, even for manual dispatch. For preview Vercel deployments, dispatch the workflow from main, set preview_ref to the branch, tag, or SHA to deploy, and confirm the actor is in TRUSTED_PREVIEW_DEPLOY_ACTORS. Do not reintroduce preview push triggers for secret-backed Vercel workflows. Package release workflows that expose production secrets or trusted publishing authority must add their own ref guard before dependency installation or publish jobs. Release Please is the only workflow that generates monorepo version and changelog PRs. It runs from production, uses secrets.RELEASE_PLEASE_TOKEN so generated PRs and releases can trigger downstream workflows, and falls back to github.token only to keep the job from failing when the bot token is not provisioned. The github.token fallback does not trigger downstream workflow runs from generated release PRs. Release Please rejects non-production manual dispatches before the write-capable release job. Package publish workflows consume release-please version bumps on production; they must not recreate checksum or PR-title version bump automation. Package release workflows use npm trusted publishing: build and artifact-pack work runs before any OIDC permission is granted, then the publish-npm job downloads one tarball, verifies its package name and version, and runs npm publish without NPM_TOKEN. Each publish job is bound to its package release environment, and the matching npm trusted publisher must use this repository, the workflow filename, and that environment. Manual dispatch is only valid with the branch selector set to production; non-production refs are rejected before the package or publish jobs can start. Every workflow-published package manifest must also declare repository.type: "git", repository.url: "https://github.com/tutur3u/platform", and repository.directory matching the package path. npm validates those fields against GitHub Actions provenance and rejects publishes with E422 when the packed manifest has an empty or mismatched repository URL. The tarball handoff uses required-file behavior, one-day retention, and compression level 0 because .tgz is already compressed. Preparation runs any package lifecycle build through root Turbo first, then calls npm pack --ignore-scripts so prepack cannot bypass the shared cache wrapper. Release Please can move an oversized generated pull request body into release-notes.md on a companion release-please--branches--<branch>--release-notes branch. The workflow runs node scripts/ci/release-please-overflow-recovery.js --target-branch production before googleapis/release-please-action@v5; when a merged pending release PR still points at a missing overflow file, the script recreates the branch and file from the merged manifest bump and current production changelogs, then the normal Release Please action can create the releases. If the script reports skipped, inspect the pending labels and merged release PR body before retrying. Keep internal Tuturuuu dependencies as workspace:* in source package manifests so local builds always use the checked-out workspace. Package release workflows must first run node scripts/ci/package-release-readiness.js gate-package-release packages/<name> in a short pre-build gate. The gate checks the package version and publishable Tuturuuu workspace dependencies once, dispatches missing dependency workflows, and exits green without build, pack, or publish work while dependencies are pending. If a dependency workflow for the same production SHA already failed, completed successfully without npm visibility, or cannot be inspected, the gate fails immediately. When the gate outputs should_publish == true and dependencies_ready == true, the workflow can build and rewrite the checked-out manifest immediately before npm pack with node scripts/ci/prepare-npm-package-manifest.js packages/<name>. That temporary rewrite replaces workspace: protocol ranges with the current workspace package versions so npm consumers can install the tarball. It must preserve package-included file: tarball dependencies, such as @tuturuuu/ui’s vendored SheetJS tarball, instead of rewriting them to mutable external tarball URLs. After npm publish, the publish job polls npm view for the exact published version before it reports success, then a separate non-OIDC job dispatches direct dependent package workflows without checking out the repo or carrying publish authority. The internal node scripts/ci/package-release-readiness.js dispatch-dependent-workflows packages/<name> command is available for direct/manual dispatches that can read the checkout. If npm returns first-publish or permission errors, fix the npm package access and trusted publisher setup instead of skipping the package. If a published package depends on another release-please-managed Tuturuuu package, that dependency also needs its own release-*-package.yaml workflow and matching tuturuuu.ts entry. The platform production Vercel workflow also runs node scripts/ci/package-release-readiness.js gate-changed-package-versions before installing dependencies. Release-please package bumps therefore publish and become visible on npm before the normal production platform deployment continues. The helper intentionally checks only the checked-out latest commit, not the whole push event payload, so package changes from earlier commits in a multi-commit push are not bound to an unrelated newer SHA. If the latest commit does change package manifests, the deploy job grants actions: write because the helper may dispatch missing package release workflows for that same production SHA. When related package releases are queued or running, the helper sets packages_ready=false; the platform build skips successfully instead of polling npm until the runner times out. npm publish authority remains isolated to package publish-npm jobs. A skipped package gate must not count as production deployment for database migrations: supabase-production.yaml requires the successful vercel-production-platform deployment marker for the same SHA before it can run production migrations. Filtered production Docker installs only include the selected app and the dependencies that app needs. Workspace packages with direct tsc build scripts must declare typescript in their own devDependencies; do not rely on the root devDependency for production Docker builds. Programmatic compiler API consumers must stay on the active TypeScript 7 toolchain instead of carrying legacy compiler compatibility packages. Next.js production apps also declare @typescript/native-preview in their own devDependencies while the repo uses the TypeScript 7 native compiler package. The TS7 typescript package does not ship the legacy typescript/lib/typescript.js API file that Next checks during build-time TypeScript setup; the native-preview marker makes Next use its supported TS7 native compiler path instead of trying to auto-install classic TypeScript.

Newer-commit guards

Production Vercel push workflows intentionally skip if the branch already has a newer commit than the current run. A skipped deployment may be correct rather than broken. The deployment marker closes the gap created by these stale-run skips. When a later push reaches the latest commit, affected-app gating compares against the last successful marker rather than only the newest push payload, so app changes from skipped intermediate runs still queue the correct Vercel workflow.

Prerequisite guards

  • supabase-staging.yaml requires a successful main platform preview build trigger unless manually dispatched.
  • Its deploy step links the staging project and runs supabase db push --include-all.
  • supabase-production.yaml runs after production platform deployment and also re-evaluates after a matching main staging migration succeeds. It still checks both the latest production platform workflow result, a successful production deployment marker, and a completed successful staging migration for the same commit before running supabase db push --include-all.

Mobile iOS native assets

Mobile workflows cache the Flutter SDK/pub downloads through the Flutter setup action. Android workflows also use the toolchain-aware Gradle cache, and iOS or macOS workflows cache CocoaPods downloads plus the trunk repository. They do not cache apps/mobile/build, final APK/AAB/IPA/app bundles, Pods, or apps/mobile/.dart_tool. Flutter native asset hook outputs can become stale across simulator/device builds and SDK updates; a stale .dart_tool cache can leave NativeAssetsManifest.json referencing objective_c while build/native_assets/ios/ is missing the generated framework. Every workflow still runs flutter pub get and its platform build on every run. Development deliverables are retained for 7 days and production store deliverables for 14 days. Archive directory-based app bundles before upload, disable redundant artifact compression for already-compressed archives and mobile packages, and fail if a required deliverable is missing. The workflow explicitly runs flutter config --no-enable-swift-package-manager after Flutter setup. Keep the iOS CI path on CocoaPods while image_cropper and dkimagepickercontroller resolve incompatible TOCropViewController Swift package ranges; otherwise Flutter 3.44+ can fail before the simulator build with an Xcode package dependency resolution error. Root bun check runs scripts/check-mobile-dependencies.js to catch mobile dependency versions known to fail Apple CI before the native build starts. While the iOS/macOS build workflows use Xcode 16.4, keep connectivity_plus pinned to 7.0.0 because 7.1.1 references NWPath.isUltraConstrained, and keep device_info_plus pinned to 12.3.0 because 12.4.0 references NSProcessInfo.isiOSAppOnVision; those symbols are not available in that CI SDK.

Mobile store beta deployment

mobile-deploy-stores.yaml runs automatically on production pushes that touch apps/mobile/**, scripts/mobile-deployment/**, the workflow file, ci-check.yml, or tuturuuu.ts. It is a beta-store workflow only:
  • Android builds the production flavor AAB from apps/mobile/.env.github and publishes it to the Google Play internal track.
  • iOS builds the production flavor IPA from apps/mobile/.env.github and uploads it to TestFlight.
  • CI requests a signed GitHub OIDC token for the tuturuuu-mobile-deployment audience, then fetches an Android or iOS bundle from https://tuturuuu.com/api/v1/mobile-deployment/bundle with the issued MOBILE_DEPLOYMENT_CI_TOKEN.
  • If MOBILE_DEPLOYMENT_CI_TOKEN is not configured in the mobile-store-beta GitHub Environment yet, the credentials preflight emits a notice and skips the Android and iOS publish jobs instead of failing the workflow. A non-empty but invalid token still fails during the bundle fetch.
  • The apps/web mobile deployment vault verifies the CI token, GitHub OIDC issuer, audience, repository, production ref, workflow file, and mobile-store-beta environment before returning any plaintext.
  • CI hydrates ignored Firebase, signing, store, and .env.github files into fixed paths under apps/mobile and $RUNNER_TEMP with umask 077, validates plaintext SHA-256 hashes, masks secret values, and deletes generated files in always() cleanup steps.
  • The workflow rejects any Google Play track other than internal, uploads only the AAB/IPA build artifacts, and uses TestFlight-only iOS upload.
  • Release Please owns mobile version and build-number bumps. Duplicate store build numbers should fail in CI instead of being bumped by this workflow.
The workflow is bound to the mobile-store-beta GitHub Environment. Keep that environment restricted to the production branch and store only MOBILE_DEPLOYMENT_CI_TOKEN there. Mobile signing, Firebase, store API, and build-time secrets live in the root workspace mobile deployment vault at /internal/mobile-deployment on the infra app and require manage_mobile_deployment_vault. Manage non-file values in the vault’s Secrets panel, then use the vault’s Verify action before activating the draft. Legacy base64 file payload env keys are intentionally blocked; Firebase, signing, and store credential payloads must be uploaded as file resources. Local release-build verification should run before relying on the workflow:
iOS IPA verification requires full Xcode, not only Command Line Tools:
If xcodebuild -version reports that Command Line Tools are selected, switch to full Xcode before claiming the iOS archive has been verified locally.

Fast Triage Checklist

  1. Check whether ci-check.yml disabled the workflow through tuturuuu.ts.
  2. For Vercel workflows, inspect the ci-check.yml decision reason and matched paths.
  3. Inspect the changed-file source, base SHA, head SHA, and path count emitted by resolve-changed-files.ts.
  4. Check whether the workflow was skipped because a newer commit exists.
  5. Check whether the prior successful GitHub Deployment marker exists for that Vercel workflow and branch.
  6. Check path filters to confirm GitHub should have started the lightweight workflow.
  7. For database workflows, inspect the prerequisite evaluation job before the deploy job.
  8. For Docker changes, verify docker-setup-check.yaml specifically.

When You Add New Automation

  1. Add the workflow file under .github/workflows/.
  2. Add its key to tuturuuu.ts unless you intentionally want it always on by default.
  3. Document the workflow in apps/docs.
  4. If it changes a docs-visible page, add that page to apps/docs/docs.json.