- Added a comprehensive Table of Contents to AGENTS.md for improved navigation. - Expanded documentation with new backend and frontend guides, detailing architecture, API contracts, and workflows. - Introduced new documents for backend architecture and requirements, outlining system design and API specifications. - Removed outdated Makefile and setup.sh scripts to streamline project setup. - Deleted yarn.lock to eliminate unnecessary dependency management files. - Updated AGENTS.md to reflect changes in documentation structure and links.
15 KiB
Frontend Workflow Documentation
This document outlines the user flow and architecture for the Resume Matcher frontend. The application follows a "Master Resume" centric workflow, allowing users to maintain a base resume and tailor it for specific job descriptions.
Core Workflow
1. Dashboard & Initialization (/dashboard)
The entry point of the application.
- State: Checks
localStoragefor amaster_resume_id. - No Master Resume: Displays an "Initialize Master Resume" card.
- Triggers
ResumeUploadDialog. - On success: Saves
resume_idtolocalStorageand updates UI.
- Triggers
- Master Resume Exists: Displays a "Master Resume" card.
- Action: Clicking the card navigates to the Resume Viewer (
/resumes/[id]).
- Action: Clicking the card navigates to the Resume Viewer (
- Create Tailored Resume: A "+" card opens
/tailor(enabled only when the master resume isready) with label text "Create Resume". - Tailored Resume Tiles: Fetched from
GET /api/v1/resumes/listand rendered as grey cards that open/resumes/[id].- Filtering: Excludes master resume by both
is_masterflag AND localStoragemaster_resume_id(handles sync issues).
- Filtering: Excludes master resume by both
- Auto-Refresh: Dashboard refreshes resume list and master status when window gains focus (handles deletions from viewer).
- Layout: Dashboard grid targets 5 columns at large breakpoints, with filler tiles using neutral greys to balance the canvas.
- Navigation: Settings access lives in the footer as a Swiss-style orange button.
2. Resume Viewer (/resumes/[id])
A read-only hub for a specific resume (either the Master or a Tailored version).
- Data Fetching: Fetches resume details from the backend using the
idfrom the URL. - Processing Status: Shows loading, processing, or failed states with appropriate messaging.
- Display: Uses the
Resumecomponent to render the document at 250mm width with Swiss-style shadow (shadow-[8px_8px_0px_0px_#000000]). - Navigation: Back to Dashboard button in header.
- Actions:
- Edit Resume: Navigates to
/builder?id=[id]. - Download Resume: Requests
GET /api/v1/resumes/{id}/pdffor a headless-Chromium PDF. - Delete Resume: Full delete workflow with confirmation dialogs (see Delete Flow below).
- Edit Resume: Navigates to
3. Tailoring Process (/tailor)
The core AI feature where a Master Resume is optimized for a specific job.
- Input: Large text area for the Job Description (JD).
- Validation: Enforces a minimum character count (e.g., 50 chars) to ensure valid input.
- Process:
- Upload JD: Sends JD to
/api/v1/jobs/upload. - Improve: Calls
/api/v1/resumes/improvewithmaster_resume_idandjob_id.
- Upload JD: Sends JD to
- Output:
- Redirects to the Resume Viewer (
/resumes/[new_id]) for the newly created resume. - The new resume is saved in the backend and can be edited further.
- Redirects to the Resume Viewer (
4. Resume Builder (/builder)
The editor interface for modifying resume content with WYSIWYG paginated preview.
- Navigation: Back to Dashboard button in header with Swiss styling.
- Modes:
- Create/Preview Mode: If accessed via the tailored flow (data passed via
ResumePreviewContext). - Edit Mode: If accessed via URL query param (
?id=xyz). Fetches data from the backend.
- Create/Preview Mode: If accessed via the tailored flow (data passed via
- Template & Formatting Controls (collapsible panel in Editor Panel):
- Template Selection: Visual thumbnail buttons for switching templates.
swiss-single: Traditional single-column layout (default)swiss-two-column: Two-column layout with experience sidebar
- Page Size: Toggle between A4 (210×297mm) and US Letter (8.5×11in).
- Margins: Sliders for top/bottom/left/right (5-25mm range).
- Spacing: Button groups for section spacing, item spacing, line height (1-5 levels).
- Font Size: Button groups for base font size and header scale (1-5 levels).
- All settings apply in real-time to the live preview via CSS custom properties.
- Settings persist to
localStorageunderresume_builder_settings.
- Template Selection: Visual thumbnail buttons for switching templates.
- Components:
- Left Panel:
ResumeFormfor editing fields (Personal Info, Experience, etc.). Scrollable with fixed height.- Header: Blue square indicator (
bg-blue-700) + "EDITOR PANEL" label - Contains:
FormattingControlspanel (template, page size, formatting) +ResumeFormsections
- Header: Blue square indicator (
- Right Panel: WYSIWYG Paginated Preview (
PaginatedPreviewcomponent).- Header: Green square indicator (
bg-green-700) + "LIVE PREVIEW" label - See Paginated Preview System section below for details.
- Header: Green square indicator (
- Left Panel:
- Data Recovery:
- Auto-saves drafts to
localStorageunder keyresume_builder_draft. - Auto-saves template settings to
localStorageunder keyresume_builder_settings. - Warns user before leaving page with unsaved changes.
- Priority loading: API (if ID) → Context (tailor flow) → localStorage → defaults.
- Auto-saves drafts to
- Actions:
- Save: PATCHes the resume to the backend when an
idis present. - Reset: Reverts to the last saved state.
- Download: Requests
GET /api/v1/resumes/{id}/pdfwith all template settings (including page size) as query params.
- Save: PATCHes the resume to the backend when an
- Footer: Shows current template type and page size.
Paginated Preview System
The right panel uses a true WYSIWYG preview that shows exactly what the PDF will look like.
Preview Controls (toolbar at top of preview):
- Zoom: +/- buttons (40% to 150%), shows current zoom percentage
- Margins Toggle: Eye icon to show/hide dashed margin guides (hidden by default)
- Page Count: Shows total number of pages (e.g., "2 pages")
Page Display:
- Each page rendered at exact dimensions (A4: 210×297mm, US Letter: 215.9×279.4mm)
- Pages scaled to fit preview area with auto-zoom
- Swiss-style shadow on each page (
shadow-[6px_6px_0px_0px_#000000]) - Page number indicator: "Page X of Y" (bottom-right of each page)
- Visual "Page Break" separator between pages
Pagination Rules:
- Sections (Experience, Projects, etc.) CAN span multiple pages - this is normal
- Individual items (single job entry, single project) stay together on one page
- Pages must be at least 50% full before moving an item to the next page
- Section titles won't be orphaned at the bottom of a page
Architecture:
components/preview/
├── page-container.tsx # Single page with margin guides
├── paginated-preview.tsx # Main component with controls
├── use-pagination.ts # Page break calculation hook
└── index.ts
lib/constants/
└── page-dimensions.ts # A4/Letter dimensions, mm↔px utilities
5. Settings (/settings)
System configuration and status monitoring page.
System Status Panel
Displays cached health and statistics (see Status Caching below):
- LLM Status: Shows HEALTHY (green) or OFFLINE (red) based on provider connectivity.
- Database Status: Shows CONNECTED when backend is reachable.
- Resumes Count: Total number of resumes stored in the database.
- Jobs Count: Total number of job descriptions stored.
- Improvements Count: Total number of tailored resumes generated.
- Master Resume: Shows CONFIGURED or NOT SET status.
- Last Fetched: Shows when status was last refreshed (e.g., "Just now", "5m ago").
- Refresh Button: Manually refresh system status from backend.
Status Caching
The Settings page uses cached status data to avoid expensive LLM health check API calls:
- No API call on page load: Uses
useStatusCache()hook for cached data. - Initial load: Status fetched once when app starts (via
StatusCacheProvider). - Auto-refresh: Background refresh every 30 minutes.
- Manual refresh: User can click "Refresh" to fetch fresh data.
- Last fetched indicator: Shows relative time since last refresh.
LLM Configuration
Configure the AI provider for resume tailoring:
- Provider Selection: Choose from 6 providers:
- OpenAI (default:
gpt-4o-mini) - Anthropic (default:
claude-3-5-sonnet-20241022) - OpenRouter (default:
anthropic/claude-3.5-sonnet) - Google Gemini (default:
gemini-1.5-flash) - DeepSeek (default:
deepseek-chat) - Ollama (default:
llama3.2, local models)
- OpenAI (default:
- Model Input: Customize the model name for the selected provider.
- API Key: Enter API key (not required for Ollama).
- Ollama Server URL: Configure local Ollama endpoint (shown only for Ollama provider).
Actions
- Save Configuration: Validates config with backend before saving, then refreshes cached status.
- Test Connection: Makes a test LLM call and displays success/failure result.
Status Footer
Displays overall system readiness with Swiss-style visual indicators:
- Ready State: Green square indicator (
bg-green-700) + green text "STATUS: READY" - Setup Required: Amber square indicator (
bg-amber-500) + amber text "STATUS: SETUP REQUIRED" - Checking State: Spinner + "CHECKING..." during refresh
- Offline State: "STATUS: OFFLINE" if no cached status available
- Visual Pattern:
w-3 h-3square + matching colored text withfont-boldemphasis
6. Delete Flow
The complete workflow for deleting a resume (Master or Tailored).
From Resume Viewer
- Trigger: User clicks "Delete Resume" button (red, bottom-right of viewer).
- Confirmation Dialog: Swiss-style danger variant dialog appears.
- Title: "Delete Master Resume" or "Delete Resume" based on type.
- Description: Warns that action cannot be undone.
- Actions: "Keep Resume" (cancel) or "Delete Resume" (confirm with trash icon).
- API Call:
DELETE /api/v1/resumes/{resume_id}viadeleteResume()function. - localStorage Cleanup: If deleting master resume, removes
master_resume_idfrom localStorage. - Success Dialog: Swiss-style success variant dialog confirms deletion.
- Title: "Resume Deleted"
- Single action: "Return to Dashboard"
- Navigation: Redirects to
/dashboard. - Dashboard Refresh: List auto-refreshes on window focus.
From Dashboard (Master Only)
- Trigger: Delete action from dashboard confirmation dialog.
- API Call: Same as above.
- State Update: Clears master state and refreshes tailored resume list.
Error Handling
- If deletion fails, shows error dialog with "OK" button.
- Error message displayed in Swiss-style danger variant.
ConfirmDialog Variants
The ConfirmDialog component (components/ui/confirm-dialog.tsx) supports:
danger: Red styling, trash icon (for delete confirmations)warning: Orange styling, alert iconsuccess: Green styling, checkmark icon (for success confirmations)default: Blue styling, alert iconshowCancelButton: Optional prop to hide cancel button (for info/success dialogs)
Key Components
ResumePreviewProvider: React Context for passing transient state (like AI generation results) between routes.ResumeUploadDialog: Handles file upload to the backend with progress states.Resume: Shared component for rendering the resume layout. Used in Viewer, Builder (Preview), and Dashboard (thumbnail).- Width: Fills parent container (parent sets
max-w-[250mm]) - Padding:
p-10 md:p-16for comfortable spacing - Typography: Serif headers, mono metadata, sans body text
- No internal shadow (parent provides Swiss-style shadow)
- Width: Fills parent container (parent sets
ResumeForm: Form editor with collapsible sections for Personal Info, Experience, Education, Projects, and Additional info.PaginatedPreview: WYSIWYG preview component that shows exact page layout with pagination.- Renders pages at actual dimensions (A4 or US Letter)
- Auto-calculates page breaks based on content
- Zoom controls (40%-150%) and margin guide toggle
- Shows page count and page break indicators
PageContainer: Single page wrapper with margin guides and page number.- Renders at exact page dimensions, scaled for preview
- Optional dashed margin guides (toggleable)
- Clips content to prevent overlap between pages
usePagination: Custom hook for calculating page breaks.- Measures content height using hidden container
- Respects
.resume-itemboundaries (won't split individual entries) - Uses ResizeObserver + MutationObserver for real-time updates
- 150ms debounce for performance
State Management
- Local Storage: Persists the
master_resume_idto maintain the user's setup across sessions. - URL Params: Used to identify specific resumes for viewing (
/resumes/[id]) or editing (/builder?id=...). - Context API: Used for passing immediate results from the AI tailoring process to the Builder/Viewer.
- Status Cache: Global cache for system status with optimistic counter updates (see below).
Status Cache Context (lib/context/status-cache.tsx)
The StatusCacheProvider wraps the app and provides cached system status:
const {
status, // SystemStatus | null
isLoading, // boolean
lastFetched, // Date | null
refreshStatus, // Manual refresh
incrementResumes, // Optimistic counter update
decrementResumes,
incrementJobs,
incrementImprovements,
setHasMasterResume,
} = useStatusCache();
Optimistic Updates: When user actions modify data, counters update instantly:
| Action | Updates |
|---|---|
| Upload master resume | incrementResumes(), setHasMasterResume(true) |
| Delete master resume | decrementResumes(), setHasMasterResume(false) |
| Upload job description | incrementJobs() |
| Generate tailored resume | incrementJobs(), incrementImprovements(), incrementResumes() |
| Delete any resume | decrementResumes() |
API Client (lib/api/)
Centralized Client (lib/api/client.ts)
Single source of truth for API configuration:
API_URL- Base URL from environment or defaultAPI_BASE- Full API path (${API_URL}/api/v1)apiFetch(endpoint, options?)- Base fetch wrapperapiPost(endpoint, body)- POST with JSONapiPatch(endpoint, body)- PATCH with JSONapiPut(endpoint, body)- PUT with JSONapiDelete(endpoint)- DELETE requestgetUploadUrl()- Returns upload endpoint URL
Barrel Export (lib/api/index.ts)
All API functions re-exported for clean imports:
import { fetchResume, API_BASE } from '@/lib/api';
Resume Operations (lib/api/resume.ts)
uploadJobDescriptions(descriptions, resumeId)- Upload job descriptionsimproveResume(resumeId, jobId)- Generate tailored resumefetchResume(resumeId)- Fetch resume by IDfetchResumeList(includeMaster)- List all resumes (optionally include master)updateResume(resumeId, resumeData)- Update resume with structured JSONdownloadResumePdf(resumeId, template)- Download resume as PDFdeleteResume(resumeId)- Delete a resume permanently
Configuration Operations (lib/api/config.ts)
fetchLlmConfig()- Get current LLM configurationupdateLlmConfig(config)- Update LLM provider/model/keyfetchSystemStatus()- Get system health and database statstestLlmConnection()- Test LLM provider connectivityPROVIDER_INFO- Provider metadata (names, defaults, requirements)