- Introduced JD Match feature documentation detailing how tailored resumes match job descriptions. - Added Resume Template Settings documentation outlining template types and formatting controls. - Created LLM Integration Guide for multi-provider AI support, JSON handling, and prompt guidelines. - Compiled Agent Documentation Index for modular documentation on AI agents working with Resume Matcher. - Developed Maintainer Guide for the resume editor, covering architecture, types, and PDF handling. - Established a Code Review & Technical Debt TODO document to track critical issues and improvements.
16 KiB
Repository Guidelines - GitHub CoPilot Instructions
Table of Contents
(Read from Project Root)
- Documentation
- Project Structure & Module Organization
- Build, Test, and Development Commands
- Coding Style & Naming Conventions
- Testing Guidelines
- Commit & Pull Request Guidelines
- LLM & AI Workflow Notes
- Resume Template Settings
- Content Language Settings
Documentation
(Read from Project Root)
All project documentation is located in the docs/ folder:
| Document | Description |
|---|---|
| backend-guide.md | Backend architecture, modules, and API endpoints |
| frontend-workflow.md | User flow, page routes, and component architecture |
| front-end-apis.md | API contract between frontend and backend |
| style-guide.md | Swiss International Style design system |
| backend-architecture.md | Detailed backend architecture diagrams |
| frontend-architecture.md | Detailed frontend architecture diagrams |
| api-flow-maps.md | API request/response flow diagrams |
| design-system.md | Extended design system documentation |
| template-system.md | Resume template system documentation |
| pdf-template-guide.md | PDF rendering & template editing guide |
| print_pdf_design_spec.md | PDF generation specifications |
| resume_template_design_spec.md | Resume template design specifications |
| i18n-preparation.md | Internationalization preparation notes |
| backend-requirements.md | API contract specifications |
| review-todo.md | Review checklist and TODOs |
Project Structure & Module Organization
Backend (apps/backend/)
A lean FastAPI application with multi-provider AI support. See docs/agent/30-architecture/backend-guide.md for detailed architecture documentation.
app/main.py- FastAPI entry point with CORS and router setupapp/config.py- Pydantic settings loaded from environmentapp/database.py- TinyDB wrapper for JSON storageapp/llm.py- LiteLLM wrapper with JSON mode support, retry logic, and robust JSON extractionapp/routers/- API endpoints (health, config, resumes, jobs)app/services/- Business logic (parser, improver)app/schemas/- Pydantic models matching frontend contractsapp/prompts/- Simplified LLM prompt templates
Frontend (apps/frontend/)
Next.js dashboard with Swiss International Style design. See docs/agent/30-architecture/frontend-workflow.md for user flow and docs/agent/40-apis/front-end-apis.md for API contracts.
app/- Next.js routes (dashboard, builder, tailor, resumes, settings, print)components/- Reusable UI components (includingConfirmDialogwith danger/success variants)lib/- API clients and utilities (lib/api/resume.tsincludes CRUD operations)hooks/- Custom React hooks
Key Features:
- Dashboard auto-refreshes on window focus (handles deletions from other pages)
ConfirmDialogcomponent supportsdanger,warning,success, anddefaultvariants- Delete flow includes confirmation before and success message after deletion
Root Tooling
package.json- Workflow coordination and scripts
Build, Test, and Development Commands
npm run installprovisions the frontend and, viauv, the backend virtual environment.npm run devlaunches FastAPI on:8000and the UI on:3000; usenpm run dev:backendornpm run dev:frontendto focus on a single tier.- Production builds:
npm run buildfor both stacks,npm run build:frontendfor UI-only. - Quality checks:
npm run lintfor the UI,npm run formatto apply Prettier.
Coding Style & Naming Conventions
Frontend (TypeScript/React)
- Design System: All UI changes MUST follow the Swiss International Style in docs/agent/50-design-and-templates/style-guide.md.
- Use
font-seriffor headers,font-monofor metadata,font-sansfor body text. - Color palette:
#F0F0E8(Canvas),#000000(Ink),#1D4ED8(Hyper Blue),#15803D(Signal Green),#F97316(Alert Orange),#DC2626(Alert Red),#4B5563(Steel Grey). - Components:
rounded-nonewith 1px black borders and hard shadows.
- Use
- Use PascalCase for components, camelCase for helpers.
- Tailwind utility classes for styling; run Prettier before committing.
- Textarea Enter Key: All textareas in forms should include
onKeyDownwithe.stopPropagation()for Enter key to ensure newlines work correctly:const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { if (e.key === 'Enter') e.stopPropagation(); };
Backend (Python/FastAPI)
- Python 3.11+, 4-space indents, type hints on all functions.
- Async functions for I/O operations (database, LLM calls).
- Mirror patterns in
app/services/improver.pyfor new services. - Pydantic models for all request/response schemas.
- Prompts go in
app/prompts/templates.py. - Error Handling: Log detailed errors server-side, return generic messages to clients:
except Exception as e: logger.error(f"Operation failed: {e}") raise HTTPException(status_code=500, detail="Operation failed. Please try again.") - Race Conditions: Use
asyncio.Lock()for shared resource initialization (seeapp/pdf.pyfor example). - Mutable Defaults: Always use
copy.deepcopy()when assigning mutable default values to avoid shared state bugs.
Environment Files
- Backend: Copy
apps/backend/.env.exampleto.env - Frontend: Copy to
apps/frontend/.env.local - Only templates (
.example,.env.local.example) belong in Git.
Testing Guidelines
- UI contributions must pass
npm run lint; add Jest or Playwright suites beneathapps/frontend/__tests__/named*.test.tsxas functionality expands. - Backend tests belong in
apps/backend/tests/usingtest_*.pynaming. Execute them withuv run python -m pytestoncepytestis added, and seed anonymised resume/job fixtures.
Commit & Pull Request Guidelines
- History shows concise, sentence-style subjects (e.g.,
Add custom funding link to FUNDING.yml) and GitHub merge commits; keep messages short and, if using prefixes, stick totype: summaryin the imperative. - Reference issues (
Fixes #123) and call out schema or prompt changes in the PR description so reviewers can smoke-test downstream agents. - List local verification commands and attach screenshots for UI or API changes.
LLM & AI Workflow Notes
- Multi-Provider Support: Backend uses LiteLLM to support OpenAI, Anthropic, OpenRouter, Gemini, DeepSeek, and Ollama through a unified API.
- API Key Handling: API keys are passed directly to
litellm.acompletion()via theapi_keyparameter (not viaos.environ) to avoid race conditions in async contexts. - JSON Mode: The
complete_json()function automatically enablesresponse_format={"type": "json_object"}for providers that support it (OpenAI, Anthropic, Gemini, DeepSeek, and major OpenRouter models). - Retry Logic: JSON completions include 2 automatic retries with progressively lower temperature (0.1 → 0.0) to improve reliability.
- JSON Extraction: Robust bracket-matching algorithm in
_extract_json()handles malformed responses, markdown code blocks, and edge cases. Includes infinite recursion protection when content starts with{but matching fails. - Error Handling Pattern: LLM functions log detailed errors server-side but return generic messages to clients to avoid exposing internal details. Example:
except Exception as e: logger.error(f"LLM completion failed: {e}") raise ValueError("LLM completion failed. Please check your API configuration.") - Adding Prompts: Add new prompt templates to
apps/backend/app/prompts/templates.py. Keep prompts simple and direct—avoid complex escaping. - Prompt Guidelines:
- Use
{variable}for substitution (single braces) - Include example JSON schemas for structured outputs
- Keep instructions concise: "Output ONLY the JSON object, no other text"
- Use
- Provider Configuration: Users configure their preferred AI provider via the Settings page (
/settings) orPUT /api/v1/config/llm-api-key. - Health Checks: The
/api/v1/healthendpoint validates LLM connectivity. Note: Docker health checks must use/api/v1/health(not/health). - Timeouts: All LLM calls have configurable timeouts (30s for health checks, 120s for completions, 180s for JSON operations).
Custom Sections System
The application supports dynamic resume sections with full customization.
Section Types
| Type | Description | Example Uses |
|---|---|---|
personalInfo |
Special type for header (always first) | Name, contact details |
text |
Single text block | Summary, objective, statement |
itemList |
Array of items with title, subtitle, years, description | Experience, projects, publications |
stringList |
Simple array of strings | Skills, languages, hobbies |
Section Features
- Rename sections: Change display names (e.g., "Education" → "Academic Background")
- Reorder sections: Up/down buttons to change section order
- Hide sections: Toggle visibility (hidden sections still editable, just not in PDF)
- Delete sections: Remove custom sections entirely
- Add custom sections: Create new sections with any name and type
Section Controls (UI)
Each section (except Personal Info) has these controls in the header:
| Control | Icon | Function |
|---|---|---|
| Visibility | 👁 Eye / EyeOff | Toggle show/hide in PDF preview |
| Move Up | ⬆ ChevronUp | Move section earlier in order |
| Move Down | ⬇ ChevronDown | Move section later in order |
| Rename | ✏️ Pencil | Edit section display name |
| Delete | 🗑 Trash | Hide (default) or delete (custom) |
Hidden Section Behavior
- Hidden sections appear in the form with:
- Dashed border and 60% opacity
- "Hidden from PDF" badge (amber)
- Hidden sections are still editable
- Only PDF/preview hides them (uses
getSortedSectionswhich filters by visibility) - Form shows all sections (uses
getAllSections)
Key Files
| File | Purpose |
|---|---|
apps/backend/app/schemas/models.py |
SectionType, SectionMeta, CustomSection models |
apps/frontend/lib/utils/section-helpers.ts |
Section management utilities (getAllSections, getSortedSections) |
apps/frontend/components/builder/section-header.tsx |
Section controls UI with visibility toggle |
apps/frontend/components/builder/add-section-dialog.tsx |
Add custom section dialog |
apps/frontend/components/builder/resume-form.tsx |
Dynamic form rendering with all sections |
apps/frontend/components/resume/dynamic-resume-section.tsx |
Renders custom sections in templates |
Data Structure
interface ResumeData {
// ... existing fields (personalInfo, summary, etc.)
sectionMeta?: SectionMeta[]; // Section order, names, visibility
customSections?: Record<string, CustomSection>; // Custom section data
}
Migration
Existing resumes are automatically migrated via lazy normalization - default section metadata is added when a resume is fetched if sectionMeta is missing.
Important: The normalize_resume_data() function uses copy.deepcopy(DEFAULT_SECTION_META) to avoid shared mutable reference bugs. Always use deep copies when assigning default mutable values.
Resume Template Settings
The application supports multiple resume templates with extensive formatting controls.
Template Types
| Template | Description |
|---|---|
swiss-single |
Traditional single-column layout with maximum content density |
swiss-two-column |
65%/35% split with experience in main column, skills in sidebar |
Formatting Controls
| Control | Range | Default | Effect |
|---|---|---|---|
| Margins | 5-25mm | 8mm | Page margins |
| Section Spacing | 1-5 | 3 | Gap between major sections |
| Item Spacing | 1-5 | 2 | Gap between items within sections |
| Line Height | 1-5 | 3 | Text line height |
| Base Font Size | 1-5 | 3 | Overall text scale (11-16px) |
| Header Scale | 1-5 | 3 | Name/section header size multiplier |
| Header Font | serif/sans-serif/mono | serif | Font family for headers |
| Body Font | serif/sans-serif/mono | sans-serif | Font family for body text |
| Compact Mode | boolean | false | Apply 0.6x spacing multiplier (spacing only; margins unchanged) |
| Contact Icons | boolean | false | Show icons next to contact info |
Key Files
| File | Purpose |
|---|---|
apps/frontend/lib/types/template-settings.ts |
Type definitions, defaults, CSS variable mapping |
apps/frontend/app/(default)/css/globals.css |
CSS custom properties for resume styling |
apps/frontend/components/builder/formatting-controls.tsx |
UI controls for template settings |
apps/frontend/components/resume/resume-single-column.tsx |
Single column template |
apps/frontend/components/resume/resume-two-column.tsx |
Two column template |
CSS Variables
Templates use CSS custom properties for styling:
--section-gap,--item-gap,--line-height- Spacing--font-size-base,--header-scale,--section-header-scale- Typography--header-font- Header font family--body-font- Body text font family--margin-top/bottom/left/right- Page margins Templates should use theresume-*helper classes inapps/frontend/app/(default)/css/globals.cssto ensure all spacing and typography respond to template settings. Formatting controls include an "Effective Output" summary that reflects compact-mode adjustments for spacing/line-height.
Internationalization (i18n)
The application supports multi-language UI and content generation.
Supported Languages
| Code | Language | Native Name |
|---|---|---|
en |
English | English |
es |
Spanish | Español |
zh |
Chinese (Simplified) | 中文 |
ja |
Japanese | 日本語 |
Two Language Settings
- UI Language - Interface text (buttons, labels, navigation)
- Content Language - LLM-generated content (resumes, cover letters)
Both are configured independently in the Settings page.
How It Works
- UI translations: Simple JSON import approach, no external dependencies
- Content generation: Backend receives language, passes to LLM prompts via
{output_language} - Existing content in database remains in original language
Key Files
| File | Purpose |
|---|---|
apps/frontend/messages/*.json |
UI translation files (en, es, zh, ja) |
apps/frontend/lib/i18n/translations.ts |
useTranslations hook |
apps/frontend/lib/context/language-context.tsx |
LanguageProvider (UI + content) |
apps/backend/app/prompts/templates.py |
LLM prompts with {output_language} |
Using Translations
import { useTranslations } from '@/lib/i18n';
const { t } = useTranslations();
<button>{t('common.save')}</button>
Storage
| Key | Purpose |
|---|---|
resume_matcher_ui_language |
UI language (localStorage only) |
resume_matcher_content_language |
Content language (localStorage + backend) |
Adding a New Language
- Create
apps/frontend/messages/{code}.jsonwith all translations - Add locale to
apps/frontend/i18n/config.ts - Add language name to
apps/backend/app/prompts/templates.py - Update
SUPPORTED_LANGUAGESin backend config router