Vesper — Implementation Plan
> Source of truth for what to build. Every task must be checked off before moving to the next.
Vesper — Implementation Plan
Source of truth for what to build. Every task must be checked off before moving to the next.
Phase 1: Foundation
Goal: Project scaffold, Supabase config, auth flow, basic journal CRUD. Exit Criteria: User can sign up, log in, write entries, view/edit/delete them. Sessions persist. Data scoped via RLS.
1.1 Project Scaffold
- Initialize React 19 + Vite frontend with Tailwind CSS v4
- Files:
frontend/vite.config.js,frontend/src/index.css - Deps:
react,react-dom,tailwindcss,@tailwindcss/vite
- Files:
- Create frontend directory structure (
/src/components,/src/pages,/src/lib,/src/hooks) - Initialize FastAPI backend with modular structure (
/app/api,/app/core,/app/models,/app/services/ai)- Files:
backend/app/main.py,backend/app/core/config.py
- Files:
- Create
requirements.txtwith all backend dependencies- File:
backend/requirements.txt - Deps: fastapi, uvicorn, supabase, langchain, google-generativeai, sentence-transformers, reportlab
- File:
1.2 Supabase Configuration
- Create Supabase project and obtain credentials
- Enable
pgvectorextension via SQL editor (CREATE EXTENSION IF NOT EXISTS vector;) - Create
entriestable with schema from PRD- Schema: id (uuid PK), user_id (uuid FK), content (text), created_at, updated_at, mood_score (float), themes (text[]), distortions (jsonb), observation (text), embedding (vector(384)), analyzed (boolean)
- File:
supabase_init.sql
- Create
reportstable with schema from PRD- Schema: id (uuid PK), user_id (uuid FK), created_at, week_start (date), dominant_emotion (text), top_themes (text[]), emotional_arc (text), ai_observation (text), pdf_url (text)
- File:
supabase_init.sql
- Configure Row Level Security (RLS) policies on both tables
- Policy: Users can only SELECT/INSERT/UPDATE/DELETE their own rows (
auth.uid() = user_id) - File:
supabase_init.sql
- Policy: Users can only SELECT/INSERT/UPDATE/DELETE their own rows (
- Add
updated_atauto-update trigger onentriestable- File:
supabase_init.sql(set_updated_atfunction + trigger)
- File:
- Add pgvector IVFFlat cosine index on
entries.embedding- File:
supabase_init.sql
- File:
- Wire Supabase client in backend (
app/core/supabase.py)- Deps:
supabasePython SDK
- Deps:
1.3 Authentication Flow
- Install
@supabase/supabase-jsandreact-router-domin frontend- File:
frontend/src/lib/supabase.js,frontend/.env.local
- File:
- Build combined Sign Up / Login page with mode toggle
- File:
frontend/src/pages/Auth.jsx
- File:
- Implement sign out functionality
- File:
frontend/src/pages/Dashboard.jsx(Sign Out button)
- File:
- Add session persistence (auto-restore on refresh via
getSession()+onAuthStateChange)- File:
frontend/src/hooks/useAuth.jsx
- File:
- Create auth context/provider to wrap the app
- File:
frontend/src/hooks/useAuth.jsx(AuthProvider+useAuthhook)
- File:
- Add protected route wrapper (redirect to /auth if unauthenticated)
- File:
frontend/src/components/ProtectedRoute.jsx - Deps:
react-router-dom
- File:
1.4 Journal Entry CRUD (Backend)
-
POST /entries— Create new entry- File:
backend/app/api/entries.py
- File:
-
GET /entries— List all entries for current user (newest first) -
GET /entries/{id}— Get single entry with analysis -
GET /entries/{id}/analysis— AI analysis polling stub (Phase 2 will activate) -
PUT /entries/{id}— Update entry content -
DELETE /entries/{id}— Delete entry - Add JWT extraction dependency (Bearer token → RLS passthrough)
- File:
backend/app/core/auth.py
- File:
- Create Pydantic models for entry request/response
- File:
backend/app/models/schemas.py(EntryCreate,EntryUpdate,EntryResponse,DeleteResponse)
- File:
- Register entries router in
main.py
1.5 Journal Editor (Frontend)
- Create authenticated API client
- File:
frontend/src/lib/api.js(Bearer token injection viasupabase.auth.getSession())
- File:
- Implement auto-save with 3-second debounce
- File:
frontend/src/hooks/useAutoSave.js(useDebounce+useAutoSavehooks)
- File:
- Build main editor component — textarea with create-or-update auto-save
- File:
frontend/src/components/JournalEditor.jsx
- File:
- Visual save state indicator: Draft → Saving… → Saved
- Add timestamp display and word count in editor toolbar
- Integrate
JournalEditorinto Dashboard- File:
frontend/src/pages/Dashboard.jsx
- File:
1.6 Entry List / History View
- Build scrollable entry list as sidebar (sorted by date, newest first)
- File:
frontend/src/components/Sidebar.jsx
- File:
- Wire edit action: clicking entry loads content + id into
JournalEditor- Implemented via
onSelectEntrycallback + Reactkeyremount pattern inDashboard.jsx
- Implemented via
- Wire delete action: trash icon with
confirm()→DELETE /entries/{id}→ removes from list - Loading skeleton and empty state in Sidebar
1.7 Basic Dashboard Shell
- Build placeholder dashboard (completed ahead of schedule in Phase 1.3)
- File:
frontend/src/pages/Dashboard.jsx
- File:
- Set up React Router with core routes (
/auth,/dashboard, wildcard)- File:
frontend/src/App.jsx
- File:
- Core routes expansion (
/entries,/editor,/drift,/reports) — added as features are built - Create nav/sidebar component
- File:
frontend/src/components/Sidebar.jsx
- File:
Phase 2: Intelligence
Goal: AI analysis engine, embeddings, insight panel. Exit Criteria: Every saved entry returns structured AI insights (mood, themes, distortions, observation). Embeddings stored.
2.1 LLM Setup — LiteLLM / OpenAI
- Configure LiteLLM proxy integration using
AsyncOpenAISDK- File:
backend/app/services/ai/analyzer.py - Deps:
openai,langchain-openai - Env vars:
LITELLM_API_KEY,LITELLM_BASE_URL,LITELLM_MODEL
- File:
- Create analysis prompt with structured JSON output (System + User messages)
- Output:
{mood_score: float, themes: list[str], distortions: list[str], observation: str} - Uses
response_format={"type": "json_object"}for reliable parsing
- Output:
- Add Pydantic output schema with CBT distortion literals and field validation
- File:
backend/app/services/ai/analyzer.py(AnalysisResultmodel)
- File:
2.2 Async Analysis Pipeline
- Trigger background analysis task after entry save (POST + PUT)
- File:
backend/app/services/ai/pipeline.py+backend/app/api/entries.py - Uses FastAPI
BackgroundTasks— HTTP response sent before analysis runs
- File:
- Update entry row in Supabase with analysis results once complete
- Set
analyzed = trueflag on entry after successful analysis - Handle failures: entry saved even if AI fails; stores "Analysis unavailable" fallback
-
GET /entries/{id}/analysis— Polling endpoint live (returns analyzed flag + fields)- File:
backend/app/api/entries.py
- File:
2.3 Sentence-Transformers Embeddings
- Load
all-MiniLM-L6-v2model lazily, cached in memory after first call- File:
backend/app/services/ai/analyzer.py(embed_text(),_get_embedder())
- File:
- Generate 384-dim vector embedding per entry concurrently with Gemini call
- Store embedding in
embeddingcolumn (pgvector) viaasyncio.gather()
2.4 Insight Panel UI
- Build right-side insight panel component
- File:
frontend/src/components/InsightPanel.jsx
- File:
- Display mood score with visual SVG arc (HSL colour-coded 1-10)
- Display themes as styled violet pill tags
- Display cognitive distortions as amber warning cards
- Display AI observation in italic text
- Show pulsing loading skeleton while analysis is running
- Show "No distortions flagged" emerald state when none detected
- Show "Analysis unavailable" fallback (handled by backend pipeline)
- Poll
/entries/{id}/analysisevery 3s untilanalyzed: true- File:
frontend/src/hooks/useAnalysis.js
- File:
2.5 Semantic Search
- Supabase RPC
match_entries(query_embedding, match_count)— pgvector cosine similarity- File:
match_entries_rpc.sql(run in Supabase SQL Editor) - Uses
SECURITY INVOKERsoauth.uid()scopes results to the caller
- File:
-
POST /entries/searchendpoint — embeds query, calls RPC, returns ranked results- File:
backend/app/api/entries.py
- File:
-
searchEntries(query, limit)API client function- File:
frontend/src/lib/api.js
- File:
- Search input in Sidebar with 500ms debounce
- File:
frontend/src/components/Sidebar.jsx
- File:
- Swap chronological list for semantic results when query is active
- Similarity percentage badge on each search result row
- Clear (×) button to return to normal timeline view
Phase 3: Differentiation
Goal: Drift Timeline, Weekly Reports, PDF export, dashboard completion. Exit Criteria: Timeline renders with theme filtering. Reports work end-to-end with PDF download.
3.1 Drift Timeline Backend
-
GET /drift/themes— all distinct themes across user's entries- File:
backend/app/api/drift.py
- File:
-
GET /drift/timeline?theme=X— mood scores chronologically (optional theme filter)- File:
backend/app/api/drift.py
- File:
-
/drift/search— covered by Phase 2.5'sPOST /entries/search(reused)
3.2 Drift Timeline UI
- Build Drift Timeline page
- File:
frontend/src/pages/DriftTimeline.jsx - Deps:
recharts(installed)
- File:
- Clickable theme pills filter timeline (active pill highlighted in violet)
- Recharts AreaChart with violet gradient fill; colour-coded dots (red/amber/lime/emerald)
- Custom tooltip: date, mood score, observation snippet, theme mini-pills
- Average mood callout in top-right corner
- Empty + loading states with graceful messaging
-
/driftroute added toApp.jsx - Journal / Drift nav toggle added to
Sidebar.jsxbottom nav
3.3 Weekly Report Backend
- LiteLLM chain: ingest last 7 entries → structured report
- Output:
{dominant_emotion, top_themes[], emotional_arc, ai_observation} - File:
backend/app/services/ai/report.py
- Output:
-
POST /reports/generate— synthesise AI report, save to Supabase, return- File:
backend/app/api/reports.py
- File:
-
GET /reports— list all past reports (newest first) -
GET /reports/{id}— get single report
3.4 PDF Export
- ReportLab layout: title, emotion tile, theme bullets, arc paragraph, italic observation box
- File:
backend/app/services/pdf.py
- File:
-
GET /reports/{id}/pdf— runs ReportLab in thread pool, streams asapplication/pdf(triggers download)- File:
backend/app/api/reports.py
- File:
3.5 Weekly Report UI
-
ReportCard— emotion badge, theme pills, arc excerpt, observation, PDF download button- File:
frontend/src/components/ReportCard.jsx
- File:
- Reports page with
Generate New Reportbutton, 2-column card grid, loading skeleton, empty state- File:
frontend/src/pages/Reports.jsx
- File:
-
/reportsroute added toApp.jsx - Reports tab added to Sidebar 3-column nav (Journal / Drift / Reports)
-
downloadReportPdfuses blob URL — triggers native browser download without navigation
3.6 Dashboard Completion
-
GET /dashboard/stats— streak, 7-day sparkline, latest analysis- File:
backend/app/api/dashboard.py
- File:
- Streak counter (flame icon, colour scales by streak length)
- File:
frontend/src/components/StreakCounter.jsx
- File:
- 7-day mood sparkline (recharts, no axes/grid, mini tooltip)
- File:
frontend/src/components/MoodSparkline.jsx
- File:
- Quick access links: New Entry, Drift Timeline, Generate Report
- File:
frontend/src/components/QuickLinks.jsx
- File:
- Dashboard stats bar integrated above editor
- File:
frontend/src/pages/Dashboard.jsx
- File:
- Stats refresh on every entry save (via
refreshTick)
Phase 4: Frontend & Design
Goal: UI polish, v0 components, responsive layout, motion, accessibility. Exit Criteria: App looks production-quality, consistent across pages, no placeholder UI.
4.1 Visual Identity
- Define color palette, typography, motion principles
- File:
frontend/src/index.css(Tailwind theme configuration)
- File:
- Web fonts — Lora (serif) imported via Google Fonts, Inter via system stack
4.2 Component Design
- Design and integrate: auth pages (login/signup + full landing page)
- Design and integrate: journal editor layout with insight panel
- Design and integrate: Drift Timeline page
- Design and integrate: Weekly Report card
- Design and integrate: Dashboard layout
4.3 Responsive Layout
- Ensure all pages work on desktop (primary) and tablet screens
- Sidebar collapses cleanly on smaller viewports (hamburger toggle at ≤900px)
4.4 Motion & Transitions
- Subtle breathing animations on insight cards (
insightPulsekeyframe) - Chart animate-in on Drift Timeline (recharts built-in)
- Smooth page transitions — framer-motion
AnimatePresence
4.5 Empty States & Edge Cases
- Empty state: no entries yet (WelcomeCenter)
- Empty state: no themes detected (Drift)
- Empty state: report not yet generated (Reports page)
- Minimum word count prompt for short entries (<20 words)
4.6 Accessibility
- Keyboard navigation on all interactive elements
- Sufficient color contrast (WCAG AA teal palette)
- Focus states on buttons, links, and form fields (
:focus-visiblerings)
Phase 5: Deployment & QA
Goal: Ship to Vercel + Render, smoke test, README. Exit Criteria: Full app live on production URLs, all features pass smoke testing.
5.1 Frontend Deployment
- Push frontend to GitHub
- Connect repo to Vercel (manual step)
- Configure environment variables — see
frontend/.env.example
5.2 Backend Deployment
- Push backend to GitHub
-
render.yamlcreated (IaC — Render detects automatically) - Environment variables documented — see
backend/.env.example - CORS updated to
FRONTEND_URLenv var (LiteLLM/OpenAI, not Gemini) - Connect repo to Render + set env vars (manual step)
5.3 Environment Configuration
- Separate
.envfor development and production - No API keys committed —
.gitignoreaudited and patched in frontend- File:
.gitignore
- File:
5.4 Smoke Testing
- Smoke test checklist written — File:
SMOKE_TEST.md - Run smoke tests on live production URLs (post-deploy)
5.5 Bug Fixes
- Address any issues found during smoke testing
5.6 README & Documentation
- Comprehensive README written with setup instructions, architecture overview, deployment guide
- File:
README.md
- File:
Related Documents
Building SupportX AI Assist: A Multi-Agent IT Support System
**Published:** February 9, 2026
Go-Attention API Documentation
This document provides a complete reference for all exported APIs in the go-attention library.
Agent Learnings - Papr Memory Python SDK
This document captures important learnings and best practices discovered while building and maintaining the Papr Memory Python SDK, specifically around on-device processing and Core ML integration.
ML Feedback Loop Analysis
> Design document analyzing how user actions feed back into ML predictions,