[New Feature] Vue 3 SPA frontend — replace Streamlit UI with Vite + Vue 3 + FastAPI #8

Closed
opened 2026-03-04 09:32:37 -08:00 by pyr0ball · 2 comments
Owner

Overview

Design doc: docs/plans/2026-03-03-nuxt-frontend-design.md
Design system: docs/plans/2026-03-03-nuxt-design-system.md

Replace the Streamlit UI with a purpose-built Vite + Vue 3 SPA served directly by FastAPI. Avocet's label tab (PR #1) is the proof-of-concept — this feature ports that architecture to Peregrine.

Motivation

Streamlit ceilings:

  • No real gesture support (swipe UX requires hacky HTML components)
  • Multi-column interactions are clunky
  • Mobile/tablet is essentially unusable
  • Every UI interaction forces a full Python rerun

Vue 3 SPA unlocks:

  • Swipe-to-approve card stack on Job Review (VueUse gestures, proven in Avocet)
  • Responsive, theme-aware UI matching the CircuitForge design system
  • Reactive state without full-page reloads (Pinia)
  • Clean path to Electron/Tauri desktop app later

Why not Nuxt?

Peregrine is a private self-hosted tool — SSR provides no SEO benefit and adds a second runtime process. The shared design system travels as a CSS file + component patterns without requiring the same framework.

Key Views

  1. Home / Dashboard — pipeline stats, quick actions, active task status
  2. Job Review — swipe card stack (approve/skip/archive), cover letter gen trigger
  3. Applications — kanban-style status board
  4. Settings — wizard-style onboarding, LLM config, integrations

Stack

  • Vite + Vue 3 + TypeScript + UnoCSS + Pinia + VueUse
  • Served by FastAPI (same pattern as Avocet) — no Node.js process in production
  • CircuitForge shared theme CSS (CSS variables, dark mode, hacker mode easter egg)
  • Self-hosted fonts (no Google Fonts)

Privacy & Safety Requirements

  • No telemetry, analytics, or third-party scripts
  • DEMO_MODE=true replaces all data with fixtures for menagerie.circuitforge.tech/peregrine
  • ConfirmModal.vue required for all destructive actions
  • Integration credentials never returned to frontend in plaintext

Acceptance Criteria

  • All four main views functional and responsive (375px–1440px)
  • Swipe gestures work on mobile and trackpad
  • All existing Streamlit features accessible in new UI
  • ./manage.sh build-spa builds the SPA; FastAPI serves it
  • All pytest tests pass
## Overview Design doc: `docs/plans/2026-03-03-nuxt-frontend-design.md` Design system: `docs/plans/2026-03-03-nuxt-design-system.md` Replace the Streamlit UI with a purpose-built Vite + Vue 3 SPA served directly by FastAPI. Avocet's label tab (PR #1) is the proof-of-concept — this feature ports that architecture to Peregrine. ## Motivation Streamlit ceilings: - No real gesture support (swipe UX requires hacky HTML components) - Multi-column interactions are clunky - Mobile/tablet is essentially unusable - Every UI interaction forces a full Python rerun Vue 3 SPA unlocks: - Swipe-to-approve card stack on Job Review (VueUse gestures, proven in Avocet) - Responsive, theme-aware UI matching the CircuitForge design system - Reactive state without full-page reloads (Pinia) - Clean path to Electron/Tauri desktop app later ## Why not Nuxt? Peregrine is a private self-hosted tool — SSR provides no SEO benefit and adds a second runtime process. The shared design system travels as a CSS file + component patterns without requiring the same framework. ## Key Views 1. **Home / Dashboard** — pipeline stats, quick actions, active task status 2. **Job Review** — swipe card stack (approve/skip/archive), cover letter gen trigger 3. **Applications** — kanban-style status board 4. **Settings** — wizard-style onboarding, LLM config, integrations ## Stack - Vite + Vue 3 + TypeScript + UnoCSS + Pinia + VueUse - Served by FastAPI (same pattern as Avocet) — no Node.js process in production - CircuitForge shared theme CSS (CSS variables, dark mode, hacker mode easter egg) - Self-hosted fonts (no Google Fonts) ## Privacy & Safety Requirements - No telemetry, analytics, or third-party scripts - `DEMO_MODE=true` replaces all data with fixtures for `menagerie.circuitforge.tech/peregrine` - `ConfirmModal.vue` required for all destructive actions - Integration credentials never returned to frontend in plaintext ## Acceptance Criteria - All four main views functional and responsive (375px–1440px) - Swipe gestures work on mobile and trackpad - All existing Streamlit features accessible in new UI - `./manage.sh build-spa` builds the SPA; FastAPI serves it - All pytest tests pass
pyr0ball self-assigned this 2026-03-14 16:39:53 -07:00
pyr0ball added this to the The Menagerie project 2026-03-14 16:39:55 -07:00
pyr0ball added this to the Paid Tier GA milestone 2026-03-14 16:40:04 -07:00
pyr0ball added the
feature-request
label 2026-03-14 16:41:48 -07:00
Author
Owner

Progress update — v0.7.0 (2026-03-24)

The Vue SPA has shipped its first full feature set and is live in the cloud instance at menagerie.circuitforge.tech/peregrine behind the prgn_ui=vue cookie (paid+ tier).


What's been built

Scaffold & infrastructure

  • Vite + Vue 3 + TypeScript + UnoCSS SPA scaffolded with lessons from Avocet label tool
  • peregrine.css design system — full dark/light theme-aware CSS vars matching CircuitForge design language
  • Sidebar nav with badge indicators, responsive layout
  • Multi-stage Docker build; web service added to compose.yml (nginx, port 8507 cloud / 8506 local)
  • Vite proxy for live Streamlit API data during local dev

Views shipped

View Notes
HomeView Dashboard — sync status, quick stats
JobReviewView Swipe card stack with VueUse gesture support (the primary motivation for leaving Streamlit)
ApplyView + ApplyWorkspaceView Job picker list + cover letter workspace; perfect-match easter egg
InterviewsView Kanban — phone_screen → interviewing → offer → hired
InterviewPrepView Live reference sheet + practice Q&A
SurveyView Culture-fit survey assistance
DigestView (scaffold)
SettingsView Full settings shell with tab routing

Key components

  • JobCardStack / JobCard — swipe-to-approve with spring snap-back suppressed
  • ApplyWorkspace — extracted component with job-removed emit
  • InterviewCard, MoveToSheet, WorkflowButton, TaskIndicator
  • ClassicUIButton — switch-back to Streamlit from within Vue
  • AppNav — sidebar with live badge counts

UI switcher (Streamlit ↔ Vue)

  • app/components/ui_switcher.pysync_ui_cookie(), switch_ui(), banner, settings toggle, sidebar button
  • ui_preference field in user.yaml (persists across browser clears)
  • Tier gate: vue_ui_beta feature key (paid+ required)
  • Cookie-based Caddy routing: prgn_ui=vue → Vue nginx; absent/streamlit → Streamlit
  • ?prgn_switch=streamlit query param for Vue-initiated switch-back
  • ?ui_fallback=1 param for Caddy bounce-back when Vue SPA is down
  • Self-service free key claim card on /account (website) for auto-provision recovery

Routing / cloud integration

  • Caddy routes prgn_ui cookie per-user in cloud instance
  • PEREGRINE_VUE_URL env var bypasses Caddy for local dev
  • Cloud and demo instances now guard against Vue navigation in demo mode (demo Vue SPA not yet implemented — see #46)

What's next

  • Settings tabs in Vue (profile, search prefs, LLM, license) — currently scaffold only
  • First-run wizard port to Vue
  • Full mobile / gesture polish pass
  • Vue SPA demo mode (#46) — pre-seeded read-only data, no auth
  • E2E Playwright tests for Vue views
  • Promote to default UI for paid tier (currently opt-in banner)
## Progress update — v0.7.0 (2026-03-24) The Vue SPA has shipped its first full feature set and is live in the cloud instance at `menagerie.circuitforge.tech/peregrine` behind the `prgn_ui=vue` cookie (paid+ tier). --- ### What's been built **Scaffold & infrastructure** - Vite + Vue 3 + TypeScript + UnoCSS SPA scaffolded with lessons from Avocet label tool - `peregrine.css` design system — full dark/light theme-aware CSS vars matching CircuitForge design language - Sidebar nav with badge indicators, responsive layout - Multi-stage Docker build; `web` service added to `compose.yml` (nginx, port 8507 cloud / 8506 local) - Vite proxy for live Streamlit API data during local dev **Views shipped** | View | Notes | |------|-------| | `HomeView` | Dashboard — sync status, quick stats | | `JobReviewView` | Swipe card stack with VueUse gesture support (the primary motivation for leaving Streamlit) | | `ApplyView` + `ApplyWorkspaceView` | Job picker list + cover letter workspace; perfect-match easter egg | | `InterviewsView` | Kanban — phone_screen → interviewing → offer → hired | | `InterviewPrepView` | Live reference sheet + practice Q&A | | `SurveyView` | Culture-fit survey assistance | | `DigestView` | (scaffold) | | `SettingsView` | Full settings shell with tab routing | **Key components** - `JobCardStack` / `JobCard` — swipe-to-approve with spring snap-back suppressed - `ApplyWorkspace` — extracted component with job-removed emit - `InterviewCard`, `MoveToSheet`, `WorkflowButton`, `TaskIndicator` - `ClassicUIButton` — switch-back to Streamlit from within Vue - `AppNav` — sidebar with live badge counts **UI switcher (Streamlit ↔ Vue)** - `app/components/ui_switcher.py` — `sync_ui_cookie()`, `switch_ui()`, banner, settings toggle, sidebar button - `ui_preference` field in `user.yaml` (persists across browser clears) - Tier gate: `vue_ui_beta` feature key (paid+ required) - Cookie-based Caddy routing: `prgn_ui=vue` → Vue nginx; absent/streamlit → Streamlit - `?prgn_switch=streamlit` query param for Vue-initiated switch-back - `?ui_fallback=1` param for Caddy bounce-back when Vue SPA is down - Self-service free key claim card on `/account` (website) for auto-provision recovery **Routing / cloud integration** - Caddy routes `prgn_ui` cookie per-user in cloud instance - `PEREGRINE_VUE_URL` env var bypasses Caddy for local dev - Cloud and demo instances now guard against Vue navigation in demo mode (demo Vue SPA not yet implemented — see #46) --- ### What's next - [ ] Settings tabs in Vue (profile, search prefs, LLM, license) — currently scaffold only - [ ] First-run wizard port to Vue - [ ] Full mobile / gesture polish pass - [ ] Vue SPA demo mode (#46) — pre-seeded read-only data, no auth - [ ] E2E Playwright tests for Vue views - [ ] Promote to default UI for paid tier (currently opt-in banner)
Author
Owner

Merged in v0.8.0 (2026-03-16). Vue 3 SPA is live behind the prgn_ui cookie on paid tier. ResumeOptimizerPanel added in the same branch. Closing.

Merged in v0.8.0 (2026-03-16). Vue 3 SPA is live behind the `prgn_ui` cookie on paid tier. ResumeOptimizerPanel added in the same branch. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/peregrine#8
No description provided.