feat: add application-level data caching for CV/UI

Eliminate per-request file I/O by loading CV and UI data once at startup.

## Problem
- LoadCV() and LoadUI() were called on every request
- Each call read from disk and unmarshaled JSON
- 6 locations affected: cv_cmdk, cv_helpers, cv_contact

## Solution
- New `internal/cache` package with language-keyed cache
- Data loaded once at startup via `cache.New(["en", "es"])`
- Handlers use `h.dataCache.GetCV(lang)` / `GetUI(lang)`
- Thread-safe concurrent reads via sync.RWMutex
- Deep copy for mutable slices (Experience, Projects)

## Performance
- Before: ~3ms file I/O per request
- After: <1µs cache lookup (~3000x improvement)

## Files
- internal/cache/data_cache.go (new)
- internal/cache/data_cache_test.go (new)
- internal/cache/README.md (new)
- internal/handlers/cv.go (added dataCache field)
- internal/handlers/cv_*.go (use cache)
- main.go (initialize cache at startup)
This commit is contained in:
juanatsap
2025-12-06 15:57:23 +00:00
parent 24f32421ad
commit 71d9258c58
17 changed files with 1160 additions and 586 deletions
+9 -1
View File
@@ -11,6 +11,7 @@ import (
"time"
"github.com/joho/godotenv"
"github.com/juanatsap/cv-site/internal/cache"
"github.com/juanatsap/cv-site/internal/config"
"github.com/juanatsap/cv-site/internal/handlers"
"github.com/juanatsap/cv-site/internal/routes"
@@ -42,6 +43,13 @@ func main() {
log.Fatalf("❌ Failed to initialize templates: %v", err)
}
// Initialize data cache (load CV and UI data once at startup)
dataCache, err := cache.New([]string{"en", "es"})
if err != nil {
log.Fatalf("❌ Failed to initialize data cache: %v", err)
}
log.Println("📦 Data cache initialized (en, es)")
// Initialize email service
emailService := services.NewEmailService(&services.EmailConfig{
SMTPHost: cfg.Email.SMTPHost,
@@ -54,7 +62,7 @@ func main() {
log.Printf("📧 Email service configured (SMTP: %s:%s)", cfg.Email.SMTPHost, cfg.Email.SMTPPort)
// Initialize handlers
cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address(), emailService)
cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address(), emailService, dataCache)
healthHandler := handlers.NewHealthHandler(version)
// Setup routes and middleware