AI_Inter/
├─ docs/ # this design set + the GitHub Pages site
│ # (index.html landing, _config.yml, media/, images/)
├─ electron.vite.config.ts # main + preload + renderer build config
├─ electron-builder.yml # packaging (win/mac/linux, icons)
├─ drizzle.config.ts # drizzle-kit (schema -> migrations)
├─ drizzle/ # generated SQL migrations + meta (bundled into the app)
├─ package.json
├─ tsconfig.json / tsconfig.node.json / tsconfig.web.json
├─ tailwind.config.js / postcss.config.js
├─ vitest.config.ts
├─ .gitignore
├─ index.html # single renderer entry (dashboard/overlay/selection roots chosen at runtime)
│
├─ CONTRIBUTING.md # setup, gate, IPC contract, invariants
├─ SECURITY.md / CODE_OF_CONDUCT.md
├─ .github/workflows/ # ci.yml · release.yml · pages.yml · auto-merge.yml
├─ .github/ # CODEOWNERS · PR template · ISSUE_TEMPLATE/
│
├─ scripts/
│ ├─ run-electron-vite.mjs # dev/preview launcher
│ ├─ clean-release.mjs # kill running app + wipe release/ (pre-package)
│ ├─ generate-icon.mjs # icon.svg -> icon.png + icon.ico
│ ├─ build-media.mjs # capture frames -> docs/media gif+mp4 (ffmpeg)
│ └─ privacy-affinity/ # the privacy hard test (hardtest.js)
│
├─ e2e/ # Playwright vs the BUILT app over CDP (see e2e/README.md)
│ ├─ fixtures.ts # spawn + connect harness, disablePrivacyMode
│ ├─ *.spec.ts # smoke / data-integrity / live tiers
│ └─ *.capture.spec.ts # opt-in (E2E_CAPTURE=1) marketing stills + clips
│
├─ resources/ # build resources (not packed into app)
│ ├─ icon.svg # icon source
│ ├─ icon.png # 1024² master (mac/linux)
│ └─ icon.ico # multi-resolution Windows icon
│
├─ src/
│ ├─ shared/ # imported by BOTH main and renderer (types/constants only)
│ │ ├─ ipc.ts # IPC + EVENTS channel name constants
│ │ ├─ types.ts # domain types (Profile, Job, Session, ...)
│ │ └─ result.ts # Result<T> envelope
│ │
│ ├─ main/ # MAIN PROCESS (Node, trusted)
│ │ ├─ index.ts # entry: lifecycle, init order
│ │ ├─ env.ts # isDev, paths, env var access
│ │ ├─ shortcuts.ts # global shortcut registration
│ │ ├─ windows/
│ │ │ ├─ mainWindow.ts overlayWindow.ts selectionWindow.ts
│ │ │ └─ loadRenderer.ts # dev-URL vs file load + diagnostics
│ │ ├─ ipc/
│ │ │ ├─ index.ts # registerIpc(): wires all handlers
│ │ │ ├─ helpers.ts # handle() wrapper + zod validation
│ │ │ ├─ broadcast.ts # push events to dashboard/overlay
│ │ │ ├─ settings.ipc.ts profiles.ipc.ts documents.ipc.ts
│ │ │ ├─ jobs.ipc.ts notes.ipc.ts session.ipc.ts mock.ipc.ts
│ │ │ ├─ capture.ipc.ts overlay.ipc.ts dialog.ipc.ts
│ │ ├─ db/
│ │ │ ├─ index.ts # better-sqlite3 + drizzle init + migrate
│ │ │ ├─ schema.ts # drizzle table definitions
│ │ │ └─ repositories/ # typed data access per entity
│ │ │ ├─ profiles.repo.ts jobs.repo.ts
│ │ │ ├─ sessions.repo.ts settings.repo.ts
│ │ ├─ providers/ # capability seam (v2): types.ts registry.ts errors.ts + openai/ impls
│ │ ├─ services/
│ │ │ ├─ engine/ # v2 conversation engine (see 12-ENGINE-PLAN.md)
│ │ │ │ ├─ engine.ts engineSession.ts modeDefinition.ts grounding.ts
│ │ │ │ ├─ meetingReport.ts contextEvent.ts sourceAdapter.ts
│ │ │ │ ├─ persona.ts # the ONE companion-personality prompt source
│ │ │ │ ├─ modes/ # interview.mode.ts meeting.mode.ts companion.mode.ts
│ │ │ │ ├─ trigger/ # reactiveQuestion summoned meetingHeuristics salience ambientPolicy presence
│ │ │ │ │ # + companion: interjectionPolicy companionSalience companionPresence
│ │ │ │ ├─ companion/ # costMeter.ts (visible estimate + budget gates)
│ │ │ │ └─ persistence/enginePersistence.ts
│ │ │ ├─ memory/ # local memory: extractor memoryService recall sensitiveFilter
│ │ │ ├─ voice/ # voice/summon layer
│ │ │ │ ├─ dialogueController.ts # explicit FSM: idle/listening/thinking/speaking/interrupted/paused/error
│ │ │ │ ├─ voiceService.ts # orchestrator: PTT buffer, STT, routing, sentence-chunked TTS
│ │ │ │ ├─ quickAnswer.ts # no-session quick ask (spoken-style persona)
│ │ │ │ └─ sentenceStream.ts wav.ts
│ │ │ ├─ openai/ # see 06-OPENAI-SERVICE.md
│ │ │ │ ├─ client.ts models.ts parsing.ts embeddings.ts
│ │ │ │ ├─ questions.ts answer.ts transcription.ts
│ │ │ │ ├─ coding.ts codingPrompt.ts vision.ts
│ │ │ │ ├─ interviewer.ts # mock-interview question/feedback gen
│ │ │ │ ├─ tts.ts # text-to-speech (mock voice)
│ │ │ │ └─ realtime.ts realtimeEvents.ts # Realtime STT
│ │ │ ├─ rag/
│ │ │ │ ├─ vectorStore.ts # interface + SQLite blob store
│ │ │ │ ├─ vectorMath.ts # cosine / decode helpers
│ │ │ │ ├─ chunker.ts # text -> chunks
│ │ │ │ ├─ indexProfile.ts # reindexProfile() + indexJob()
│ │ │ │ └─ retriever.ts # embed query -> top-k
│ │ │ ├─ documents/
│ │ │ │ ├─ extract.ts # pdf/docx/txt/md -> text
│ │ │ │ ├─ fetchUrl.ts # download a posting URL -> readable text
│ │ │ │ └─ companyResearch.ts # scrape company site (home + about/careers…) -> text
│ │ │ ├─ capture/
│ │ │ │ ├─ screenshot.ts # desktopCapturer + region crop
│ │ │ │ └─ codingMode.ts # coding-question solve flow
│ │ │ ├─ mock/
│ │ │ │ └─ mockManager.ts # mock-interview session orchestration
│ │ │ ├─ session/
│ │ │ │ ├─ sessionManager.ts# live session orchestration
│ │ │ │ ├─ report.ts # post-session report generation
│ │ │ │ └─ privacy.ts # screen-capture privacy affinity
│ │ │ ├─ stt/ # speech-to-text engine choice + local engine (see 22-LOCAL-STT.md)
│ │ │ │ ├─ index.ts # seam: readSttPrefs / sttReady / applySttSelection
│ │ │ │ ├─ prefs.ts # persisted SttPrefs
│ │ │ │ ├─ modelStore.ts # <userData>/models/stt/<id>: installed(), bytesOnDisk(), active downloads
│ │ │ │ ├─ downloader.ts # resumable, size-verified download (Range + .part)
│ │ │ │ ├─ worker.ts # sherpa-onnx recognizer — a utilityProcess (out/main/stt-worker.js)
│ │ │ │ ├─ localRealtimeStt.ts # the `local` RealtimeSttProvider driving the worker
│ │ │ │ └─ protocol.ts pcm.ts # worker messages; PCM16→Float32 + 24k→16k helpers
│ │ │ └─ security/
│ │ │ ├─ apiKey.ts # safeStorage-backed ApiKeyStore
│ │ │ └─ logger.ts # redacting logger
│ │ │
│ ├─ preload/
│ │ ├─ index.ts # contextBridge -> window.api (typed facade)
│ │ └─ index.d.ts # ambient types for window.api
│ │
│ └─ renderer/ # RENDERER (React)
│ ├─ main.tsx # entry: mounts dashboard / overlay / selection
│ ├─ index.css # tailwind entry
│ ├─ components/ # Markdown.tsx Waveform.tsx ui.tsx (shared kit)
│ ├─ lib/
│ │ ├─ api.ts # thin wrapper over window.api
│ │ ├─ useMicCapture.ts useAnswerRecorder.ts pcm.ts
│ │ └─ usePagedSearch.ts
│ ├─ store/ # zustand: useProfileStore.ts useSettingsStore.ts useTourStore.ts
│ ├─ dashboard/
│ │ ├─ App.tsx # router + shell (5-section sidebar, hosts the guided tour)
│ │ ├─ Tour.tsx # first-run guided tour (spotlight + steps)
│ │ ├─ StartSessionModal.tsx startFlow.ts # the shared universal start flow
│ │ ├─ library/ # Library tabs: ProfilesTab SpacesTab DocumentsTab
│ │ └─ pages/ (Home, Library, ProfileEditor, Interview, Mock, Sparring, Tailor, Sessions, Reports=Insights, Settings)
│ ├─ overlay/ # always-on-top Cue Card (contribution feed)
│ │ ├─ Overlay.tsx # shell: window state, IPC subscriptions, composition
│ │ ├─ store/useOverlayStore.ts # zustand card feed (reducers in cards/model.ts)
│ │ ├─ cards/ # ContributionCard frame + registry.ts + per-kind views + UnknownCardView
│ │ ├─ controls/ # HeaderBar SessionBar AnswerControls AskBar VoiceBar Btn EqualizerBars
│ │ ├─ panels/ # ClientNotes Captures ErrorBanner AudioMeter Transcript DataSent SettingsModal
│ │ ├─ voice/ # useVoice.ts (state mirror + VAD) voiceCapture.ts voicePlayer.ts (setSinkId queue)
│ │ └─ lib/ # streamBuffer.ts (rAF token coalescer) style.ts
│ └─ selection/RegionSelector.tsx # region-capture window
│
└─ (userData at runtime: app.db, documents/, vectors/ — see 04-DATABASE.md)
src/shared must contain types and constants only (no Node, no DOM) so it
is safe to import from both sides.src/main may use Node + Electron main APIs. Never imported by renderer.src/renderer may use DOM/React. Reaches main only via window.api.src/preload is the only place using contextBridge/ipcRenderer.Path aliases (configured in electron.vite.config.ts + tsconfigs): @shared,
@main, @renderer.