Commit Graph

100 Commits

Author SHA1 Message Date
juanatsap 1d0cf46dd3 fix: resolve errcheck warnings in security_test.go
Use t.Setenv for env var management in tests.
2026-03-15 20:22:41 +00:00
juanatsap cafd117437 fix: resolve golangci-lint errcheck and staticcheck warnings
Use t.Setenv in tests, add error return handling, and replace
WriteString(fmt.Sprintf(...)) with fmt.Fprintf.
2026-03-15 20:22:41 +00:00
juanatsap 585949b709 chore: update Matomo analytics URL to matomo.txeo.club
Migrate from matomo.morenorub.io to matomo.txeo.club in both
CSP headers and tracking script. Also fix errcheck lint warnings
in cv_streaming.go.
2026-03-15 20:22:41 +00:00
juanatsap 69012bb1ae test: add comprehensive Go test suite with ~75% coverage
New test files:
- config/config_test.go (100% coverage)
- constants/constants_test.go (100% coverage)
- httputil/response_test.go (100% coverage)
- validation/rules_test.go (91.9% coverage)
- middleware/logger_test.go, security_test.go, security_logger_test.go
- handlers/errors_test.go

Updated documentation:
- doc/27-GO-TESTING.md: Complete testing guide
- doc/00-GO-DOCUMENTATION-INDEX.md: Added testing section
- doc/01-ARCHITECTURE.md: Updated package structure
- doc/DECISIONS.md: Added ADR-004 caching decision
- PROJECT-MEMORY.md: Added Go testing section
2025-12-06 17:51:20 +00:00
juanatsap 6ed6c7780b docs: add CLAUDE.md pointing to key project documentation
Links to PROJECT-MEMORY.md and DECISIONS.md for development rules
and architectural decisions, plus quick commands and doc index.
2025-12-06 17:49:13 +00:00
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
juanatsap 30ed21ff7a refactor: use 'c' alias for constants package
- Update all imports from 'constants' to 'c' for brevity
- Replace all 'constants.' references with 'c.'
- Fix remaining hardcoded content-type headers in httputil
- Fix remaining hardcoded User-Agent and Accept headers
- Rename CSRF receiver from 'c' to 'csrf' to avoid conflict
- Add ContentTypePlainSimple constant for Accept header matching
- Fix JSONCached to use proper integer formatting
2025-12-06 16:31:42 +00:00
juanatsap 2c7f8de242 refactor: centralize constants and reorganize documentation
- Create internal/constants package with all hardcoded values
  (environment, cookies, themes, headers, routes, cache)
- Create internal/httputil package for HTTP helper functions
- Update all handlers and middleware to use centralized constants
- Reorganize documentation with numbered prefixes (00-26)
- Remove duplicate docs from validation folder and docs/
- Delete handlers/constants.go (moved to internal/constants)
2025-12-06 16:27:12 +00:00
juanatsap 71d9258c58 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)
2025-12-06 15:57:23 +00:00
juanatsap d51e1f4520 chore: remove duplicate docs from validation folder
Documentation lives in docs/go-validation-system.md
2025-12-06 15:22:13 +00:00
juanatsap 6c7595b041 feat: add tag-based validation system with reflection caching
Implement a declarative struct tag validation system for Go:

- Add validator.go with sync.Map caching for reflection metadata
- Add rules.go with 11 built-in validation rules (required, email,
  pattern, honeypot, timing, etc.)
- Add errors.go with FieldError and ValidationErrors types
- Update ContactFormRequest with validate tags
- Add ValidateContactFormV2() using the new tag-based validator

Rules implemented:
- required/optional: field presence validation
- trim/sanitize: automatic value transformations
- min/max: UTF-8 aware length validation
- email: RFC 5322 email format validation
- pattern: predefined regex patterns (name, subject, company)
- no_injection: email header injection prevention
- honeypot: bot trap (must be empty)
- timing: timestamp validation for bot detection

Documentation:
- docs/go-validation-system.md: complete validation guide
- docs/go-template-system.md: template manager documentation
- docs/go-routes-api.md: routes and API reference
- docs/README.md: documentation index
2025-12-06 15:20:45 +00:00
juanatsap b5a50ca3ef feat: implement CSS sprite system for image optimization
Reduces HTTP requests from 44+ individual images to 3 sprite sheets
(~93% reduction). Includes Go sprite generator tool, CSS classes,
template integration, and E2E tests.

- Add cmd/sprites/main.go for sprite generation (60x60px + 120x120px @2x)
- Add _sprites.css with responsive sizing and retina support
- Update templates to use sprites with logoIndex fallback
- Add Makefile targets: sprites, sprites-clean
- Add 9-test E2E suite for sprite functionality
- Add doc/22-SPRITES.md with usage documentation
2025-12-04 11:38:36 +00:00
juanatsap bd859c318f docs: update architecture and add contact handler unit tests
Architecture updates:
- Add EmailService documentation with config and flow diagram
- Update CVHandler struct to show all dependencies
- Add new middleware components (BrowserOnly, RateLimiter, etc.)
- Update package structure to include services, pdf, validation

New unit tests for HandleContact (9 tests):
- Valid submission
- Missing email/message validation
- Honeypot bot protection
- Timing-based bot protection (too fast)
- Invalid HTTP method (405)
- Invalid email format
- Message too short
- Spanish language support

Includes MockEmailService for isolated testing.
2025-12-02 14:35:37 +00:00
juanatsap f3842a3486 fix: connect EmailService to contact form handler
The contact form was logging submissions but never actually sending emails.
This commit:
- Adds EmailService field to CVHandler
- Initializes EmailService in main.go with SMTP config
- Calls SendContactForm in HandleContact handler
- Updates all test files to pass nil for emailService parameter
2025-12-02 14:27:03 +00:00
juanatsap fc63151dcd fix: errcheck for client.Close in STARTTLS error path 2025-12-02 14:14:02 +00:00
juanatsap ff74946d2d feat: add Udemy courses and fix footer i18n + golangci-lint errors
- Add 5 Udemy courses with PDF certificate links (Go, Fyne, HTMX)
- Fix cv-footer.html to use CV data instead of hardcoded values
- Add i18n labels for footer (linkedin, github, domestika, email, phone)
- Fix 11 golangci-lint errors:
  - errcheck: proper Close() error handling in email/security/tests
  - staticcheck: simplify return and merge variable declaration
  - unused: remove legacy sendEmail and formatMessage functions
2025-12-02 14:11:36 +00:00
juanatsap 3edeb5274d fix: security tests with mock email sender and rate limit isolation
- Add EmailSender interface to allow mocking in tests
- Add IsInitialized() method to template.Manager for nil-safe checks
- Update contact handler to use interface and safe initialization checks
- Add mockEmailSender in security tests to avoid SMTP connection attempts
- Use unique IPs per test case to avoid rate limiting interference
2025-12-02 13:49:54 +00:00
juanatsap 41dbd77c2f feat: responsive HTML email templates with DreamHost SMTP
- Add professional HTML email template matching CV aesthetic
- Implement multipart emails (HTML + plain text fallback)
- Configure DreamHost SMTP with SSL (port 465)
- Add "light only" color scheme for Gmail iOS compatibility
- Include Reply-To header for easy sender response
- Add email validation and integration tests
- Update .env.example with DreamHost/Gmail SMTP examples
- Add .env to .gitignore to protect credentials
- Document email template customization and dark mode approach
2025-12-02 13:42:36 +00:00
juanatsap 40733034ca feat: comprehensive WCAG 2.1 AA accessibility audit
- Add aria-labels to menu action buttons (PDF, Print, Contact)
- Add aria-labelledby to toggle checkboxes (desktop + mobile)
- Add -webkit-user-select prefix for Safari compatibility
- Add DynamicCacheControl middleware for HTML pages
- Add accessibility test suite (60-accessibility.test.mjs)
- Add comprehensive accessibility documentation (21-ACCESSIBILITY.md)
- Update Modern Web Techniques doc to mark audit complete
2025-12-02 10:46:53 +00:00
juanatsap 2d3d3de8cd feat: lazy load ninja-keys + HTML Invoker Commands API
- Lazy load ninja-keys only on CMD+K press (0 requests on initial load)
- Use esm.sh bundled module (3 requests vs ~81 previously)
- Add esm.sh to CSP whitelist
- Implement HTML Invoker Commands API for modals:
  - commandfor="modal-id" + command="show-modal" for opening
  - commandfor="modal-id" + command="close" for closing
  - Removes need for onclick handlers on modal buttons
- Refactor index.html into layout partials (head, body-scripts)
- Add comprehensive tests for both features
2025-12-02 08:29:54 +00:00
juanatsap c6411db9c8 chore: consolidate contact templates to single location
Remove duplicate contact templates:
- templates/partials/contact_success.html (old, 1.2KB)
- templates/partials/contact_error.html (old, 1.1KB)

The active templates remain in templates/partials/contact/:
- contact-success.html
- contact-error.html

Updated contact.go to use the new template names to match cv_contact.go.
The old templates had inline styles and were larger; the new ones use
external CSS and are more maintainable.

All contact form tests pass (7/7).
2025-12-01 14:18:11 +00:00
juanatsap e0d445b92a refactor: simplify toggle handlers to return 204 No Content
Remove empty toggle templates (length-toggle.html, theme-toggle.html,
logo-toggle.html) that were just placeholders. The frontend uses
hx-swap="none" so the response body was always ignored anyway.

Now the handlers:
- Set the preference cookie
- Return 204 No Content immediately
- Hyperscript handles the UI state toggle on the frontend

This removes unnecessary template rendering overhead and cleans up
dead code. Tests updated to expect 204 instead of 200.
2025-12-01 14:16:24 +00:00
juanatsap 9a848e8c53 feat: Add CMD+K command palette with ninja-keys integration
Implement a command palette accessible via CMD+K/Ctrl+K using the ninja-keys
web component. Features include:

- New /api/cmd-k endpoint serving dynamic CV entries (experiences, projects, courses)
- Language-aware responses with 1-hour cache headers
- Scroll-to-section functionality for quick navigation
- Enhanced keyboard shortcuts modal with CMD+K documentation
- Comprehensive test coverage for API and UI interactions

Also includes cleanup of deprecated debug test files and various UI polish
improvements to contact form, themes, and action bar components.
2025-12-01 13:03:06 +00:00
juanatsap 5f85a7cc8d fix: Handle Unicode/emoji in plain text CV with proper centering
- Fix infinite loop caused by byte-based string slicing on multi-byte chars
- Use rune-based operations for proper Unicode handling
- Add template functions: center, separator, box
- Box function creates rounded corners with dynamic width
- Account for emoji display width (2 chars) in calculations
- Make line width configurable via plainTextLineWidth constant
2025-11-30 17:15:44 +00:00
juanatsap 58c1237326 feat: Add secure contact form with comprehensive security features
- Add contact form dialog with HTMX integration (hx-post)
- Implement browser-only access middleware (blocks curl/Postman/wget)
- Add rate limiting (5 requests/hour per IP) for contact endpoint
- Implement honeypot and timing-based bot detection
- Add input validation (email format, message length 10-5000 chars)
- Create contact button in desktop and mobile navigation (last position)

Security features:
- Browser-only middleware validates User-Agent, Referer/Origin, HX-Request headers
- Honeypot field returns fake success to fool bots while logging spam
- Timing validation rejects forms submitted < 2 seconds
- All security events logged for monitoring

Documentation:
- docs/SECURITY.md - Comprehensive security documentation
- docs/HACK-CHALLENGE.md - "Try to Hack Me!" challenge for security researchers
- docs/SECURITY-AUDIT-REPORT.md - Full security audit report
- docs/CONTACT-FORM-QUICKSTART.md - Integration guide

Form fields: email (required), name, company, subject, message (required)
2025-11-30 14:31:58 +00:00
juanatsap 19951b6f42 feat: Auto-detect text browsers and serve plain text CV
- Detect curl, wget, lynx, w3m, links, elinks, browsh, carbonyl
- Check User-Agent and Accept: text/plain header
- Redirect to /text endpoint automatically
- Document in SEO guide and modern techniques
2025-11-30 14:28:51 +00:00
juanatsap 768fd3ba72 fix: Use 80-char lines with centered section titles 2025-11-30 14:25:28 +00:00
juanatsap 170dba1a5b feat: Add 120-char line wrapping to plain text CV 2025-11-30 14:21:05 +00:00
juanatsap 64cb990860 fix: Improve plain text CV output with dedicated template
- Replace html2text library conversion with dedicated text template
- Create clean, well-formatted cv-text.txt template
- Remove k3a/html2text dependency
- Fix lint warnings in security tests (ineffectual assignments)
- Output now shows only CV content without UI/menu elements
2025-11-30 14:13:34 +00:00
juanatsap f91a24ea9b feat: Add plain text CV endpoint and contact form with security
Plain text endpoint:
- Add /text route for plain text CV (for curl/AI crawlers)
- Use k3a/html2text library for HTML-to-text conversion
- Add Plain Text button to hamburger menu with UI translations

Contact form feature:
- Add ContactHandler with proper email service integration
- Add CSRF protection middleware
- Add rate limiting (5 submissions/hour per IP)
- Add honeypot and timing-based bot protection
- Add input validation with detailed error messages
- Add security logging middleware
- Add browser-only middleware for API protection

Code quality:
- Fix all golangci-lint errcheck warnings for w.Write calls
- Remove duplicate getClientIP functions
- Wire up ContactHandler in routes.Setup
2025-11-30 13:47:49 +00:00
juanatsap 00e28906e6 fix: Resolve CSS bundling in production and lint errors
- Fix golangci-lint errcheck errors by using t.Setenv() instead of os.Setenv()
- Add CSS bundle build step to deploy workflow for production
- Add graceful fallback to modular CSS if bundle doesn't exist
- Remove unused os import from preferences_test.go
2025-11-30 12:38:31 +00:00
juanatsap 95de841e14 feat: Add CSS bundling with Lightning CSS for production optimization
- Add Lightning CSS integration for CSS bundling and minification
- Create Makefile targets: css-dev, css-prod, css-watch, css-clean
- Implement conditional CSS loading based on GO_ENV (dev=modular, prod=bundled)
- Add IsProduction template variable for environment-aware rendering
- Keep print.css separate with media="print" for PDF export
- Add static/dist/ to .gitignore (generated bundles)
- Fix Go template syntax in _cv-header.css
- Remove redundant font @import in _typography.css

Performance gains:
- 27 HTTP requests → 1 (96% reduction)
- 188KB → 86KB CSS (54% reduction)
- ~15KB gzip network transfer

Documentation:
- Update 12-CSS-ARCHITECTURE.md with bundling section
- Add Phase 9 to 2-MODERN-WEB-TECHNIQUES.md
- Add css-bundling.test.mjs Playwright test (8/8 pass)
2025-11-30 12:32:46 +00:00
juanatsap 9636b3659f refactor: Extract all hardcoded content to JSON files
- Move all bilingual text from templates to UI JSON (labels, buttons, modals)
- Move skills summary paragraph to CV JSON with HTML support
- Add new UI sections: navigation, viewControls, sections, footer, portfolio,
  pdfModal, shortcutsModal, infoModal, widgets
- Update Go structs to match expanded JSON structure
- Add template.HTML type for CV.SkillsSummary field
- Add JSON content validation test (70-json-content-validation.test.mjs)

Templates now contain only structural logic (CSS classes, HTML attributes)
while all user-visible text loads from JSON files for proper i18n support.
2025-11-30 10:13:37 +00:00
juanatsap eb92f64e93 fix: Mobile hamburger menu and iPad sidebar visibility
Mobile fixes:
- Add click toggle handler for hamburger menu (was hover-only)
- Menu now opens/closes on tap and closes when clicking outside
- Keep hover support for desktop

iPad fixes:
- Sidebar content now visible on touch devices (901-1280px)
- Added (hover: hover) media query to prevent hide-on-hover on tablets

Security improvements:
- Replace exec.CommandContext with go-git library for git operations
- Add path traversal and command injection prevention
- Fix race condition in template hot reload
- Add environment-based cookie Secure flag

Code quality:
- Add constants.go for magic numbers
- Remove unused code (ParsePreferenceToggleRequest, DomainError)
- Add FOUC prevention with inline critical CSS
- Add Makefile dev/run/clean targets
- Fix README git clone URL
- Add doc/DECISIONS.md for architectural decisions

Tests:
- Add hamburger menu click toggle tests
- Add iPad sidebar visibility tests
- Update security tests for go-git implementation
- Add cookie Secure flag tests
2025-11-30 09:29:35 +00:00
juanatsap 0be8972429 fix: Skip PDF integration tests in CI
PDF generation tests require a running HTTP server for chromedp to connect to.
This is not available in CI environment, causing tests to fail with ERR_CONNECTION_REFUSED.

Changes:
- Added skip condition to TestDefaultCVShortcut when running in short mode
- Updated CI workflow to use -short flag for tests and benchmarks
- Removed Chrome installation from CI (not needed for unit tests)
- Integration tests can still run locally without -short flag
2025-11-25 06:10:26 +00:00
juanatsap 76d80edd7e fix: Remove unused cookie helper functions and fix desktop sidebar visibility
1. Removed unused getPreferenceCookie and setPreferenceCookie functions
   - These were flagged by golangci-lint as unused
   - Cookie preferences now handled client-side via localStorage
   - Removed unused net/http import

2. Fixed desktop sidebar accordion auto-opening
   - Updated handleLandscapeAccordions() to open accordions in desktop view (≥769px)
   - Sidebars now show content in desktop, landscape mobile, and portrait mobile
   - Only keep accordions collapsed in portrait mobile for space saving

3. Created comprehensive multi-viewport test (66-comprehensive-all-viewports-test.mjs)
   - Tests desktop (1278px), portrait mobile (375×667), landscape mobile (667×375)
   - Validates sidebars, accordion state, content visibility, AND all buttons
   - Checks button backdrop visibility in mobile views
   - Every feature now has corresponding test coverage

Fixes golangci-lint errors:
- internal/handlers/cv_helpers.go:366: func getPreferenceCookie is unused
- internal/handlers/cv_helpers.go:375: func setPreferenceCookie is unused
- internal/handlers/cv_helpers.go:7: net/http imported and not used
2025-11-25 06:00:39 +00:00
juanatsap 4528e04bad feat: Complete all remaining Future Improvements (#4-8)
Implemented 5 additional architectural improvements:

1. Response Types (types.go)
   - APIResponse with Success, Data, Error, Meta fields
   - ErrorInfo with Code, Message, Field, Details
   - MetaInfo with Timestamp, Version, RequestID
   - SuccessResponse() and NewErrorResponse() helpers
   - HealthCheckResponse for health endpoint
   - Consistent JSON API responses

2. Validation Tags (types.go)
   - Added struct tags to LanguageRequest
   - Added struct tags to PDFExportRequest
   - Declarative validation rules (oneof, required)
   - Self-documenting validation constraints
   - Ready for go-playground/validator integration

3. Context Helper Functions (middleware/preferences.go)
   - GetLanguage(), GetCVLength(), GetCVIcons(), GetCVTheme(), GetColorTheme()
   - IsLongCV(), IsShortCV() boolean helpers
   - ShowIcons(), HideIcons() boolean helpers
   - IsCleanTheme(), IsDefaultTheme() boolean helpers
   - IsDarkMode(), IsLightMode() boolean helpers
   - 13 new convenience functions for cleaner code

4. Typed Errors (errors.go)
   - ErrorCode constants for all error types
   - DomainError with Code, Message, Err, StatusCode, Field
   - Unwrap() support for error chains
   - WithError() and WithField() fluent builders
   - InvalidLanguageError(), InvalidLengthError(), etc.
   - PDFGenerationError(), MethodNotAllowedError(), RateLimitError()
   - 13 error codes, domain-specific constructors

5. Benchmark Tests
   - handlers/benchmarks_test.go (11 benchmarks)
   - middleware/benchmarks_test.go (12 benchmarks)
   - Sequential benchmarks for handlers, middleware, request parsing
   - Parallel benchmarks for concurrent load testing
   - Response creation benchmarks
   - Helper function benchmarks

Benefits:
- Type Safety: Validation tags and structured types
- Developer Experience: 13 context helpers reduce boilerplate
- Error Handling: Domain-specific errors with codes
- Performance Monitoring: 23 benchmarks for regression detection
- API Consistency: Standardized response formats
- Maintainability: Self-documenting validation and errors

Testing:
- All unit tests pass
- All benchmarks working
- Build succeeds
- No breaking changes
2025-11-20 18:05:45 +00:00
juanatsap ae89d84e07 refactor: Integrate PreferencesMiddleware and update handlers
Complete middleware integration with comprehensive testing:

1. Middleware Integration
   - Added PreferencesMiddleware to middleware chain in routes
   - Order: Recovery → Logger → SecurityHeaders → Preferences → Mux
   - Reads all preference cookies once per request
   - Stores in context for handlers to access

2. Handler Updates
   - cv_pages.go: Home handler uses middleware.GetPreferences()
   - cv_htmx.go: All toggle handlers use middleware preferences
   - Eliminated manual cookie reading in handlers
   - Migration logic handled entirely by middleware

3. Comprehensive Middleware Tests
   - Created preferences_test.go with 10+ test functions
   - Tests: default values, migrations, cookie setting, context access
   - Verified: extended→long, true→show, false→hide migrations
   - All tests passing

Benefits:
- Performance: Cookies read once per request (not multiple times)
- Consistency: All handlers get same preference values
- Maintainability: Migration logic centralized in middleware
- Testability: Easy to mock preferences via context

Testing:
- All unit tests pass (handlers + middleware)
- Build succeeds
- No breaking changes
2025-11-20 17:56:47 +00:00
juanatsap 8a709c6863 improve: Add type safety, middleware, and comprehensive handler tests
Five complementary improvements to handler layer:

1. Fix Pre-Commit Hook
   - Remove broken Perl-style regex (unsupported by Go)
   - Use -short flag to exclude integration tests
   - Tests now run successfully in pre-commit

2. Extract Duplicate Logic
   - Remove 100+ lines of duplicate data preparation
   - Both Home() and CVContent() now use prepareTemplateData()
   - Reduce cv_pages.go from 290 to 120 lines (58% reduction)

3. Request/Response Types
   - Create internal/handlers/types.go with structured types
   - PDFExportRequest, LanguageRequest, PreferenceToggleRequest
   - Type-safe parameter parsing with centralized validation
   - Refactor ExportPDF to use typed requests

4. Middleware Extraction
   - Create internal/middleware/preferences.go
   - PreferencesMiddleware reads cookies once, stores in context
   - Automatic migration of old preference values
   - Ready for integration in routes

5. Handler Tests
   - Add internal/handlers/cv_pages_test.go (190 lines, 15+ cases)
   - Add internal/handlers/cv_htmx_test.go (325 lines, 20+ cases)
   - Test language validation, toggles, cookies, methods
   - Increase handler test coverage significantly

Testing:
- All unit tests pass (35+ new test cases)
- Pre-commit hook working
- Build succeeds
- No breaking changes

Benefits:
- Type safety: Compile-time parameter validation
- Code quality: 170 lines of duplication eliminated
- Testing: 100% increase in test files
- Architecture: Clean middleware pattern
- Developer experience: Self-documenting request types

Documentation:
- Create _go-learning/refactorings/004-handler-improvements.md
- Document all five improvements with examples
- Include metrics, testing strategy, and future improvements
2025-11-20 17:28:23 +00:00
juanatsap 4acde64c01 refactor: Split monolithic handler into focused files
Split internal/handlers/cv.go (1,001 lines) into 5 focused files:

Structure:
- cv.go (29 lines) - CVHandler struct + constructor
- cv_pages.go (290 lines) - Page handlers (Home, CVContent, DefaultCVShortcut)
- cv_pdf.go (153 lines) - PDF export handler (ExportPDF)
- cv_htmx.go (218 lines) - HTMX toggle handlers (Length, Icons, Language, Theme)
- cv_helpers.go (385 lines) - Helper functions (skills, dates, git, templates, cookies)

Benefits:
- Single Responsibility: Each file has one clear purpose
- Improved Discoverability: Easy to find specific functionality
- Reduced Cognitive Load: 200-400 lines per file vs 1,001
- Parallel Development: No conflicts when editing different concerns
- Better Organization: Clear section markers and grouping
- Maintainability: Trade +74 lines (+7.4%) for better organization

Testing:
- All Go tests pass (fileutil, handlers, lang, cv, ui)
- Server builds and runs correctly
- All HTTP endpoints functional
- No breaking changes

Documentation:
- Create _go-learning/refactorings/003-handler-split.md
- Document architecture, benefits, and trade-offs
- Explain WHY single package vs separate packages
2025-11-20 17:01:50 +00:00
juanatsap 29a00f432b improve: Enhance UI appearance and startup logs
UI improvements:
- Remove CV page borders for cleaner look in both themes
- Soften light theme shadow (0.06 opacity, 24px blur)
- Set light theme border color to white for seamless appearance

Server improvements:
- Add descriptive icons to startup logs (📂 🇬🇧 🇪🇸 ⚙️ 📦 📋 🌐 ⏹️)
- Improve visual clarity of server initialization sequence
2025-11-20 16:52:30 +00:00
juanatsap 9240a863d1 refactor: Extract shared utilities and add validation layer
Part 1: Shared Utilities
- Create internal/fileutil package with FindDataFile() and LoadJSON()
- Create internal/lang package with language constants and validation
- Eliminate 46 lines of code duplication between cv/loader.go and ui/loader.go
- Simplify cv/loader.go from 69 to 36 lines (-48%)
- Simplify ui/loader.go from 56 to 24 lines (-57%)

Part 2: Validation Layer
- Add comprehensive validation in internal/models/cv/validation.go
- Validate Personal (name, email format, URLs)
- Validate Experience (required fields, dates)
- Validate Education (required fields)
- Validate Skills (proficiency ranges 1-5, categories)
- Validate Languages (proficiency levels 1-5)
- Validate Projects (title, URLs)
- Validate Meta (version, language)
- Integrate validation into LoadCV() - automatic on load
- Create ValidationError and ValidationErrors types for clear error reporting
- Report all validation errors at once (better UX)

Testing:
- Add comprehensive tests for fileutil package (FindDataFile, LoadJSON)
- Add tests for lang package (IsValid, Validate, All)
- Add 280+ validation test cases covering edge cases
- All tests pass with real CV data (cv-en.json, cv-es.json)
- Fixed validation to allow both URLs and local paths for gitRepoUrl

Documentation:
- Create _go-learning/refactorings/002-shared-utilities-validation.md
- Document architecture, benefits, testing, and interview talking points
- Explain WHY decisions were made (DRY, type safety, data integrity)

Benefits:
- DRY: Single source of truth for utilities
- Type safety: Language constants instead of magic strings
- Data integrity: Validation catches errors at load time
- Better errors: Clear messages showing all issues at once
- Maintainability: Centralized utilities easier to update
2025-11-20 16:41:13 +00:00
juanatsap 7b60fdcf9c 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)
2025-11-20 16:17:56 +00:00
juanatsap 23f63e77fe fix: Update build tag to new Go 1.17+ format
- Change '// +build integration' to '//go:build integration'
- Fixes golangci-lint govet warning about deprecated build tag format
2025-11-20 14:06:01 +00:00
juanatsap 96d34d5f6f test: Mark PDF tests as integration tests (skip in CI)
- Add '// +build integration' tag to exclude from default test runs
- CI runs fast unit tests only (no Chrome dependency)
- Full test suite available with: go test -tags=integration ./...

PDF tests require Chrome browser and are run manually before releases.
2025-11-20 14:00:43 +00:00
juanatsap 32814c4796 fix: Use proper chromedp options for no-sandbox mode
- Replace chromedp.Flag() with chromedp.NoSandbox
- Replace chromedp.Flag() with chromedp.DisableGPU
- Apply fix to both GenerateFromURL and GenerateFromURLWithOptions
- Fixes Ubuntu 23.10+ AppArmor sandbox restrictions

The chromedp.Flag() method wasn't properly disabling the sandbox, causing
Chrome to crash with 'No usable sandbox!' fatal error in CI.
2025-11-20 13:56:29 +00:00
juanatsap d2ee1074fc fix: Add headless Chrome configuration for CI environment
- Configure chromedp with headless mode and CI-friendly flags
- Add --no-sandbox flag (required for Docker/CI environments)
- Add --disable-gpu and --disable-dev-shm-usage for stability
- Use NewExecAllocator with DefaultExecAllocatorOptions

This fixes 'chrome failed to start' errors in GitHub Actions CI where
Chrome needs to run without a display and with relaxed sandbox restrictions.
2025-11-20 13:49:46 +00:00
juanatsap 295a9948f7 fix: PDF tests data file loading and Chrome installation in CI
- Add findDataFile() helper to search up directory tree for data files
- Fixes tests running from subdirectories (internal/handlers)
- Install Chrome in GitHub Actions for PDF generation tests

This resolves test failures that have existed since PDF tests were introduced:
- Error: 'open data/cv-es.json: no such file or directory'
- Error: 'chrome failed to start'

Tests now properly locate data files from any working directory and
have Chrome available for PDF generation in CI environment.
2025-11-20 13:44:31 +00:00
juanatsap 585db9aeb1 fix: Convert if-else chains to switch statements for staticcheck QF1003
- Convert cvIcons migration logic to switch statement (line 103-110)
- Convert currentIcons migration logic to switch statement (line 861-866)
- Resolves golangci-lint staticcheck QF1003 warnings in GitHub Actions
2025-11-20 13:23:32 +00:00
juanatsap 810ee7955b fix: References section link corruption and download filename issues
**Issue 1: URL corruption in "See this CV in..." links**
- Bug: replaceYearPlaceholder used fmt.Sprintf on ALL URLs
- URLs like "/?lang=es" were corrupted to "/?lang=es%!(EXTRA string=2025)"
- Fix: Changed to strings.ReplaceAll("{{YEAR}}", year)
- Result: Only replaces actual {{YEAR}} placeholders, leaves other URLs intact

**Issue 2: Download filename not respected**
- Bug: Shortcut URLs (cv-jamr-2025-en.pdf) redirected with HTTP 301
- Browsers used original URL filename instead of Content-Disposition header
- Fix: Generate PDF directly in DefaultCVShortcut handler
- Result: Returns PDF with correct filename in Content-Disposition header

Files changed:
- internal/models/cv.go: Fixed replaceYearPlaceholder function
- internal/handlers/cv.go: Changed redirect to direct PDF generation

Both fixes verified:
- "See this CV in Spanish" link: href="/?lang=es" ✓
- Download link: filename=cv-jamr-2025-en.pdf ✓
2025-11-20 13:00:06 +00:00