# Request Flow Diagram ## Complete HTTP Request Lifecycle ``` ┌─────────────────────────────────────────────────────────────────┐ │ Full Request Lifecycle │ └─────────────────────────────────────────────────────────────────┘ Client Browser │ ├─→ User visits /?lang=es&cv-length=long │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HTTP Request │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ GET /?lang=es&cv-length=long HTTP/1.1 │ │ │ │ Host: localhost:8080 │ │ │ │ Cookie: cv-length=short; cv-icons=show │ │ │ │ Accept: text/html │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Go HTTP Server (net/http) │ │ ├─ Port :8080 │ │ ├─ ServeMux Router │ │ └─ Match route pattern │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ MIDDLEWARE CHAIN (4 layers) │ │ │ │ 1. Recovery Middleware │ │ └─→ Wraps entire request in defer/recover │ │ │ │ 2. Logger Middleware │ │ └─→ Logs: [GET] / 127.0.0.1 │ │ │ │ 3. SecurityHeaders Middleware │ │ └─→ Sets: CSP, X-Frame-Options, etc. │ │ │ │ 4. PreferencesMiddleware │ │ ├─→ Reads cookies │ │ ├─→ Migrates old values │ │ └─→ Stores in request context │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ROUTER (ServeMux) │ │ ├─ Pattern: / │ │ ├─ Match: Home handler │ │ └─ Call: handler.Home(w, r) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HANDLER: CVHandler.Home() │ │ (internal/handlers/cv_pages.go) │ │ │ │ Step 1: Get preferences from context │ │ ├─→ prefs := middleware.GetPreferences(r) │ │ └─→ Result: CVLength="long", CVLanguage="es" │ │ │ │ Step 2: Validate language from query params │ │ ├─→ lang := r.URL.Query().Get("lang") │ │ ├─→ Fallback to: prefs.CVLanguage if empty │ │ └─→ Validate: must be "en" or "es" │ │ │ │ Step 3: Prepare template data │ │ ├─→ Call: h.prepareTemplateData(lang) │ │ └─→ Returns: map with CV, UI, preferences │ │ │ │ Step 4: Render template │ │ ├─→ Call: h.tmpl.Render(w, "index.html", data) │ │ └─→ Returns: HTML response │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ TEMPLATE PREPARATION │ │ (prepareTemplateData helper) │ │ │ │ 1. Load CV data │ │ ├─→ cv, err := cvmodel.LoadCV(lang) │ │ └─→ Read: data/cv-es.json │ │ │ │ 2. Load UI strings │ │ ├─→ ui, err := uimodel.LoadUI(lang) │ │ └─→ Read: data/ui-es.json │ │ │ │ 3. Calculate experience durations │ │ └─→ For each experience: years/months │ │ │ │ 4. Split skills into columns │ │ └─→ Distribute skills evenly across columns │ │ │ │ 5. Build data map │ │ └─→ Return: CV, UI, preferences, SEO metadata │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ TEMPLATE RENDERING │ │ (internal/templates/manager.go) │ │ │ │ 1. Get cached template │ │ ├─→ tmpl := m.templates["index.html"] │ │ └─→ (or reload if hot reload enabled) │ │ │ │ 2. Execute template │ │ ├─→ tmpl.Execute(w, data) │ │ ├─→ Process: {{.CV.Name}}, {{range .CV.Experience}} │ │ └─→ Include partials: header, footer, sections │ │ │ │ 3. Generate HTML │ │ └─→ Full HTML page with data injected │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ RESPONSE GENERATION │ │ │ │ Headers: │ │ ├─ Content-Type: text/html; charset=utf-8 │ │ ├─ Content-Security-Policy: [CSP rules] │ │ ├─ X-Frame-Options: DENY │ │ └─ Set-Cookie: cv-language=es; Path=/; Max-Age=... │ │ │ │ Body: │ │ └─ │ │ │ │ ... │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ LOGGER MIDDLEWARE (completion) │ │ └─→ Log: Completed in 45ms (status: 200) │ └─────────────────────────────────────────────────────────────┘ │ ▼ Client Browser receives HTML ``` ## HTMX Toggle Request Flow ``` ┌─────────────────────────────────────────────────────────────┐ │ HTMX Toggle Request (Partial Update) │ └─────────────────────────────────────────────────────────────┘ User clicks toggle button │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HTMX Request │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ GET /toggle/length?current=short HTTP/1.1 │ │ │ │ HX-Request: true │ │ │ │ HX-Trigger: toggle-length-btn │ │ │ │ HX-Target: #main-content │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ Middleware Chain (same as above) │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ROUTER │ │ ├─ Pattern: /toggle/length │ │ └─ Handler: CVHandler.ToggleCVLength(w, r) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HANDLER: CVHandler.ToggleCVLength() │ │ (internal/handlers/cv_htmx.go) │ │ │ │ 1. Get current preferences │ │ └─→ prefs := middleware.GetPreferences(r) │ │ │ │ 2. Toggle state │ │ ├─→ currentLength := prefs.CVLength │ │ └─→ newLength := "long" if current == "short" │ │ │ │ 3. Save new preference │ │ └─→ middleware.SetPreferenceCookie(w, "cv-length", newLength) │ │ │ │ 4. Get language and prepare data │ │ └─→ data := h.prepareTemplateData(lang) │ │ │ │ 5. Render partial template │ │ └─→ h.tmpl.Render(w, "partials/cv_content.html", data) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ PARTIAL TEMPLATE RENDERING │ │ └─ Only renders: partials/cv_content.html │ │ (Not full page, just the content section) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HTMX Response │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ HTTP/1.1 200 OK │ │ │ │ Content-Type: text/html │ │ │ │ Set-Cookie: cv-length=long; Path=/; Max-Age=... │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ HTMX swaps content in #main-content (No page reload, instant update) ``` ## PDF Export Request Flow ``` ┌─────────────────────────────────────────────────────────────┐ │ PDF Export Request Flow │ └─────────────────────────────────────────────────────────────┘ User clicks "Export PDF" │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HTTP POST Request │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ POST /export/pdf HTTP/1.1 │ │ │ │ Content-Type: application/json │ │ │ │ Origin: http://localhost:8080 │ │ │ │ │ │ │ │ { │ │ │ │ "lang": "es", │ │ │ │ "length": "long", │ │ │ │ "icons": "show", │ │ │ │ "version": "with_skills" │ │ │ │ } │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ Global Middleware Chain │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ROUTE-SPECIFIC MIDDLEWARE │ │ │ │ 1. OriginChecker │ │ └─→ Verify same-origin request │ │ │ │ 2. RateLimiter │ │ └─→ Check: 3 requests/min per IP │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HANDLER: CVHandler.ExportPDF() │ │ (internal/handlers/cv_pdf.go) │ │ │ │ 1. Parse and validate request │ │ ├─→ var req PDFExportRequest │ │ ├─→ json.NewDecoder(r.Body).Decode(&req) │ │ └─→ Validate: lang, length, icons, version │ │ │ │ 2. Render HTML for PDF │ │ ├─→ Build data map with preferences │ │ ├─→ Render to buffer: index.html template │ │ └─→ Result: Full HTML page in memory │ │ │ │ 3. Generate PDF │ │ ├─→ Call: pdf.GeneratePDF(htmlContent, pdfOptions) │ │ └─→ Uses: chromedp to render HTML → PDF │ │ │ │ 4. Send PDF response │ │ ├─→ Set headers: application/pdf │ │ ├─→ Set filename: CV-[Name]-[lang].pdf │ │ └─→ Write: PDF bytes to response │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ PDF GENERATION (chromedp) │ │ (internal/pdf/generator.go) │ │ │ │ 1. Launch headless Chrome │ │ └─→ chromedp.NewContext() │ │ │ │ 2. Navigate to data URL │ │ └─→ Load HTML content │ │ │ │ 3. Wait for rendering │ │ └─→ Ensure fonts, images loaded │ │ │ │ 4. Generate PDF │ │ ├─→ chromedp.PrintToPDF() with options │ │ ├─→ A4 size, margins, print background │ │ └─→ Return: PDF bytes │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ PDF Response │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ HTTP/1.1 200 OK │ │ │ │ Content-Type: application/pdf │ │ │ │ Content-Disposition: attachment; filename="CV-..." │ │ │ │ Content-Length: 245678 │ │ │ │ │ │ │ │ [PDF binary data] │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ Browser triggers download ``` ## Error Handling Flow ``` ┌─────────────────────────────────────────────────────────────┐ │ Error Handling Flow │ └─────────────────────────────────────────────────────────────┘ Request with invalid language │ ▼ Handler validation detects error │ ├─→ Create: InvalidLanguageError("xx") │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ DomainError Created │ │ ├─ Code: INVALID_LANGUAGE │ │ ├─ Message: "Unsupported language: xx (use 'en' or 'es')" │ │ ├─ StatusCode: 400 │ │ └─ Field: "lang" │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Handler.HandleError(w, r, err) │ │ (internal/handlers/errors.go) │ │ │ │ 1. Check if DomainError │ │ └─→ Extract: code, message, status, field │ │ │ │ 2. Log error │ │ └─→ log.Printf("[ERROR] %s: %s", code, message) │ │ │ │ 3. Build error response │ │ ├─→ Create: ErrorInfo struct │ │ └─→ Create: APIResponse wrapper │ │ │ │ 4. Send error response │ │ ├─→ Set status: 400 Bad Request │ │ ├─→ Set content-type: application/json │ │ └─→ Write: JSON error response │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Error Response │ │ { │ │ "success": false, │ │ "error": { │ │ "code": "INVALID_LANGUAGE", │ │ "message": "Unsupported language: xx", │ │ "field": "lang" │ │ } │ │ } │ └─────────────────────────────────────────────────────────────┘ │ ▼ Client receives error ``` ## Performance Metrics ``` Typical Request Timings: ┌─────────────────────────────────────────────────────┐ │ Component Time % │ ├─────────────────────────────────────────────────────┤ │ Middleware overhead ~350 μs 0.7% │ │ ├─ Recovery ~10 ns │ │ ├─ Logger ~100 μs │ │ ├─ SecurityHeaders ~50 ns │ │ └─ Preferences ~200 μs │ │ │ │ Handler processing ~500 μs 1.0% │ │ ├─ Get preferences ~10 μs │ │ ├─ Validate input ~50 μs │ │ └─ Prepare data ~440 μs │ │ │ │ Data loading ~2 ms 4.0% │ │ ├─ Load CV JSON ~1 ms │ │ └─ Load UI JSON ~1 ms │ │ │ │ Template rendering ~45 ms 90% │ │ ├─ Template execution ~40 ms │ │ └─ HTML generation ~5 ms │ │ │ │ Response transmission ~2 ms 4.0% │ ├─────────────────────────────────────────────────────┤ │ TOTAL REQUEST TIME ~50 ms 100% │ └─────────────────────────────────────────────────────┘ PDF Export Timings: ┌─────────────────────────────────────────────────────┐ │ Component Time % │ ├─────────────────────────────────────────────────────┤ │ Middleware + Handler ~1 ms 0.1% │ │ Template rendering ~50 ms 5% │ │ Chrome launch/navigation ~200 ms 20% │ │ PDF generation ~700 ms 70% │ │ Response transmission ~50 ms 5% │ ├─────────────────────────────────────────────────────┤ │ TOTAL PDF EXPORT TIME ~1 sec 100% │ └─────────────────────────────────────────────────────┘ ``` ## Related Diagrams - [System Architecture](./01-system-architecture.md) - Overall system design - [Middleware Chain](./03-middleware-chain.md) - Middleware execution details - [Handler Organization](./04-handler-organization.md) - Handler structure - [Error Handling Flow](./06-error-handling-flow.md) - Error propagation details