# Blockers

Updated: 2026-07-31

## Stripe billing

- **Blocked:** Activating roadmap item 7.5 in production.
- **Why:** Hosted Checkout, customer-portal sessions, signed subscription webhooks, persisted billing state, and Premium-role provisioning are implemented. The Stripe product, recurring price, portal, webhook registration, and production credentials must be created outside the repository.
- **Required:** Configure the Premium recurring price, enable the Stripe customer portal, register `/api/billing/webhook` for `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`, then supply `STRIPE_SECRET_KEY`, `STRIPE_PRICE_PREMIUM`, and `STRIPE_WEBHOOK_SECRET` through the deployment environment. Do not place secret values in source control or chat.
- **Recommended:** One monthly Premium price first; add annual billing only after the monthly flow is operating.
- **Current access check:** Production has test-mode secret and webhook values, but `STRIPE_PRICE_PREMIUM` currently contains a `prod_...` Product ID. Checkout requires the recurring `price_...` Price ID. The publishable key is not used by hosted Checkout.
- **Runbook:** Follow `docs/operations/stripe-activation.md`, completing test mode before creating or installing live-mode values.

## Public registration verification

- **Blocked:** Completing a real-browser production signup check.
- **Why:** The 2026-07-31 anonymous production check confirms `allowRegistration=true`, `turnstileEnabled=true`, and Google sign-in enabled. Completing Turnstile and creating a disposable account requires an interactive production browser session.
- **Required:** Register one disposable account through Turnstile, verify email/sign-in/rate-limit behavior, then remove the account if it is not needed.
- **Recommended:** Monitor Turnstile and rate-limit failures during the first public rollout; keep email verification required.
- **Current status:** Production returns `allowRegistration=true`, `turnstileEnabled=true`, `googleEnabled=true`, and `microsoftEnabled=false`. A registration request without a Turnstile token is rejected with HTTP 400. SMTP is configured and enabled. The release branch now maps `AUTH_REQUIRE_EMAIL_VERIFICATION`; production must set it to `true` before the interactive signup test.

## CI runner verification

- **Blocked:** Proving that the current release gate completes on the self-hosted runner.
- **Why:** The workflow now runs the complete backend, frontend, dependency-audit, browser, and production-build checks, but historical runner failures were intermittent and the current working tree has not been submitted to remote CI. Local success cannot prove runner health.
- **Required:** Submit the reviewed changes and run the Gitea workflow. If it still fails early, inspect the job log and `journalctl -u act_runner`/runner resources on the host.
- **Recommended:** Keep the full gate intact; fix the runner instead of skipping or filtering tests.
- **Current status:** The `release-readiness` branch is pushed to origin. Creating the pull request at `https://git.cesnimda.uk/cesnimda/jobtrackingapp/pulls/new/release-readiness` still requires an authenticated Gitea browser or CLI session; neither is available in this workspace.

## React Router security release

- **Blocked:** Clearing the final two moderate React Router package findings without introducing a higher-severity advisory.
- **Why:** The reported paths affect redirects and SSR hydration. This application uses declarative `BrowserRouter` (not SSR/RSC), and post-login redirects reject protocol-relative and backslash paths. The redirect-fixed React Router 7.18.2 release is itself covered by a high-severity RSC advisory; npm's suggested high-severity fix downgrades to a release that reintroduces the moderate redirect findings. No published version clears both sets.
- **Required:** Upgrade React Router when a release clears both the redirect/SSR findings and the RSC advisory, then rerun Jest, production build, and Playwright.
- **Recommended:** Keep 6.30.3 plus the explicit redirect allowlist until that release; do not force an audit-driven major downgrade/upgrade that leaves tests unable to load.

## Production verification and deployment

- **Blocked:** Authenticated production smoke tests, backup restore verification against real data, OAuth-provider checks, and deployment.
- **Why:** These require production access, real credentials, and operator authorization.
- **Required:** Follow `docs/release-candidate-review.md` and `docs/release-checklist.md` on the production host.
- **Recommended:** Verify backup/restore before deployment, then exercise login, existing application counts, Career Workspace, public CV refresh/download, AI, and attachments in order.
- **Current access check:** Read-only SSH access is confirmed to the LAN production host as both `root` and `pi` using the existing `id_ed25519` identity. All four containers are healthy and the host has 44 GB free. No production change or deployment was attempted.
- **Current status:** Anonymous production checks confirm the frontend and `/api/auth/config` return HTTP 200. The public `/health` path currently returns the SPA HTML shell; the release branch now proxies that exact path to the backend and includes a regression test.

## Legacy job/application column cutover

- **Blocked:** Removing the opportunity columns duplicated between `JobApplication` and `Job`.
- **Why:** The compatibility dual-write protects existing production rows and older clients. The release branch now backfills missing opportunities on startup, synchronizes both creation paths, and leaves all legacy columns intact. Dropping columns still requires production validation and an observation release.
- **Required:** After deployment, run the read-only report in `docs/operations/job-opportunity-cutover.md` against production and a restored backup, then confirm that backward API compatibility is no longer required.
- **Recommended:** Use an expand/contract release: first stop legacy reads after a verified backfill, observe one release, then drop the duplicate columns in the following migration.
