# Data Models Diagram ## Data Model Overview ``` ┌──────────────────────────────────────────────────────────────┐ │ Data Model Structure │ └──────────────────────────────────────────────────────────────┘ internal/models/ ├── cv/ CV data structures │ ├── cv.go Main CV model │ ├── personal.go Personal information │ ├── experience.go Work experience │ ├── education.go Education history │ ├── skills.go Technical skills │ └── languages.go Language proficiency │ └── ui/ UI text structures ├── ui.go Main UI model ├── sections.go Section titles ├── buttons.go Button labels └── messages.go User messages ``` ## CV Data Model ``` ┌──────────────────────────────────────────────────────────────┐ │ CV Structure (cv/cv.go) │ ├──────────────────────────────────────────────────────────────┤ │ type CV struct { │ │ Personal Personal `json:"personal"` │ │ Summary string `json:"summary"` │ │ Experience []Experience `json:"experience"` │ │ Education []Education `json:"education"` │ │ Skills Skills `json:"skills"` │ │ Languages []Language `json:"languages"` │ │ } │ │ │ │ Methods: │ │ ├─ LoadCV(lang string) (*CV, error) │ │ │ └─→ Read data/cv-{lang}.json │ │ │ │ │ ├─ Validate() error │ │ │ └─→ Ensure all required fields present │ │ │ │ │ └─ CalculateDurations() │ │ └─→ Calculate years/months for experiences │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Personal Information (cv/personal.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Personal struct { │ │ Name string `json:"name"` │ │ Title string `json:"title"` │ │ Email string `json:"email"` │ │ Phone string `json:"phone,omitempty"` │ │ Location string `json:"location"` │ │ Website string `json:"website,omitempty"` │ │ LinkedIn string `json:"linkedin,omitempty"` │ │ GitHub string `json:"github,omitempty"` │ │ Photo string `json:"photo,omitempty"` │ │ } │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Work Experience (cv/experience.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Experience struct { │ │ Company string `json:"company"` │ │ Position string `json:"position"` │ │ Location string `json:"location"` │ │ StartDate string `json:"start_date"` │ │ EndDate string `json:"end_date,omitempty"` │ │ Current bool `json:"current"` │ │ Description string `json:"description"` │ │ Highlights []string `json:"highlights"` │ │ Duration string `json:"-"` // Calculated │ │ } │ │ │ │ Methods: │ │ ├─ CalculateDuration() string │ │ │ ├─ Parse StartDate and EndDate │ │ │ ├─ Calculate difference │ │ │ └─ Return: "2 years 3 months" or "Present" │ │ │ │ │ └─ IsCurrent() bool │ │ └─→ Check if EndDate is empty or Current flag │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Education (cv/education.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Education struct { │ │ Institution string `json:"institution"` │ │ Degree string `json:"degree"` │ │ Field string `json:"field"` │ │ Location string `json:"location"` │ │ StartDate string `json:"start_date"` │ │ EndDate string `json:"end_date,omitempty"` │ │ GPA string `json:"gpa,omitempty"` │ │ Honors []string `json:"honors,omitempty"` │ │ } │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Skills (cv/skills.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Skills struct { │ │ Technical []Skill `json:"technical"` │ │ Soft []Skill `json:"soft"` │ │ Tools []Skill `json:"tools"` │ │ } │ │ │ │ type Skill struct { │ │ Name string `json:"name"` │ │ Level string `json:"level,omitempty"` │ │ Icon string `json:"icon,omitempty"` │ │ Category string `json:"category,omitempty"` │ │ } │ │ │ │ Methods: │ │ └─ SplitIntoColumns(numCols int) [][]Skill │ │ └─→ Distribute skills evenly across columns │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Languages (cv/languages.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Language struct { │ │ Name string `json:"name"` │ │ Level string `json:"level"` │ │ Proficiency string `json:"proficiency,omitempty"` │ │ } │ │ │ │ Levels: Native, Fluent, Professional, Intermediate, Basic │ └──────────────────────────────────────────────────────────────┘ ``` ## UI Data Model ``` ┌──────────────────────────────────────────────────────────────┐ │ UI Structure (ui/ui.go) │ ├──────────────────────────────────────────────────────────────┤ │ type UI struct { │ │ Sections Sections `json:"sections"` │ │ Buttons Buttons `json:"buttons"` │ │ Messages Messages `json:"messages"` │ │ Labels Labels `json:"labels"` │ │ } │ │ │ │ Methods: │ │ └─ LoadUI(lang string) (*UI, error) │ │ └─→ Read data/ui-{lang}.json │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Section Titles (ui/sections.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Sections struct { │ │ Summary string `json:"summary"` │ │ Experience string `json:"experience"` │ │ Education string `json:"education"` │ │ Skills string `json:"skills"` │ │ Languages string `json:"languages"` │ │ Contact string `json:"contact"` │ │ } │ │ │ │ Example (English): │ │ { │ │ "summary": "Professional Summary", │ │ "experience": "Work Experience", │ │ "education": "Education", │ │ "skills": "Technical Skills", │ │ "languages": "Languages", │ │ "contact": "Contact Information" │ │ } │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Button Labels (ui/buttons.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Buttons struct { │ │ ExportPDF string `json:"export_pdf"` │ │ ToggleLength string `json:"toggle_length"` │ │ ToggleIcons string `json:"toggle_icons"` │ │ ToggleTheme string `json:"toggle_theme"` │ │ ToggleLanguage string `json:"toggle_language"` │ │ Print string `json:"print"` │ │ } │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ User Messages (ui/messages.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Messages struct { │ │ Loading string `json:"loading"` │ │ Error string `json:"error"` │ │ Success string `json:"success"` │ │ PDFGenerating string `json:"pdf_generating"` │ │ PDFReady string `json:"pdf_ready"` │ │ } │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ Labels (ui/labels.go) │ ├──────────────────────────────────────────────────────────────┤ │ type Labels struct { │ │ ShortCV string `json:"short_cv"` │ │ LongCV string `json:"long_cv"` │ │ ShowIcons string `json:"show_icons"` │ │ HideIcons string `json:"hide_icons"` │ │ Light string `json:"light"` │ │ Dark string `json:"dark"` │ │ } │ └──────────────────────────────────────────────────────────────┘ ``` ## Data Flow ``` ┌────────────────────────────────────────────────────────────┐ │ Data Flow │ └────────────────────────────────────────────────────────────┘ JSON Files (data/) ├── cv-en.json English CV data ├── cv-es.json Spanish CV data ├── ui-en.json English UI strings └── ui-es.json Spanish UI strings │ ▼ ┌─────────────────────────┐ │ LoadCV(lang) │ │ LoadUI(lang) │ │ (internal/models/) │ └─────────────────────────┘ │ ├─→ Parse JSON ├─→ Validate structure └─→ Return typed structs │ ▼ ┌─────────────────────────┐ │ Handler │ │ (internal/handlers/) │ └─────────────────────────┐ │ ├─→ Calculate durations ├─→ Split skills └─→ Build template data map │ ▼ ┌─────────────────────────┐ │ Template Rendering │ │ (templates/) │ └─────────────────────────┘ │ ▼ HTML Response ``` ## Example Data Structure ``` ┌────────────────────────────────────────────────────────────┐ │ Sample CV Data (data/cv-en.json) │ └────────────────────────────────────────────────────────────┘ { "personal": { "name": "John Doe", "title": "Senior Software Engineer", "email": "john@example.com", "location": "San Francisco, CA", "linkedin": "linkedin.com/in/johndoe", "github": "github.com/johndoe" }, "summary": "Experienced software engineer with 8+ years...", "experience": [ { "company": "Tech Corp", "position": "Senior Software Engineer", "location": "San Francisco, CA", "start_date": "2020-01", "end_date": "", "current": true, "description": "Leading backend development...", "highlights": [ "Designed and implemented microservices architecture", "Reduced API response time by 60%", "Mentored 5 junior developers" ] } ], "education": [ { "institution": "University of California", "degree": "Bachelor of Science", "field": "Computer Science", "location": "Berkeley, CA", "start_date": "2012-09", "end_date": "2016-05", "gpa": "3.8/4.0" } ], "skills": { "technical": [ {"name": "Go", "level": "Expert", "icon": "golang"}, {"name": "JavaScript", "level": "Advanced", "icon": "js"}, {"name": "Python", "level": "Intermediate", "icon": "python"} ], "tools": [ {"name": "Docker", "icon": "docker"}, {"name": "Kubernetes", "icon": "k8s"}, {"name": "Git", "icon": "git"} ] }, "languages": [ {"name": "English", "level": "Native"}, {"name": "Spanish", "level": "Fluent"} ] } ┌────────────────────────────────────────────────────────────┐ │ Sample UI Data (data/ui-en.json) │ └────────────────────────────────────────────────────────────┘ { "sections": { "summary": "Professional Summary", "experience": "Work Experience", "education": "Education", "skills": "Technical Skills", "languages": "Languages" }, "buttons": { "export_pdf": "Export PDF", "toggle_length": "Toggle Length", "toggle_icons": "Toggle Icons", "toggle_theme": "Toggle Theme", "toggle_language": "Switch Language" }, "messages": { "loading": "Loading...", "error": "An error occurred", "pdf_generating": "Generating PDF...", "pdf_ready": "PDF is ready for download" }, "labels": { "short_cv": "Short", "long_cv": "Long", "show_icons": "Show Icons", "hide_icons": "Hide Icons" } } ``` ## Data Validation ``` ┌────────────────────────────────────────────────────────────┐ │ Validation Rules │ └────────────────────────────────────────────────────────────┘ CV Validation: ├─ Personal │ ├─ Name: Required, non-empty │ ├─ Title: Required, non-empty │ ├─ Email: Required, valid email format │ └─ Location: Required, non-empty │ ├─ Experience │ ├─ Company: Required, non-empty │ ├─ Position: Required, non-empty │ ├─ StartDate: Required, valid date (YYYY-MM) │ └─ EndDate: Optional, must be after StartDate if present │ ├─ Education │ ├─ Institution: Required, non-empty │ ├─ Degree: Required, non-empty │ └─ Field: Required, non-empty │ ├─ Skills │ ├─ Name: Required, non-empty │ └─ Level: Optional, one of [Basic, Intermediate, Advanced, Expert] │ └─ Languages ├─ Name: Required, non-empty └─ Level: Required, one of [Native, Fluent, Professional, Intermediate, Basic] UI Validation: ├─ All section titles: Required, non-empty ├─ All button labels: Required, non-empty └─ All messages: Required, non-empty ``` ## Model Lifecycle ``` ┌────────────────────────────────────────────────────────────┐ │ Model Lifecycle │ └────────────────────────────────────────────────────────────┘ Application Start │ └─→ Models NOT loaded (lazy loading) │ ▼ Request Arrives (lang=es) │ ├─→ Handler calls LoadCV("es") │ ├─ Check cache (if caching enabled) │ ├─ Read data/cv-es.json │ ├─ Parse JSON → CV struct │ ├─ Validate struct │ └─ Return *CV │ ├─→ Handler calls LoadUI("es") │ ├─ Read data/ui-es.json │ ├─ Parse JSON → UI struct │ └─ Return *UI │ └─→ Handler processes data ├─ Calculate durations ├─ Split skills └─ Render template Next Request (lang=es) │ └─→ Models reloaded (no persistent cache) (Each request loads fresh data for hot reload) ``` ## Data Transformation ``` ┌────────────────────────────────────────────────────────────┐ │ Data Transformation Pipeline │ └────────────────────────────────────────────────────────────┘ JSON (static) │ ├─ "start_date": "2020-01" └─ "end_date": "" │ ▼ Go Struct (typed) │ ├─ StartDate: "2020-01" ├─ EndDate: "" └─ Duration: "" (empty) │ ▼ Calculate Duration │ ├─ Parse dates ├─ Calculate difference └─ Format: "3 years 2 months" │ ▼ Template Data (enriched) │ ├─ StartDate: "2020-01" ├─ EndDate: "Present" └─ Duration: "3 years 2 months" │ ▼ HTML (rendered) │ └─ 3 years 2 months ``` ## Related Diagrams - [System Architecture](./01-system-architecture.md) - Overall system design - [Request Flow](./02-request-flow.md) - HTTP request lifecycle - [Template Rendering](./07-template-rendering.md) - Template processing