Historical. This is the v1 (interview-copilot) build plan, fully shipped as of v1.5.3. The current plan is 10-ROADMAP.md; the v2 spec is 01-PRD.md and the vision 00-VISION.md.
Incremental milestones. Each is independently runnable/testable. The skeleton in this repo delivers M0 and the scaffolding for M1–M2.
handle() wrapper, Result<T>).ApiKeyStore (safeStorage) + settings:set/get/test-api-key.vectorStore persistence (auto re-index on import/notes).services/rag/retriever.ts) — an internal service call, not an IPC channel.ProfileEditorPage (resume/JD upload + paste + parse, notes).sessionManager state machine.useMicCapture, segmented MediaRecorder) → audio
chunks via IPC; main approves only media permission.gpt-4o-transcribe, server-side VAD):
live partial deltas + precise finalized turns (realtime.ts).session:realtime-audio).setDisplayMediaRequestHandler({ audio: 'loopback' }).session:context event.Ctrl+Shift+Enter or “Solve from clipboard”) →
coding.solveFromOcr streaming to the overlay.Ctrl+Shift+S / “Select region” → captures the primary screen,
opens a transparent full-screen selection window; drag-select → crop the
frozen frame (canvas, devicePixelRatio-aware) → vision.solveFromImage.setContentProtection on overlay + selector),
togglable from the overlay header and Settings, with compliance reminder.components/ui.tsx): Button, Card, Badge, Field, inputs,
Spinner, PageHeader, BusyOverlay.documents:save-resume,
documents:extract-file) with a blocking spinner; decoupled from key presence
so saving always works. JD entry moved to the per-job flow (see below).jobs table holds each target role’s JD +
parsed JSON, added/parsed independently of the resume.documents:save-resume,
jobs:save); JD is optional and can be added later.jobs.jdUrl): paste a job-posting URL
and “Fetch” (documents:fetch-url) best-effort downloads + strips it to text;
the link itself is stored for reference (clickable) but not parsed. If the link
can’t be fetched, the user is prompted to paste the JD manually.jobs.companyUrl): on
save the app scrapes the site (services/documents/companyResearch.ts), parses
it (parseCompany) into jobs.parsedCompany, and indexes it as company
chunks scoped to the job — so answers can speak to the company. Best-effort;
failures surface as companyError and don’t fail the save.jobId; retrieval always includes resume/notes and,
when a session/mock selects a job, that job’s JD chunks too
(sessions.jobId, retrieve(..., jobId)).dashboard/Tour.tsx, useTourStore) spotlights the
sidebar to walk through key → profile → interview → overlay → reports.settings.tourDone; replayable from Settings →
Getting started.resources/icon.svg; pre-package clean step (scripts/clean-release.mjs).npm run typecheck).npm install
npm run dev # electron-vite dev (HMR for renderer)
npm run typecheck
npm run db:generate # drizzle-kit generate migrations from schema
npm run build # type build + bundle
npm run package # electron-builder