feat(onboarding): mint the first workspace instead of asking for its … #74
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy app | |
| # Deploy the Talyn application — app.talyn.dev — to Vercel on every push to | |
| # main that touches it. Unlike apps/marketing this IS an npm workspace member | |
| # (it depends on @talyn/client and @talyn/shared), so everything installs from | |
| # the ROOT lockfile, not a private one. | |
| # | |
| # NAMING: the two Vercel deploys are "web" (the marketing WEBSITE, | |
| # www.talyn.dev, deploy-marketing.yml, VERCEL_PROJECT_ID_WEB) and "app" (the | |
| # APPLICATION, app.talyn.dev, this file, VERCEL_PROJECT_ID_APP). The source | |
| # directory is still apps/web, which reads backwards against that — the | |
| # secret, not the folder, is what decides where a build lands, so check the | |
| # secret. Pointing this at the website's project id would publish the app's | |
| # bundle over www.talyn.dev. | |
| # | |
| # THIS WORKFLOW IS THE ONLY DEPLOY PATH. apps/web/vercel.json sets | |
| # `"git": { "deploymentEnabled": false }`, which turns off Vercel's own | |
| # push-triggered builds — otherwise every push to main deploys app.talyn.dev | |
| # TWICE, once from here and once from Vercel's Git integration, and whichever | |
| # finishes last wins the production alias. | |
| # | |
| # That race is not theoretical: on 2026-08-04 the two paths disagreed about | |
| # env (Vercel's build had the real Supabase values, the CLI build got | |
| # `[SENSITIVE]` placeholders) and the losing-but-later build served a white | |
| # screen. Keeping one path means one thing to reason about — and this is the | |
| # one to keep, because `check` typechecks before anything deploys. | |
| # | |
| # Deploys here still work: `git.deploymentEnabled` only governs Vercel's Git | |
| # hooks, not an explicit `vercel deploy --prebuilt`. | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'apps/web/**' | |
| - 'packages/client/**' | |
| - 'packages/shared/**' | |
| - '.github/workflows/deploy-app.yml' | |
| workflow_dispatch: {} | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| # Skip on forks — no secrets there and nothing to deploy. | |
| if: github.repository == 'Gilbert09/talyn' | |
| steps: | |
| - name: Check out Git repository | |
| uses: actions/checkout@v4 | |
| - name: Install Node.js and NPM | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Build workspace deps | |
| run: | | |
| npm run build -w @talyn/shared | |
| npm run build -w @talyn/client | |
| - name: Typecheck | |
| run: npx tsc --noEmit -p apps/web/tsconfig.json | |
| deploy: | |
| needs: check | |
| runs-on: ubuntu-latest | |
| if: github.repository == 'Gilbert09/talyn' | |
| env: | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_APP }} | |
| steps: | |
| - name: Check out Git repository | |
| uses: actions/checkout@v4 | |
| - name: Install Node.js and NPM | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| # Until the Vercel project exists, a push that touches apps/web would | |
| # fail this job red on a missing project id. Skip cleanly instead — | |
| # `check` above still gates the code. (The guard lives inside a step, | |
| # not in `if:`, because the `secrets` context is not available in job | |
| # conditions — same reason publish.yml guards its sourcemap upload | |
| # this way.) | |
| - name: Is the Vercel project configured? | |
| id: gate | |
| run: | | |
| if [ -z "${{ secrets.VERCEL_PROJECT_ID_APP }}" ]; then | |
| echo "VERCEL_PROJECT_ID_APP not set — skipping deploy." | |
| echo "configured=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "configured=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install Vercel CLI | |
| if: steps.gate.outputs.configured == 'true' | |
| run: npm i -g vercel | |
| # Run from the repo root — the Vercel project's Root Directory is pulled | |
| # with the project settings. VITE_TALYN_* build values live as Vercel | |
| # project environment variables so `vercel build` sees them. | |
| # | |
| # Those variables must NOT be marked "Sensitive" in Vercel. `vercel pull` | |
| # cannot decrypt a sensitive variable — it writes the literal string | |
| # `[SENSITIVE]`, which then gets baked into the bundle. buildEnv.ts | |
| # rejects that value by name now, so the build fails loudly instead of | |
| # shipping a white screen (which is what happened to the web app on | |
| # 2026-08-04, because the guard only checked for EMPTY). | |
| - name: Pull Vercel environment | |
| if: steps.gate.outputs.configured == 'true' | |
| run: vercel pull --yes --environment=production --token="${{ secrets.VERCEL_TOKEN }}" | |
| - name: Build | |
| if: steps.gate.outputs.configured == 'true' | |
| env: | |
| # Passed explicitly rather than relying on VERCEL_GIT_COMMIT_SHA: | |
| # `--prebuilt` runs after OUR checkout, so Vercel injects that | |
| # variable empty and the build shipped as "web/" with no SHA. | |
| VITE_TALYN_BUILD_SHA: ${{ github.sha }} | |
| run: vercel build --prod --token="${{ secrets.VERCEL_TOKEN }}" | |
| - name: Deploy | |
| if: steps.gate.outputs.configured == 'true' | |
| run: vercel deploy --prebuilt --prod --token="${{ secrets.VERCEL_TOKEN }}" |