refactor: Separate CV domain and UI presentation models into distinct packages
**Main Changes:** 1. **Package Restructuring** - Separated mixed concerns into focused packages: - Created `internal/models/cv/` for CV domain logic (CV, Personal, Experience, etc.) - Created `internal/models/ui/` for UI presentation logic (InfoModal, ShortcutsModal, etc.) - Removed monolithic `internal/models/cv.go` (300+ lines → organized packages) 2. **Testing** - Added comprehensive unit tests: - `internal/models/cv/loader_test.go` - CV data loading and validation - `internal/models/ui/loader_test.go` - UI translations loading - All tests passing ✅ 3. **Documentation** - Added Go learning knowledge base: - `_go-learning/architecture/server-design.md` - Goroutines, graceful shutdown explained - `_go-learning/refactorings/001-cv-model-separation.md` - This refactoring documented - Public documentation showcasing Go expertise (README.md kept private) 4. **Handler Updates** - Updated imports to use new package structure: - `internal/handlers/cv.go` - Uses `cvmodel` and `uimodel` aliases **Benefits:** - ✅ Clear separation of concerns (domain vs presentation) - ✅ Better testability (isolated package testing) - ✅ Improved maintainability (smaller, focused files) - ✅ Scalability (each domain can evolve independently) - ✅ Follows Go best practices (small, cohesive packages) **Other Updates:** - Updated middleware security checks - Template improvements - Organized completed prompts **Testing:** - All Go unit tests pass (cv, ui, handlers) - Server verified with curl tests (English, Spanish, Health endpoints) - Frontend functionality unchanged (refactoring is transparent to UI)
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package cv
|
||||
|
||||
// CV represents the complete curriculum vitae structure
|
||||
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"`
|
||||
Projects []Project `json:"projects"`
|
||||
Awards []Award `json:"awards"`
|
||||
Certifications []Certification `json:"certifications"`
|
||||
Courses []Course `json:"courses"`
|
||||
References []Reference `json:"references"`
|
||||
Other Other `json:"other"`
|
||||
Meta Meta `json:"meta"`
|
||||
}
|
||||
|
||||
type Personal struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
Location string `json:"location"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
DateOfBirth string `json:"dateOfBirth"`
|
||||
PlaceOfBirth string `json:"placeOfBirth"`
|
||||
Citizenship string `json:"citizenship"`
|
||||
LinkedIn string `json:"linkedin"`
|
||||
GitHub string `json:"github"`
|
||||
Domestika string `json:"domestika"`
|
||||
Website string `json:"website"`
|
||||
Photo string `json:"photo"`
|
||||
}
|
||||
|
||||
type Experience struct {
|
||||
Position string `json:"position"`
|
||||
Company string `json:"company"`
|
||||
CompanyURL string `json:"companyURL,omitempty"` // Optional URL for company website
|
||||
CompanyLogo string `json:"companyLogo"`
|
||||
Location string `json:"location"`
|
||||
StartDate string `json:"startDate"`
|
||||
EndDate string `json:"endDate"`
|
||||
Current bool `json:"current"`
|
||||
Expired bool `json:"expired,omitempty"` // Optional flag for expired companies
|
||||
ShortDescription string `json:"shortDescription"`
|
||||
Responsibilities []string `json:"responsibilities"`
|
||||
Technologies []string `json:"technologies"`
|
||||
Highlights []string `json:"highlights"`
|
||||
Duration string `json:"-"` // Calculated field, not from JSON
|
||||
}
|
||||
|
||||
type Education struct {
|
||||
Degree string `json:"degree"`
|
||||
Institution string `json:"institution"`
|
||||
Location string `json:"location"`
|
||||
StartDate string `json:"startDate"`
|
||||
EndDate string `json:"endDate"`
|
||||
Field string `json:"field"`
|
||||
}
|
||||
|
||||
type Skills struct {
|
||||
Technical []SkillCategory `json:"technical"`
|
||||
SoftSkills []string `json:"soft_skills"`
|
||||
}
|
||||
|
||||
type SkillCategory struct {
|
||||
Category string `json:"category"`
|
||||
Proficiency int `json:"proficiency"`
|
||||
Items []string `json:"items"`
|
||||
Sidebar string `json:"sidebar"` // "left" or "right"
|
||||
}
|
||||
|
||||
type Language struct {
|
||||
Language string `json:"language"`
|
||||
Proficiency string `json:"proficiency"`
|
||||
Level int `json:"level"`
|
||||
Detail string `json:"detail,omitempty"` // Optional detail like "Oral (Medio/Alto) Escrito (Alto)"
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
Title string `json:"title"`
|
||||
ProjectName string `json:"projectName,omitempty"` // Optional: linkable part of title
|
||||
ProjectDesc string `json:"projectDesc,omitempty"` // Optional: non-linkable description part
|
||||
URL string `json:"url"`
|
||||
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
|
||||
GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates
|
||||
Location string `json:"location"`
|
||||
StartDate string `json:"startDate,omitempty"` // Optional static start date
|
||||
Current bool `json:"current"`
|
||||
MaintainedBy string `json:"maintainedBy,omitempty"` // Optional maintainer name (e.g., "SAP")
|
||||
Technologies []string `json:"technologies"`
|
||||
ShortDescription string `json:"shortDescription"`
|
||||
Responsibilities []string `json:"responsibilities"`
|
||||
|
||||
// Computed fields (not stored in JSON)
|
||||
ComputedStartDate string `json:"-"` // Dynamically calculated from git repo or system
|
||||
DynamicDate string `json:"-"` // Current date for ongoing projects
|
||||
}
|
||||
|
||||
type Award struct {
|
||||
Title string `json:"title"`
|
||||
Issuer string `json:"issuer"`
|
||||
Date string `json:"date"`
|
||||
Description string `json:"description"`
|
||||
ShortDescription string `json:"shortDescription,omitempty"`
|
||||
Responsibilities []string `json:"responsibilities,omitempty"`
|
||||
AwardLogo string `json:"awardLogo"`
|
||||
}
|
||||
|
||||
type Certification struct {
|
||||
Name string `json:"name"`
|
||||
Issuer string `json:"issuer"`
|
||||
Date string `json:"date"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type Course struct {
|
||||
Title string `json:"title"`
|
||||
Institution string `json:"institution"`
|
||||
CourseLogo string `json:"courseLogo,omitempty"` // Optional logo filename
|
||||
Location string `json:"location"`
|
||||
Date string `json:"date"`
|
||||
Duration string `json:"duration"`
|
||||
Description string `json:"description"`
|
||||
ShortDescription string `json:"shortDescription,omitempty"`
|
||||
Responsibilities []string `json:"responsibilities,omitempty"`
|
||||
}
|
||||
|
||||
type Reference struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"` // "recommendation", "portfolio", "profile", "cv", "presentation"
|
||||
Action string `json:"action,omitempty"` // Optional action like "downloadPDF"
|
||||
TextBefore string `json:"textBefore,omitempty"` // Text before the link
|
||||
LinkText string `json:"linkText,omitempty"` // Bold text inside the link
|
||||
TextAfter string `json:"textAfter,omitempty"` // Text after the link
|
||||
}
|
||||
|
||||
type Other struct {
|
||||
DriverLicense string `json:"driverLicense"`
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
Version string `json:"version"`
|
||||
LastUpdated string `json:"lastUpdated"`
|
||||
Format string `json:"format"`
|
||||
Language string `json:"language"`
|
||||
}
|
||||
Reference in New Issue
Block a user