Skip to content

feat(dx): mock API for local development (MSW) so the app runs without a backend - #145

Merged
afeezorobsco-cyber merged 2 commits into
DocForum:mainfrom
mskdylan:feat/mock-api-local-development
Oct 18, 2026
Merged

afeezorobsco-cyber merged 2 commits into
DocForum:mainfrom
mskdylan:feat/mock-api-local-development

Conversation

@mskdylan

Copy link
Copy Markdown
Contributor

Closes #95

Note: opened from the fork mskdylan/docforum-web (the contributor account has read-only access to DocForum/docforum-web). Branch: feat/mock-api-local-development, based on main @ 7e2c21b.

This is a developer-tooling change — no screen tied to a PRD §4 core flow is altered, so no PRD flow mapping applies (the flows are exercised through the existing service layer, unchanged).

What changed & why

Contributors previously needed a running docforum-core (or its cold-starting Render preview) to see most screens. npm run dev:mock now boots the same Vite dev server with an MSW service worker mocking every endpoint the app's service layer calls, so every screen runs locally in any role, instantly, with obviously fake data.

  • src/mocks/ — handlers for all ~40 endpoints (auth, dependents, health profile, care threads, consultation notes, doctor queue/messages/insights, facility finder/team/fulfillment, payments, account export/delete) over an in-memory DB seeded from obviously-fake fixtures (example.test emails, Placeholder/Example personas).
  • Dev panel — role switcher (patient / doctor / facility / admin), scenario toggles (normal / empty states / forced 500s), latency slider (0–3 s), fixture reset, sign-out.
  • npm run dev:mock — VITE_ENABLE_MOCKS=true vite (same inline-env convention as the existing build:pages script).
  • Bundle exclusion — mocks are only reachable via a dynamic import behind import.meta.env.DEV && VITE_ENABLE_MOCKS in main.tsx; new npm run check:dist (wired into ci.yml after build) fails if any mock marker string appears in dist/.
  • Docs — CONTRIBUTING.md mock-mode section (incl. the rule: new endpoints get a handler + fixture in the same PR), ROADMAP.md W7 section, ARCHITECTURE_ESSENTIALS.md src/mocks/ note.

Implementation / architectural decisions

  • All data access stays behind the existing service layer (src/services/ → api-fetch/apiFetch → intercepted fetch). No screen, hook, or service was modified to accommodate mocks, and the pages/ components/ features/ hooks/ services/ store/ types/ shape is preserved (src/mocks/ is new tooling-only tooling scoped to the issue's sanctioned path).
  • Handlers express happy paths only; a shared respond() wrapper applies the dev-panel scenario (forced errors, empty lists/null singletons) and latency uniformly, so scenario coverage can't drift per-endpoint.
  • In-memory mutable DB (db.ts + resetDb()) so mutations (start a visit, fund an intent, add a dependent) persist across requests within a session and reset on reload/Reset data.
  • Mocks boot before React's first render (top-level await import() in main.tsx, dev+flag only). The earlier fire-and-forget approach lost the deep-link race: RequireAuth bounced protected deep links to #/login before the persona session existed. Booting first also preserves arbitrary deep links.
  • src/query-client.ts — the app's QueryClient was moved out of main.tsx (same defaults, same instance) so the panel can invalidateQueries() on role/scenario/data changes; without it, cached responses masked scenario switches.
  • Login handler: seeded persona emails log in as that persona; any other email logs in as the panel's active role (keeps the typed email), so the real login screen is exercisable in mock mode.
  • Handler tests run in the node environment (// @vitest-environment node) so MSW's interceptor wraps Node's fetch, driving the real service functions — no vi.mock of services.

Validation (actual output)

$ npm run typecheck
> tsc -b --noEmit
(no output — pass)

$ npm test
 Test Files  25 passed (25)
      Tests  138 passed (138)      # was 112 before this PR; +26 = src/mocks/handlers.test.ts
   Duration  34.04s

$ npm run build
dist/index.html                   2.90 kB │ gzip:   1.32 kB
dist/assets/index-CBmAo9AB.css   53.85 kB │ gzip:   9.02 kB
dist/assets/index-Akq-wW34.js   518.33 kB │ gzip: 162.19 kB
✓ built in 4.12s

$ npm run check:dist
✓ no mock code in production bundle (4 files scanned)

Before/after bundle: byte-identical — the built JS is index-Akq-wW34.js at 518.33 kB / 162.19 kB gzip on both main and this branch (mock code adds zero production bytes).

Exclusion check negative-tested: planting a file containing a mock marker in dist/ makes check:dist exit 1 with ✗ mock marker "mock-access-token" found in ….

Browser verification (headless Chromium against npm run dev:mock, 9/9 scripted checks, no uncaught page errors): dev panel renders; patient persona auto-signed in; role switch → doctor dashboard shows seeded queue (live queue, running delay, inbox badge); patient dependents show fixtures; empty scenario → No dependents added yet.; error scenario → Mock scenario: forced server error (dev panel) rendered via the app's FormError; deep link into #/patient/dependents keeps the mock session; mobile (390×844) panel usable.

Screenshots (desktop + mobile)

Committed under screenshots/ per repo convention (raw URLs below render inline):

Desktop Mobile
dev panel dev panel mobile
doctor dashboard patient mobile
dependents
empty scenario error scenario

Limitations / notes for review

  • GitHub Actions CI can't be run from this environment; the local runs above are the exact commands ci.yml executes, plus the new check:dist step added in this PR.
  • Browser verification was scripted (headless Chromium), not hand-clicked by a human; the reviewer flow in the issue ("runs dev:mock from a clean clone and visits every route") is the intended final check.
  • The mock login accepts any password by design; scenario switches affect all endpoints including auth (useful for testing auth error states).
  • ROADMAP.md now contains the W7 section with [Platform] Generate MSW handlers and fixtures from the backend OpenAPI spec #96 marked blocked on open docforum-core#112 — if [Platform] Mock API for local development (MSW) so the app runs without a backend #95 merges after another W7 PR lands, expect the usual trivial ROADMAP conflicts.
  • Screenshots are committed to the branch rather than uploaded to the PR (no image-upload credential available in this environment); the raw URLs above render inline in the PR.

…t a backend (DocForum#95)

- npm run dev:mock boots Vite with an MSW service worker covering every
  endpoint the service layer calls (auth, dependents, health profile, care
  threads, consultation notes, doctor queue/messages/insights, facility
  finder/team/fulfillment, payments, account export/delete)
- Obviously fake fixtures (example.test personas) in an in-memory DB with
  a dev panel: role switcher (patient/doctor/facility/admin), scenarios
  (normal / empty states / forced errors), latency slider, reset
- Mocks boot before React's first render (dev-only top-level await) so
  deep links into protected routes keep the persona session
- 26 handler tests drive the real src/services layer through MSW, incl.
  scenario/latency switches and 404/409 paths
- Production bundles stay byte-identical; new CI step npm run check:dist
  fails if any mock marker leaks into dist/
- Docs: CONTRIBUTING mock-mode section, ROADMAP W7 section, ARCHITECTURE_
  ESSENTIALS src/mocks note; shared src/query-client.ts for cache
  invalidation from the panel

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Oct 18, 2026

Copy link
Copy Markdown

@mskdylan Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@afeezorobsco-cyber
afeezorobsco-cyber merged commit 39f8ba0 into DocForum:main Oct 18, 2026
1 check passed
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.

[Platform] Mock API for local development (MSW) so the app runs without a backend

2 participants