Overview
Core TypeScript interfaces for CV Builder data structure, including personal information, experience, education, projects, and section configuration.
CVData
Main CV data structure containing all sections and configuration.
interface CVData {
personalInfo: PersonalInfo;
experience: Experience[];
education: Education[];
projects: Project[];
achievements: Achievement[];
languages: Language[];
skills: Skill[];
sectionOrder: SectionId[];
references: string;
hiddenSections: SectionId[];
template?: TemplateId;
}
Fields
Contact information and professional summary.
Work experience entries. Empty array if none.
Education history. Empty array if none.
Project portfolio. Empty array if none.
Awards and achievements. Empty array if none.
Language proficiencies. Empty array if none.
Technical and professional skills. Empty array if none.
Order of sections in the CV. 'personal' is always first.
References text (e.g., “Available upon request”).
Sections hidden from preview and PDF export.
Selected CV template. Defaults to 'default'.Options: 'default' | 'rhyhorn' | 'nexus'
Initial Value
const initialCVData: CVData = {
personalInfo: {
fullName: "",
email: "",
phone: "",
address: "",
jobTitle: "",
summary: "",
linkedin: "",
github: "",
website: "",
profileImageUrl: "",
},
experience: [],
education: [],
projects: [],
achievements: [],
languages: [],
skills: [],
sectionOrder: [
"personal",
"skills",
"experience",
"education",
"projects",
"achievements",
"languages",
"references",
],
references: "Available upon request.",
hiddenSections: [],
template: 'default',
};
PersonalInfo
Contact information and professional details.
interface PersonalInfo {
fullName: string;
email: string;
phone: string;
address: string;
jobTitle: string;
summary: string;
website?: string;
linkedin?: string;
github?: string;
profileImageUrl?: string;
}
Fields
Full name (e.g., “John Doe”).
Phone number (e.g., “+1 234-567-8900”).
Physical address or location (e.g., “San Francisco, CA”).
Current or desired job title (e.g., “Senior Software Engineer”).
Professional summary or bio. Can be multi-paragraph.
Profile photo URL (stored in Firebase Storage).
Experience
Work experience entry.
interface Experience {
id: string;
company: string;
role: string;
startDate: string;
endDate: string;
current: boolean;
description: string;
}
Fields
Unique identifier (UUID).
Company or organization name.
Start date in any format (e.g., “Jan 2020”, “2020-01”).
End date. Can be “Present” if current is true.
true if currently employed at this position.
Job responsibilities and achievements. Supports markdown.
Education
Education history entry.
interface Education {
id: string;
school: string;
degree: string;
startDate: string;
endDate: string;
description: string;
}
Fields
Unique identifier (UUID).
School, college, or university name.
Degree or program name (e.g., “B.S. Computer Science”).
Start date (e.g., “2016”, “Sep 2016”).
Graduation date (e.g., “2020”, “May 2020”).
Additional details (GPA, honors, coursework, etc.).
Project
Project portfolio entry.
interface Project {
id: string;
title: string;
date: string;
techStack: string;
description: string;
}
Fields
Unique identifier (UUID).
Project date or date range (e.g., “2023”, “Jan - Mar 2023”).
Technologies used. Format: “Skill: React, Node.js, PostgreSQL”
Project details and achievements. Supports markdown.
Achievement
Award or achievement entry.
interface Achievement {
id: string;
title: string;
organization: string;
date: string;
}
Fields
Unique identifier (UUID).
Award or achievement name.
Date received (e.g., “2023”, “June 2023”).
Language
Language proficiency entry.
interface Language {
id: string;
name: string;
proficiency: string;
}
Fields
Unique identifier (UUID).
Language name (e.g., “English”, “Spanish”).
Proficiency level (e.g., “Native”, “Fluent”, “Intermediate”, “Basic”).
Skill
Skill entry (technical or professional).
interface Skill {
id: string;
name: string;
description?: string;
category?: 'technical' | 'professional';
}
Fields
Unique identifier (UUID).
Skill name (e.g., “Programming Languages”, “Leadership”).
Skill details or comma-separated values (e.g., “C, C++, Java, Python”).
category
'technical' | 'professional'
Skill category for grouping.
SectionId
CV section identifier.
type SectionId =
| "personal"
| "experience"
| "education"
| "projects"
| "achievements"
| "languages"
| "skills"
| "references";
Default Order
const defaultSectionOrder: SectionId[] = [
"personal",
"skills",
"experience",
"education",
"projects",
"achievements",
"languages",
"references",
];
TemplateId
CV template identifier.
type TemplateId = 'default' | 'rhyhorn' | 'nexus';
Templates
'default' - Standard professional template
'rhyhorn' - Modern two-column layout
'nexus' - Minimalist single-column design
ResumeListItem
Resume metadata for list views.
interface ResumeListItem {
userId: string;
createdAt: Date;
updatedAt: Date;
currentVersionId?: string;
fullName: string;
jobTitle: string;
versionCount: number;
lastVersionDate?: Date;
sectionCounts: {
experience: number;
education: number;
projects: number;
skills: number;
languages: number;
achievements: number;
};
}
Fields
User ID (Firebase Auth UID).
ID of the currently active version.
User’s full name from personal info.
User’s job title from personal info.
Total number of saved versions.
Timestamp of most recent version.
Item counts for each section array.
Utility Functions
normalizeSectionOrder
Normalize and validate section order array.
function normalizeSectionOrder(order?: SectionId[]): SectionId[]
Behavior:
- Removes duplicates
- Filters invalid section IDs
- Adds missing sections at the end
- Ensures
'personal' is always first
Example:
const order = normalizeSectionOrder(['experience', 'personal', 'education']);
// Returns: ['personal', 'experience', 'education', 'projects', ...]
isSectionHidden
Check if a section is hidden.
function isSectionHidden(
sectionId: SectionId,
hiddenSections?: SectionId[]
): boolean
Example:
const isHidden = isSectionHidden('references', cvData.hiddenSections);
if (!isHidden) {
// Render section
}
getVisibleSections
Get list of visible sections.
function getVisibleSections(
sectionOrder: SectionId[],
hiddenSections?: SectionId[]
): SectionId[]
Example:
const visible = getVisibleSections(
cvData.sectionOrder,
cvData.hiddenSections
);
visible.forEach(sectionId => {
// Render visible sections only
});
Usage Examples
Creating CV Data
import { CVData, initialCVData, PersonalInfo } from '@/lib/types';
const newCV: CVData = {
...initialCVData,
personalInfo: {
fullName: 'John Doe',
email: '[email protected]',
phone: '+1 234-567-8900',
address: 'San Francisco, CA',
jobTitle: 'Senior Software Engineer',
summary: 'Experienced developer with 8+ years...',
},
experience: [
{
id: crypto.randomUUID(),
company: 'Tech Corp',
role: 'Senior Engineer',
startDate: 'Jan 2020',
endDate: 'Present',
current: true,
description: 'Led team of 5 developers...'
}
],
template: 'rhyhorn'
};
import { useForm } from 'react-hook-form';
import { CVData, initialCVData } from '@/lib/types';
const CVForm = () => {
const form = useForm<CVData>({
defaultValues: initialCVData
});
const onSubmit = (data: CVData) => {
console.log('CV Data:', data);
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
<input {...form.register('personalInfo.fullName')} />
<input {...form.register('personalInfo.email')} />
{/* ... other fields */}
</form>
);
};
Section Rendering
const CVPreview = ({ data }: { data: CVData }) => {
const visibleSections = getVisibleSections(
data.sectionOrder,
data.hiddenSections
);
return (
<div>
{visibleSections.map(sectionId => {
switch (sectionId) {
case 'personal':
return <PersonalInfoSection data={data.personalInfo} />;
case 'experience':
return <ExperienceSection items={data.experience} />;
case 'education':
return <EducationSection items={data.education} />;
// ... other sections
default:
return null;
}
})}
</div>
);
};