Files
cv-site/internal/routes/routes.go
T
juanatsap c89b67a06d refactor: consolidate lang into constants, rename services to email
- Merge lang package into constants (add IsValidLang, ValidateLang, AllLangs)
- Rename internal/services to internal/email for consistency with pdf package
- Rename types to avoid redundancy: EmailService→Service, EmailConfig→Config
- Update all imports and references across codebase
- Delete internal/lang directory (functions moved to constants)
2025-12-06 17:05:17 +00:00

72 lines
2.5 KiB
Go

package routes
import (
"net/http"
c "github.com/juanatsap/cv-site/internal/constants"
"github.com/juanatsap/cv-site/internal/handlers"
"github.com/juanatsap/cv-site/internal/middleware"
)
// Setup configures all application routes and middleware
func Setup(cvHandler *handlers.CVHandler, healthHandler *handlers.HealthHandler) http.Handler {
mux := http.NewServeMux()
// Shortcut routes for default CV (year-aware) - MUST be before "/" route
// Pattern: /cv-jamr-{year}-{lang}.pdf (e.g., /cv-jamr-2025-en.pdf)
mux.HandleFunc("/cv-jamr-", cvHandler.DefaultCVShortcut)
// API routes (must be before "/" to avoid catch-all)
mux.HandleFunc("/api/cmd-k", cvHandler.CmdKData) // CMD+K command palette data
// Public routes
mux.HandleFunc("/", cvHandler.Home)
mux.HandleFunc("/cv", cvHandler.CVContent)
mux.HandleFunc("/text", cvHandler.PlainText) // Plain text version for curl/AI
mux.HandleFunc("/health", healthHandler.Check)
// HTMX endpoints for interactive controls
mux.HandleFunc("/switch-language", cvHandler.SwitchLanguage)
mux.HandleFunc("/toggle/length", cvHandler.ToggleLength)
mux.HandleFunc("/toggle/icons", cvHandler.ToggleIcons)
mux.HandleFunc("/toggle/theme", cvHandler.ToggleTheme)
// Contact form endpoint with full security chain:
// BrowserOnly → RateLimiter → Handler
// This blocks curl/Postman, enforces rate limits, then processes the request
contactRateLimiter := middleware.NewRateLimiter(c.RateLimitContactRequests, c.RateLimitContactWindow)
protectedContactHandler := middleware.BrowserOnly(
contactRateLimiter.Middleware(
http.HandlerFunc(cvHandler.HandleContact),
),
)
mux.Handle("/api/contact", protectedContactHandler)
// Protected PDF endpoint with rate limiting (3 requests/minute per IP)
pdfRateLimiter := middleware.NewRateLimiter(c.RateLimitPDFRequests, c.RateLimitPDFWindow)
protectedPDFHandler := middleware.OriginChecker(
pdfRateLimiter.Middleware(
http.HandlerFunc(cvHandler.ExportPDF),
),
)
mux.Handle("/export/pdf", protectedPDFHandler)
// Static files with cache control
staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir(c.DirStatic)))
mux.Handle("/static/", middleware.CacheControl(staticHandler))
// Apply comprehensive middleware chain
// Order: Recovery → Logger → SecurityHeaders → DynamicCacheControl → Preferences → Mux
handler := middleware.Recovery(
middleware.Logger(
middleware.SecurityHeaders(
middleware.DynamicCacheControl(
middleware.PreferencesMiddleware(mux),
),
),
),
)
return handler
}