Resume Builder Implementation Plan
Goal: Build a resume builder feature into Field Notes — admin-only form for editing resume data stored in MongoDB, with client-side PDF and DOCX download.
Architecture: Single resumes MongoDB collection stores one resume document per user (keyed by user_id, unique). Backend provides CRUD endpoints following existing handler patterns. Frontend provides an admin page with a multi-section form. PDF generation uses @react-pdf/renderer (dynamic import, SSR-disabled). DOCX generation uses docx npm package. No new section/routing integration — standalone admin page.
Tech Stack: FastAPI, MongoDB/motor, Pydantic, React, TypeScript, @react-pdf/renderer, docx, file-saver
Seed Data (Nicholas Hillier)
Contact: Nicholas Hillier, Montreal, nicholas@ghostmonk.com, github.com/ghostmonk Skills: TypeScript, Python, React, Next.js, FastAPI, MongoDB, Go, C#, .NET, Docker, GCP, Tailwind CSS Notable repos: Field-Notes (Next.js/FastAPI CMS), financial-tracker (Tauri v2), dotfiles (Neovim/tmux/WezTerm)
Task 1: Backend — Resume Model
Files:
- Create:
backend/models/resume.py
"""Resume Pydantic models."""
from datetime import datetime, timezone
from typing import List, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator
class ContactInfo(BaseModel):
full_name: str = Field(..., min_length=1, max_length=200)
email: str = Field(..., min_length=1, max_length=200)
phone: Optional[str] = None
location: Optional[str] = None
website: Optional[str] = None
linkedin: Optional[str] = None
github: Optional[str] = None
class WorkExperience(BaseModel):
company: str = Field(..., min_length=1, max_length=200)
title: str = Field(..., min_length=1, max_length=200)
start_date: str = Field(..., min_length=1)
end_date: Optional[str] = None
current: bool = False
description: str = Field(default="", max_length=5000)
technologies: List[str] = Field(default_factory=list)
class Education(BaseModel):
institution: str = Field(..., min_length=1, max_length=200)
degree: str = Field(..., min_length=1, max_length=200)
field_of_study: Optional[str] = None
start_date: str = Field(..., min_length=1)
end_date: Optional[str] = None
description: Optional[str] = Field(default=None, max_length=2000)
class ResumeCreate(BaseModel):
contact: ContactInfo
summary: str = Field(default="", max_length=2000)
work_experience: List[WorkExperience] = Field(default_factory=list)
education: List[Education] = Field(default_factory=list)
skills: List[str] = Field(default_factory=list)
class ResumeUpdate(BaseModel):
contact: Optional[ContactInfo] = None
summary: Optional[str] = Field(default=None, max_length=2000)
work_experience: Optional[List[WorkExperience]] = None
education: Optional[List[Education]] = None
skills: Optional[List[str]] = None
class ResumeResponse(ResumeCreate):
id: str
user_id: str
createdDate: datetime
updatedDate: datetime
@field_validator("createdDate", "updatedDate")
def ensure_utc(cls, value: datetime | None) -> datetime | None:
if value is None:
return None
if value.tzinfo is None:
return value.replace(tzinfo=timezone.utc)
return value.astimezone(timezone.utc)
model_config = ConfigDict(from_attributes=True)Task 2: Backend — Database Collection Helper
Files:
- Modify:
backend/database.py
Add get_resumes_collection function and resume index in ensure_indexes.
Task 3: Backend — Resume Handler (CRUD)
Files:
- Create:
backend/handlers/resume.py
Endpoints:
GET /resume— get current user’s resume (auth required)POST /resume— create resume (auth required, one per user)PUT /resume— update resume (auth required)DELETE /resume— delete resume (auth required)
No slug, no listing. Single resource per user. Rate limited on mutations.
Task 4: Backend — Register Router
Files:
- Modify:
backend/app.py
Import and include resume_router.
Task 5: Backend — Test Fixtures
Files:
- Modify:
backend/tests/conftest.py
Add mock_resumes_collection, override_resumes_database, resumes_async_client, sample_resume_data fixtures.
Task 6: Backend — Resume API Tests
Files:
- Create:
backend/tests/test_resume_api.py
Test all CRUD operations, auth requirements, duplicate prevention.
Task 7: Frontend — Resume Types
Files:
- Modify:
frontend/src/shared/types/api.ts
Add ContactInfo, WorkExperience, Education, Resume, CreateResumeRequest, UpdateResumeRequest interfaces.
Task 8: Frontend — API Client Methods
Files:
- Modify:
frontend/src/shared/lib/api-client.ts
Add resume namespace with get, create, update, delete methods.
Task 9: Frontend — Resume Editor Hook
Files:
- Create:
frontend/src/modules/resume/hooks/useResumeEditor.ts - Create:
frontend/src/modules/resume/hooks/index.ts - Create:
frontend/src/modules/resume/index.ts
Hook manages form state, CRUD operations, loading/error states.
Task 10: Frontend — Resume Form Components
Files:
- Create:
frontend/src/modules/resume/components/ResumeForm.tsx - Create:
frontend/src/modules/resume/components/ContactForm.tsx - Create:
frontend/src/modules/resume/components/WorkExperienceForm.tsx - Create:
frontend/src/modules/resume/components/EducationForm.tsx - Create:
frontend/src/modules/resume/components/SkillsForm.tsx - Create:
frontend/src/modules/resume/components/index.ts
Each sub-form is a controlled component receiving data + onChange callback.
Task 11: Frontend — Admin Resume Page
Files:
- Create:
frontend/src/pages/admin/resume.tsx
Admin-only page that renders the resume form with save/load/download buttons.
Task 12: Frontend — PDF Generator
Files:
- Create:
frontend/src/modules/resume/generators/pdf-generator.tsx
Uses @react-pdf/renderer to produce PDF from resume data. Dynamically imported.
Task 13: Frontend — DOCX Generator
Files:
- Create:
frontend/src/modules/resume/generators/docx-generator.ts
Uses docx + file-saver to produce DOCX from resume data.
Task 14: Frontend — Download Buttons Component
Files:
- Create:
frontend/src/modules/resume/components/DownloadButtons.tsx
Two buttons: Download PDF, Download DOCX. Each triggers client-side generation.
Task 15: Install NPM Dependencies
cd frontend && npm install @react-pdf/renderer docx file-saver && npm install -D @types/file-saverTask 16: Format, Test, Fix
Run make format, make test, make test-frontend-unit, fix any issues.
Task 17: Docs Site Update
Files:
- Create:
docs-site/pages/plans/2026-03-19-resume-builder.md(this file) - Modify:
docs-site/pages/plans/_meta.ts