d95c62bad4
Remove 557-line server-design.md from _go-learning/architecture - content is now covered in updated architecture documentation with real implementation examples and test coverage.
482 lines
26 KiB
Markdown
482 lines
26 KiB
Markdown
# 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)
|
|
│
|
|
└─ <span class="duration">3 years 2 months</span>
|
|
```
|
|
|
|
## 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
|