51f5b3f0a0
fix: bootstrap digest store on app mount for correct badge count on load
2026-03-20 10:27:13 -07:00
5621140a72
fix: add error feedback and keyboard accessibility to DigestView
2026-03-20 10:16:24 -07:00
8302b58b20
feat: add DigestView with expand/extract/queue UI
2026-03-20 10:12:45 -07:00
247f807e02
fix: bind aria-label on nav badge span (was static string, not template expression)
2026-03-20 10:10:10 -07:00
165811c420
feat: add Digest tab to nav and router
2026-03-20 10:07:12 -07:00
154f691334
style: use void instead of .catch on fire-and-forget digest-queue call
2026-03-20 10:06:04 -07:00
4246e71061
feat: fire digest-queue add call from digest chip handler
2026-03-20 09:58:16 -07:00
9bf14fbc75
fix: add error rollback and error state hygiene in digest store
2026-03-20 09:56:22 -07:00
4c2a08057c
feat: add digest Pinia store
2026-03-20 09:52:52 -07:00
f3e7f89e2e
style: pass Path(DB_PATH) to insert_job for type consistency
2026-03-20 09:51:35 -07:00
1b2643675d
feat: add queue-jobs and delete digest endpoints
2026-03-20 07:44:19 -07:00
5bb3674fea
fix: guard extract_digest_links db.close(), remove domain-in-path false positive, add hint assertion
2026-03-20 07:04:24 -07:00
182ab789df
feat: add /extract-links endpoint with URL scoring
2026-03-20 06:59:26 -07:00
7993984af9
fix: guard db.close() in add_to_digest_queue with try/finally
2026-03-20 06:54:50 -07:00
a503ecde3b
feat: add GET/POST /api/digest-queue endpoints
2026-03-20 02:51:17 -07:00
0590a3a12e
fix: fix indentation and add try/finally in digest startup
2026-03-20 02:36:23 -07:00
6a1ee3ed28
feat: add digest_queue table to schema and dev-api startup
2026-03-20 02:34:41 -07:00
c6f810fb30
feat(signals): add Unrelated and Digest reclassify chips to InterviewsView
2026-03-19 20:01:08 -07:00
87aae6eefc
feat(signals): add Unrelated and Digest reclassify chips to InterviewCard
2026-03-19 20:00:27 -07:00
34494db8d8
feat(signals): strip HTML and normalize whitespace from email bodies
2026-03-19 19:59:59 -07:00
909fe60908
feat(interviews): paginate applied list (10 per page)
2026-03-19 19:45:59 -07:00
e487942eeb
fix(signals): add .stop modifiers and aria-labels to pre-list signal banner buttons
2026-03-19 19:35:15 -07:00
9de51d6b4a
feat(signals): expandable body + reclassify chips in InterviewsView pre-list
2026-03-19 19:31:23 -07:00
804c2a8064
fix(signals): per-signal expand state, error rollback, type safety in InterviewCard
2026-03-19 19:26:36 -07:00
2796d0d911
feat(signals): expandable body + reclassify chips in InterviewCard
2026-03-19 19:22:10 -07:00
3b2df5e89e
feat(signals): add body and from_addr to StageSignal interface
2026-03-19 19:19:27 -07:00
218f4ff9c8
fix(signals): capture rowcount after commit in reclassify_signal (consistency)
2026-03-19 19:18:43 -07:00
1d943ed8a3
feat(signals): add body/from_addr to signal query; add reclassify endpoint
2026-03-19 19:14:11 -07:00
e24e0b7233
feat(interviews): collapsible Applied section, email sync pill, pre-list signal banners
2026-03-19 16:38:05 -07:00
5ca25e160c
feat(interviews): add stage signal banners and extend move emit in InterviewCard
2026-03-19 16:31:33 -07:00
52c7dfcfe3
feat(interviews): add preSelectedStage prop to MoveToSheet
2026-03-19 16:25:48 -07:00
6e2ddaf6da
feat(interviews): export StageSignal interface; add stage_signals to PipelineJob
2026-03-19 16:22:59 -07:00
bc8174271e
feat(interviews): add stage signals, email sync, and dismiss endpoints to dev-api
2026-03-19 16:17:22 -07:00
4abdf21981
fix(apply): check saveCoverLetter error; document cover-letter-generated in wrapper
2026-03-19 08:36:19 -07:00
1006e88e5b
fix(apply): ensure loading resets on fetchJobs error and clear toast timer on unmount
2026-03-19 08:24:52 -07:00
b94828855b
feat(apply): desktop split-pane layout with narrow list, expand animation, speed demon + marathon easter eggs
2026-03-19 08:21:08 -07:00
d8aca3ec52
feat(apply): extract ApplyWorkspace component with job-removed emit and perfect match easter egg
2026-03-19 08:14:15 -07:00
5ac742d892
refactor(apply): add score-badge--mid-high token for 4-tier scoring
2026-03-19 08:09:39 -07:00
73c2557c31
feat(interviews): complete InterviewsView with kanban, keyboard nav, confetti
...
Replaces stub with full kanban implementation: three-column pipeline
(Phone Screen / Interviewing / Offer+Hired), pre-list for applied/survey
jobs, rejected accordion, keyboard navigation (arrow keys + vim keys),
confetti easter egg on hired move (respects prefers-reduced-motion),
and /prep/:id route added to router.
2026-03-19 00:38:11 -07:00
c5b3d31cb9
feat(interviews): add MoveToSheet bottom sheet / dialog component
2026-03-18 18:15:02 -07:00
b523707d17
feat(interviews): add InterviewCard component (medium density)
2026-03-18 18:15:01 -07:00
4dcab5ff29
feat(interviews): add interviews Pinia store with optimistic moves
...
Setup-form Pinia store with per-stage computed lanes, optimistic status
mutation on move, and API-error rollback. Shallow-copies API response
objects on fetch to prevent shared-reference mutation across tests.
2026-03-18 15:26:44 -07:00
6fb366e499
feat(interviews): add /api/interviews and /api/jobs/:id/move endpoints
...
Adds GET /api/interviews to fetch all pipeline-stage jobs in one call,
and POST /api/jobs/:id/move to transition a job between kanban statuses
with automatic timestamp stamping (or rejection_stage capture).
2026-03-18 15:22:51 -07:00
cce0f8195a
feat(vue-spa): Apply view — job picker list + cover letter workspace
...
- 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
2026-03-18 09:05:40 -07:00
d138b27619
fix(vue-spa): suppress spring snap-back on processed cards
...
When a new job prop arrives after approve/reject, the watch cleared the
exit-transform inline style while the spring transition was still active,
causing the card to animate from offscreen back to center before the new
card rendered. Fix: set transition:none before clearing the style, then
restore it on the next rAF — browser paints the new position first.
2026-03-17 22:39:06 -07:00
1f5ab2df37
chore(vue-spa): dev API + Vite proxy for live data during development
...
- dev-api.py: minimal FastAPI on :8601 reading /devl/job-seeker/staging.db
Endpoints: GET /api/jobs, /api/jobs/counts, POST /api/jobs/{id}/approve|reject|revert,
GET /api/system/status, /api/config/user
- vite.config.ts: server.proxy /api/* → localhost:8601; host: 0.0.0.0 for LAN access
2026-03-17 22:36:45 -07:00
75cc0760e1
feat(vue-spa): JobReviewView card stack with swipe gestures
...
- stores/review.ts: Pinia setup store — pending queue, undo stack,
stoop-speed session timer (easter egg 9.2: 10 cards/60s)
- components/JobCard.vue: card content with match-score badge (colored
pill), keyword-gap pills, expand/collapse description, footer with
job URL + relative date; shimmer animation for ≥95% matches (ee 9.4)
- components/JobCardStack.vue: pointer-event drag with setPointerCapture,
rolling 50ms velocity buffer for fling detection (600px/s + cos45°
alignment), left/right color-tint overlay (red/green), spring snap-back
on no-action, buffered exit animation before emitting approve/reject
- views/JobReviewView.vue: segmented status tabs, card stack for pending,
list view for other statuses, action buttons, keyboard shortcuts
(←/J reject, →/L approve, S skip, Z undo, ? help), help overlay,
undo toast (5s), falcon stoop empty state (easter egg 9.3)
2026-03-17 22:30:33 -07:00
f3ce46e252
feat(web): implement design spec — peregrine.css, sidebar nav, HomeView
...
Applies the full design spec from circuitforge-plans/peregrine/2026-03-03-nuxt-design-system.md:
CSS tokens:
- Falcon Blue (#2B6CB0 / #68A8D8 dark) — was incorrectly using forest green
- Talon Orange (#E06820 / #F6872A dark) with --app-accent-text dark navy (never white)
- Full pipeline status token set (--status-pending/approve/reject/applied/synced/...)
- Match score tokens, motion tokens, type scale tokens
- Dark mode + hacker mode overrides
AppNav: sidebar layout (replaces top bar)
- Desktop ≥1024px: persistent sidebar with brand, links, hacker-exit, settings footer
- Mobile <1024px: bottom tab bar with 5 primary destinations
- Click-the-bird easter egg (9.6): 5 rapid clicks → ruffle animation
- Heroicons via @heroicons/vue/24/outline
App.vue:
- Skip-to-content link (a11y)
- Sidebar margin-left layout (desktop) / tab bar clearance (mobile)
HomeView: full dashboard implementation
- Pipeline metric cards (Pending/Approved/Applied/Synced/Rejected) with status colors
- Primary workflow buttons (Run Discovery, Sync Emails, Score Unscored) + sync banner
- Auto-enrichment status row
- Backlog management (conditionally visible)
- Add Jobs by URL / CSV upload tabs
- Advanced/danger zone in collapsible <details>
- Stoop speed toast easter egg (9.2)
- Midnight mode greeting easter egg (9.7)
WorkflowButton component with loading spinner, proper touch targets (min-height 44px)
Pinia jobs store (setup form) with counts + system status
Build: clean 2.28s, 0 errors
2026-03-17 22:00:42 -07:00
ae6021ceeb
feat(web): Vue 3 SPA scaffold with avocet lessons applied
...
Sets up web/ Vue 3 SPA skeleton for issue #8 , synthesizing all 15 gotchas
from avocet's Vue port testbed. Key fixes baked in before any component work:
- App.vue root uses .app-root class (not id="app") — gotcha #1
- overflow-x: clip on html (not hidden) — gotcha #3
- UnoCSS presetAttributify with prefixedOnly: true — gotcha #4
- peregrine.css alias map for theme variable names — gotcha #5
- useHaptics guards navigator.vibrate — gotcha #9
- Pinia setup store pattern documented — gotcha #10
- test-setup.ts stubs matchMedia, vibrate, ResizeObserver — gotcha #12
- min-height: 100dvh throughout — gotcha #13
Includes:
- All 7 Peregrine views as stubs (ready to port from Streamlit)
- AppNav with all routes
- useApi (fetch + SSE), useMotion, useHaptics, useEasterEgg composables
- Konami hacker mode easter egg + confetti + cursor trail
- docs/vue-spa-migration.md: full migration guide + implementation order
- Build verified clean (0 errors)
- .gitleaks.toml: allowlist web/package-lock.json (sha512 integrity hashes)
2026-03-17 21:24:00 -07:00
bf1dc39f14
fix(tests): update mock from inner_text() to text_content() in e2e helpers
...
get_page_errors() was switched to text_content() to capture errors in
CSS-hidden elements (collapsed Streamlit expanders). Two unit test mocks
still stubbed inner_text() — causing CI failures because MagicMock()
returned a non-string from text_content(), breaking the "boom" in message
content assertion.
2026-03-17 20:33:55 -07:00