Skip to content

chore: prove backend supports mobile clients + unblock CI#8

Merged
jeanpaulsio merged 2 commits intomainfrom
chore/mobile-client-readiness
Apr 13, 2026
Merged

chore: prove backend supports mobile clients + unblock CI#8
jeanpaulsio merged 2 commits intomainfrom
chore/mobile-client-readiness

Conversation

@jeanpaulsio
Copy link
Copy Markdown
Owner

Summary

Locks in the contract that the backend works for React Native / native mobile clients by proving it with an integration test, and clears the pre-existing CI breakage that was hiding on main.

Why this matters: The template is about to be used for a new project with a React Native frontend. The backend already returns tokens in the response body and uses HTTPBearer for auth, so it should work with mobile — but nothing in the test suite actually proves that, and a regression (e.g. adding a cookie-only code path) would silently break mobile clients without failing any web tests.

What's in here

Mobile-client contract

  • New integration test (tests/integration/test_mobile_client_flow.py) walks the full flow — register → verify → login → protected call → refresh → protected call — using only Authorization: Bearer headers. Asserts no response sets a Set-Cookie header. Also verifies that passing the access token as a cookie (with no header) fails, to prove there's no hidden cookie fallback.
  • CLAUDE.md + README document the client-agnostic contract explicitly: backend returns tokens in the response body, web uses cookies for SSR, mobile uses SecureStore/Keychain with a Authorization header.

CI unblock (drive-by fixes)

Main CI has been red since the last backport PR. Three pre-existing bugs, all fixed here:

  1. .github/workflows/ci.yml had literal {{APP_SLUG_UNDERSCORE}}_test placeholders in POSTGRES_DB and TEST_DATABASE_URL. GitHub Actions reads {{ }} as its own expression syntax and fails to parse the workflow. Fixed by hardcoding starter_test (the template's own CI runs against this stable name, post-setup projects keep using it for CI since CI databases don't need to match prod names anyway). Removed ci.yml from setup.sh's substitution list.
  2. test_list_requires_auth asserted 403 for an unauthenticated request. FastAPI's HTTPBearer returns 401 (correct HTTP semantics — 401 = "not authenticated", 403 = "authenticated but forbidden"). Fixed the assertion.
  3. app/config.py had a line-length format violation that ruff format --check would have caught if CI had been running. Fixed by the formatter.

Zustand cleanup

README claimed a "Zustand auth store" and a web/stores/ directory — neither exists. The codebase has always used React Query (useCurrentUser() hook in web/hooks/useAuth.ts). Fixed README and one stale reference in .claude/skills/vike-patterns.md.

Test plan

  • ruff check app/ tests/ — passes
  • ruff format --check app/ tests/ — passes (after format fix)
  • mypy app/ --ignore-missing-imports — passes
  • pytest tests/ — 104 passed, coverage 92.27% (above 90% threshold)
  • New test_full_mobile_client_flow_uses_only_bearer_tokens passes
  • New test_protected_endpoint_rejects_cookie_only_auth passes
  • Verify GitHub Actions CI is green on this PR (confirming the {{APP_SLUG_UNDERSCORE}} fix unblocked the workflow)

- Add integration test that walks register → verify → login → Bearer call
  → refresh → Bearer call with no cookies, asserting no Set-Cookie headers
  appear. Locks in the contract that the backend works for React Native /
  native mobile clients, not just the Vike frontend.
- Document the client-agnostic contract in CLAUDE.md + README: backend
  returns tokens in the response body, clients choose their own storage
  (cookies for web SSR, SecureStore/Keychain for mobile).
- Fix CI workflow: POSTGRES_DB had literal {{APP_SLUG_UNDERSCORE}}
  placeholder which GitHub Actions interpreted as expression syntax and
  failed to parse. Replaced with stable 'starter_test' name and removed
  ci.yml from setup.sh's substitution list.
- Fix pre-existing test_list_requires_auth assertion: HTTPBearer returns
  401 for missing auth (correct HTTP semantics), not 403.
- Zustand cleanup: README claimed a Zustand auth store and a stores/
  directory that don't exist. Codebase has always used React Query.
- Drive-by: ruff format fix on config.py that main had drifted on while
  CI was broken.
Three issues were preventing CI from going green on the template itself
(user projects post-setup.sh were fine):

- pyproject.toml used `{{APP_SLUG}}-server` as the project name, which
  isn't a valid PEP 508 identifier, so `pip install -e .` failed on CI.
  Switched to a static default (`fastapi-vike-starter-server`) and moved
  the slug rewrite into setup.sh.
- package-lock.json was out of sync with package.json after Sentry was
  added in da77914. Regenerated.
- Prettier errors and one unused `user` binding in pages/app/+Layout.tsx
  that slipped in with the React Query refactor.
@jeanpaulsio jeanpaulsio merged commit b303d9b into main Apr 13, 2026
3 checks passed
@jeanpaulsio jeanpaulsio deleted the chore/mobile-client-readiness branch April 13, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant