d95c62bad4
Remove 557-line server-design.md from _go-learning/architecture - content is now covered in updated architecture documentation with real implementation examples and test coverage.
448 lines
32 KiB
Markdown
448 lines
32 KiB
Markdown
# 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: │
|
|
│ └─ <!DOCTYPE html> │
|
|
│ <html lang="es"> │
|
|
│ <head>...</head> │
|
|
│ <body> │
|
|
│ <!-- Full CV content --> │
|
|
│ </body> │
|
|
│ </html> │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ 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=... │ │
|
|
│ │ │ │
|
|
│ │ <div id="main-content"> │ │
|
|
│ │ <!-- Updated CV content with long format --> │ │
|
|
│ │ </div> │ │
|
|
│ └───────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
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
|