fix(billing): stop double-charging listening, split AI meters, surface caps in the UI #4
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: CI | |
| # Prod-fidelity gate: every job runs the same commands (and where possible the | |
| # same build) that production runs, so a green CI means the code will deploy | |
| # and work. Called by deploy.yml before anything ships (issue #42). | |
| on: | |
| pull_request: | |
| workflow_call: | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| extension: | |
| name: Extension — typecheck, unit tests, pack | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| # Node 24 ships npm 11; all three package-lock.json files are | |
| # lockfileVersion 3 generated by npm 11. npm 10 rejects them. | |
| node-version: "24" | |
| cache: npm | |
| cache-dependency-path: package-lock.json | |
| - run: npm ci | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Unit tests | |
| run: npm run test:unit | |
| - name: Pack extension (the exact zip deploy ships) | |
| run: npm run pack | |
| web: | |
| name: Web — lint, typecheck, unit tests, prod build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| defaults: | |
| run: | |
| working-directory: web | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "24" | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - run: npm ci | |
| - name: ESLint (errors fail the build) | |
| run: npx eslint | |
| - name: Typecheck | |
| run: npx tsc --noEmit | |
| - name: Unit tests | |
| run: npm run test:unit | |
| # The same build command `npm run deploy` runs in deploy.yml, minus the | |
| # upload — catches next build / OpenNext bundling breakage before merge. | |
| # Clerk env mirrors deploy.yml so the compiled output matches prod | |
| # (empty on forks, where the build still succeeds without keys). | |
| - name: Production build (opennextjs-cloudflare) | |
| env: | |
| NEXT_PUBLIC_CLERK_ENABLED: "true" | |
| NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }} | |
| CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }} | |
| NEXT_PUBLIC_CLERK_PROXY_URL: https://animevocab.com/__clerk | |
| NEXT_PUBLIC_CLERK_SIGN_IN_URL: /sign-in | |
| NEXT_PUBLIC_CLERK_SIGN_UP_URL: /sign-up | |
| NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL: /app | |
| NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL: /app | |
| run: npx opennextjs-cloudflare build | |
| backend: | |
| name: Backend — typecheck, unit tests, wrangler dry-run | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "24" | |
| cache: npm | |
| cache-dependency-path: backend/package-lock.json | |
| - run: npm ci | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Unit tests | |
| run: npm test | |
| - name: Wrangler dry-run (validates the exact deploy bundle) | |
| run: npx wrangler deploy --dry-run --outdir=/tmp/wrangler-dry-run --config wrangler.toml | |
| web-e2e: | |
| name: Web — Playwright e2e (core loop) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| defaults: | |
| run: | |
| working-directory: web | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "24" | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - run: npm ci | |
| - name: Install Playwright Chromium | |
| run: npx playwright install --with-deps chromium | |
| - name: Start dev server (Clerk bypass) | |
| run: | | |
| NEXT_PUBLIC_AVC_DEV_NO_CLERK=1 PORT=3400 npm run dev > /tmp/nextdev.log 2>&1 & | |
| echo $! > /tmp/nextdev.pid | |
| for i in $(seq 1 60); do | |
| curl -sf -o /dev/null http://localhost:3400/ && exit 0 | |
| sleep 2 | |
| done | |
| echo "dev server never became ready" >&2 | |
| cat /tmp/nextdev.log >&2 | |
| exit 1 | |
| - name: Run e2e core loop | |
| run: SKIP_AI=1 node e2e/core-loop.mjs | |
| - name: Dev server log (on failure) | |
| if: failure() | |
| run: cat /tmp/nextdev.log |