docs/agent/features/custom-sections.md
Dynamic resume sections with full customization.
| 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 |
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) |
getSortedSections which filters by visibility)getAllSections)| File | Purpose |
|---|---|
apps/backend/app/schemas/models.py | SectionType, SectionMeta, CustomSection models |
apps/frontend/lib/utils/section-helpers.ts | Section management utilities |
apps/frontend/components/builder/section-header.tsx | Section controls UI |
apps/frontend/components/builder/add-section-dialog.tsx | Add custom section dialog |
apps/frontend/components/builder/resume-form.tsx | Dynamic form rendering |
apps/frontend/components/resume/dynamic-resume-section.tsx | Renders custom sections in templates |
interface ResumeData {
// ... existing fields (personalInfo, summary, etc.)
sectionMeta?: SectionMeta[]; // Section order, names, visibility
customSections?: Record<string, CustomSection>; // Custom section data
}
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 usescopy.deepcopy(DEFAULT_SECTION_META)to avoid shared mutable reference bugs. Always use deep copies when assigning default mutable values.