Skip to main content

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

personalInfo
PersonalInfo
required
Contact information and professional summary.
experience
Experience[]
required
Work experience entries. Empty array if none.
education
Education[]
required
Education history. Empty array if none.
projects
Project[]
required
Project portfolio. Empty array if none.
achievements
Achievement[]
required
Awards and achievements. Empty array if none.
languages
Language[]
required
Language proficiencies. Empty array if none.
skills
Skill[]
required
Technical and professional skills. Empty array if none.
sectionOrder
SectionId[]
required
Order of sections in the CV. 'personal' is always first.
references
string
required
References text (e.g., “Available upon request”).
hiddenSections
SectionId[]
required
Sections hidden from preview and PDF export.
template
TemplateId
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

fullName
string
required
Full name (e.g., “John Doe”).
email
string
required
Email address (e.g., “[email protected]”).
phone
string
required
Phone number (e.g., “+1 234-567-8900”).
address
string
required
Physical address or location (e.g., “San Francisco, CA”).
jobTitle
string
required
Current or desired job title (e.g., “Senior Software Engineer”).
summary
string
required
Professional summary or bio. Can be multi-paragraph.
website
string
Personal website URL.
linkedin
string
LinkedIn profile URL.
github
string
GitHub profile URL.
profileImageUrl
string
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

id
string
required
Unique identifier (UUID).
company
string
required
Company or organization name.
role
string
required
Job title or role.
startDate
string
required
Start date in any format (e.g., “Jan 2020”, “2020-01”).
endDate
string
required
End date. Can be “Present” if current is true.
current
boolean
required
true if currently employed at this position.
description
string
required
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

id
string
required
Unique identifier (UUID).
school
string
required
School, college, or university name.
degree
string
required
Degree or program name (e.g., “B.S. Computer Science”).
startDate
string
required
Start date (e.g., “2016”, “Sep 2016”).
endDate
string
required
Graduation date (e.g., “2020”, “May 2020”).
description
string
required
Additional details (GPA, honors, coursework, etc.).

Project

Project portfolio entry.
interface Project {
  id: string;
  title: string;
  date: string;
  techStack: string;
  description: string;
}

Fields

id
string
required
Unique identifier (UUID).
title
string
required
Project name.
date
string
required
Project date or date range (e.g., “2023”, “Jan - Mar 2023”).
techStack
string
required
Technologies used. Format: “Skill: React, Node.js, PostgreSQL”
description
string
required
Project details and achievements. Supports markdown.

Achievement

Award or achievement entry.
interface Achievement {
  id: string;
  title: string;
  organization: string;
  date: string;
}

Fields

id
string
required
Unique identifier (UUID).
title
string
required
Award or achievement name.
organization
string
required
Issuing organization.
date
string
required
Date received (e.g., “2023”, “June 2023”).

Language

Language proficiency entry.
interface Language {
  id: string;
  name: string;
  proficiency: string;
}

Fields

id
string
required
Unique identifier (UUID).
name
string
required
Language name (e.g., “English”, “Spanish”).
proficiency
string
required
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

id
string
required
Unique identifier (UUID).
name
string
required
Skill name (e.g., “Programming Languages”, “Leadership”).
description
string
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

userId
string
required
User ID (Firebase Auth UID).
createdAt
Date
required
CV creation timestamp.
updatedAt
Date
required
Last update timestamp.
currentVersionId
string
ID of the currently active version.
fullName
string
required
User’s full name from personal info.
jobTitle
string
required
User’s job title from personal info.
versionCount
number
required
Total number of saved versions.
lastVersionDate
Date
Timestamp of most recent version.
sectionCounts
object
required
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'
};

Form Integration

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>
  );
};

Build docs developers (and LLMs) love