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
- router: add /apply/:id → ApplyWorkspaceView (lazy-loaded)
- ApplyView.vue: approved job list sorted by match score; badges for
match %, remote, and cover-letter draft status; links to workspace
- ApplyWorkspaceView.vue: two-panel desktop layout (sticky job details
left, editor right); cover letter state machine (none/queued/running/
ready/failed); auto-resize textarea; word count toolbar; Save button
with dirty tracking; Download PDF (programmatic <a> click, named file);
Generate with AI + Retry; Mark as Applied + Reject Listing actions;
polling loop for in-flight generation tasks; toast on action
- HomeView.vue: split combined "Archive Pending + Rejected" into three
separate per-status archive buttons (only shown when count > 0)
- dev-api.py: add GET /api/jobs/:id, POST /api/jobs/:id/applied,
PATCH /api/jobs/:id/cover_letter, POST .../cover_letter/generate
(wires submit_task), GET .../cover_letter/task (poll), GET .../pdf
(reportlab); has_cover_letter field on list + detail responses