Setup-store pattern (setup function style) with fetchFor, analyze,
saveResponse, and clear. analysis ref stores mode + rawInput so
saveResponse can build the full POST body without re-passing them.
6/6 unit tests pass; full suite 15/15.
Add GET /api/vision/health, POST /api/jobs/{id}/survey/analyze,
POST /api/jobs/{id}/survey/responses, and GET /api/jobs/{id}/survey/responses
to dev-api.py. All 10 TDD tests pass; 549 total suite tests pass (0 regressions).
Contacts 5xx no longer early-returns from fetchFor, leaving the entire
right panel blank. A new contactsError ref surfaces the failure message
in the Email tab only; JD tab, Cover Letter tab, and match score all
render normally. Adds test asserting partial degradation behavior.
- Fix 1: Add missing `:` binding prefix to aria-label on score badge
(was emitting literal backtick template string to DOM)
- Fix 2: Remove unused `watch` import from InterviewPrepView.vue
- Fix 3: guardAndLoad now checks interviewsStore.error after fetchAll;
shows pageError banner instead of silently redirecting to /interviews
on network failure; job is now a ref set explicitly in the guard
- Fix 4: Remove unconditional research-badge from InterviewCard.vue
(added in this branch; card has no access to prep store so badge
always showed regardless of whether research exists)
Two-column desktop layout (40/60 split, sticky left panel):
- Left: job header with stage badge, interview countdown chip, research
controls (generate/spinner/refresh/retry), and research sections
(talking points, company, leadership, tech, funding, red flags, A11y)
- Right: tabbed panel (JD + match score/keyword gaps, email history,
cover letter) plus locally-persisted call notes via @vueuse/core
- Mobile (≤1023px): single-column, left content first
- Routing guard: redirects to /interviews if no id, job not found, or
wrong status; calls prepStore.fetchFor on mount, clear on unmount
- Check error from POST /research/generate; only start pollTask on success to prevent unresolvable polling intervals
- Surface contacts and fullJob fetch errors in fetchFor; silently ignore research 404 (expected when no research yet)
- Remove redundant type assertions (as Contact[], as TaskStatus, as FullJobDetail)
- Add @internal JSDoc to pollTask
- Remove redundant vi.runAllTimersAsync() after vi.advanceTimersByTimeAsync(3000) in test
Delete useApiFetch.ts wrapper (returned T|null) and update prep.ts and
prep.test.ts to import useApiFetch from useApi.ts directly, destructuring
{ data, error } to match the established pattern used by all other stores.
Adds usePrepStore (Pinia) for interview prep data: parallel fetch of
research brief, contacts, task status, and full job detail; setInterval-
based polling that stops on completion and re-fetches; clear() cancels
the interval and resets all state. Also adds useApiFetch composable
wrapper (returns T|null directly) used by the store.
- Replace lazy import + scripts.db.get_research with inline SQL via _get_db(),
matching the pattern used by research_task_status and get_job_contacts
- Exclude raw_output from SELECT instead of post-fetch pop
- Change HTTPException in generate_research to positional-arg style
- Update test_get_research_found/not_found to patch dev_api._get_db
- _parse_message now prefers text/html over text/plain so digest emails
retain href attribute values needed for link extraction
- Strip <head>, <style>, <script> blocks before storing to remove CSS/JS
garbage while keeping anchor tags intact
- Remove [:4000] truncation — digest emails need full body for URL regex
- Update test: large body should NOT be truncated (assert len == 10_000)