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.
This commit is contained in:
juanatsap
2025-12-02 14:35:37 +00:00
parent f3842a3486
commit bd859c318f
2 changed files with 388 additions and 6 deletions
+68 -6
View File
@@ -19,9 +19,12 @@ cv/
└── internal/ # Private packages (cannot be imported by other projects)
├── config/ # Configuration management
├── handlers/ # HTTP request handlers
├── middleware/ # HTTP middleware
├── middleware/ # HTTP middleware (security, logging, rate limiting)
├── models/ # Data models and business logic
── templates/ # Template management
── pdf/ # PDF generation service
├── services/ # Business services (email, etc.)
├── templates/ # Template management
└── validation/ # Input validation utilities
```
**Benefits**:
@@ -37,11 +40,15 @@ Handlers and services receive their dependencies through constructors:
```go
// ✅ Good: Dependencies injected
type CVHandler struct {
templates *templates.Manager
templates *templates.Manager
emailService *services.EmailService
}
func NewCVHandler(tmpl *templates.Manager) *CVHandler {
return &CVHandler{templates: tmpl}
func NewCVHandler(tmpl *templates.Manager, addr string, email *services.EmailService) *CVHandler {
return &CVHandler{
templates: tmpl,
emailService: email, // Can be nil for graceful degradation
}
}
// ❌ Bad: Global state
@@ -146,11 +153,15 @@ manager.Render("index.html") // Hot-reloads in dev mode
```go
type CVHandler struct {
templates *templates.Manager
templates *templates.Manager
pdfGenerator *pdf.Generator
emailService *services.EmailService
serverAddr string
}
func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request)
func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request)
func (h *CVHandler) HandleContact(w http.ResponseWriter, r *http.Request)
```
**Features**:
@@ -159,12 +170,63 @@ func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request)
- Consistent error handling
- HTMX-aware responses
### Email Service (`internal/services`)
**Pattern**: Service layer with dependency injection and interface-based design
```go
type EmailService struct {
config *EmailConfig
}
type EmailConfig struct {
SMTPHost string
SMTPPort string
SMTPUser string
SMTPPassword string
FromEmail string
ToEmail string
}
func NewEmailService(config *EmailConfig) *EmailService
func (e *EmailService) SendContactForm(data *ContactFormData) error
```
**Features**:
- TLS support (port 465 implicit SSL, port 587 STARTTLS)
- Multipart email formatting (HTML + plain text)
- Input validation with header injection prevention
- Reply-To header support for easy responses
- Graceful degradation (nil service skips email sending)
**Email Flow**:
```
Contact Form → HandleContact → EmailService.SendContactForm
Validation → Build HTML/Text Body → Connect SMTP → Send
```
**Configuration** (via environment variables):
```bash
SMTP_HOST=smtp.dreamhost.com
SMTP_PORT=465
SMTP_USER=info@example.com
SMTP_PASSWORD=secret
SMTP_FROM_EMAIL=info@example.com
CONTACT_EMAIL=recipient@example.com
```
### Middleware (`internal/middleware`)
**Components**:
1. **Recovery**: Catches panics, logs stack traces
2. **Logger**: Structured request/response logging
3. **SecurityHeaders**: CSP, XSS protection, clickjacking prevention
4. **BrowserOnly**: Blocks non-browser requests (curl, wget, bots) for sensitive endpoints
5. **RateLimiter**: Per-IP rate limiting with configurable limits and time windows
6. **OriginChecker**: Validates request origin for CSRF protection
7. **CacheControl**: Dynamic cache headers based on content type
8. **PreferencesMiddleware**: Cookie-based user preference handling
## Security Features