Files
cv-site/doc/DECISIONS.md
T

240 lines
6.5 KiB
Markdown
Raw Normal View History

# Architectural Decisions
This document records key architectural decisions made for this project.
## Table of Contents
- [ADR-001: No Data Caching](#adr-001-no-data-caching) *(Superseded by ADR-004)*
- [ADR-002: Static Dates Instead of Git Integration](#adr-002-static-dates-instead-of-git-integration)
- [ADR-003: CI/CD with GitHub Actions](#adr-003-cicd-with-github-actions)
- [ADR-004: Application-Level Data Caching](#adr-004-application-level-data-caching)
---
## ADR-001: No Data Caching
**Status:** Superseded by [ADR-004](#adr-004-application-level-data-caching)
**Date:** 2025-11-30
### Context
The CV data (JSON files) is loaded from disk on every request. A caching layer could reduce disk I/O and improve response times.
### Decision
**No caching will be implemented for CV data.**
### Rationale
1. **Project Size**: This is a small, personal CV website with minimal traffic
2. **Simplicity**: Caching adds complexity (cache invalidation, memory management, TTL configuration)
3. **Performance is Already Good**: JSON file loading takes <10ms, which is acceptable
4. **Hot Reload**: In development, we want fresh data on every request for testing
5. **YAGNI**: We don't need caching until we have evidence of performance issues
### Consequences
- Simple, maintainable code
- No cache invalidation bugs
- Slightly higher disk I/O (negligible for this scale)
- If traffic increases significantly, this decision can be revisited
---
## ADR-002: Static Dates Instead of Git Integration
**Status:** Accepted
**Date:** 2025-11-30
### Context
Previously, the project had a feature to dynamically fetch project start dates from git repository first commit dates using `exec.CommandContext` to run `git log` commands.
### Decision
**Git command execution has been removed. Use static dates in JSON files instead.**
### Rationale
1. **Security Risk**: Executing shell commands (even with path validation) poses injection risks
2. **Symlink Bypass**: Path validation can be bypassed with symbolic links
3. **Unnecessary Complexity**: Static dates in JSON are simpler and more maintainable
4. **Control**: Static dates give full control over what's displayed
5. **Performance**: No external process spawning
### Implementation
Instead of `gitRepoUrl` in project data, use `startDate` directly:
```json
{
"title": "My Project",
"startDate": "2024-06",
"current": true
}
```
### Consequences
- More secure codebase
- Simpler implementation
- Manual date updates required when adding new projects
- No external dependencies on git binary
---
## ADR-003: CI/CD with GitHub Actions
**Status:** Implemented
**Date:** 2025-11-30
### Context
The project needs automated testing, linting, and deployment.
### Decision
**GitHub Actions is used for CI/CD with two workflows:**
1. **test.yml** - Runs on PRs and pushes to main/develop
2. **deploy.yml** - Deploys to production on push to main
### Workflows
#### Test Workflow (`.github/workflows/test.yml`)
Triggers: `push` and `pull_request` to `main` and `develop` branches
Steps:
1. Checkout code
2. Setup Go 1.25.1
3. Install and verify dependencies
4. Run golangci-lint
5. Run unit tests with coverage
6. Generate coverage report
7. Check coverage threshold (target: 70%)
8. Upload coverage to Codecov
9. Run benchmarks
10. Build binary
11. Upload artifacts
#### Deploy Workflow (`.github/workflows/deploy.yml`)
Triggers: `push` to `main` branch or manual dispatch
Steps:
1. SSH into production server
2. Fix repository permissions
3. Stash any local changes
4. Pull latest changes
5. Restart systemd service
6. Verify health check
### Required Secrets
- `SSH_PRIVATE_KEY` - SSH private key for server access
- `SSH_HOST` - Server IP or domain
- `SSH_USER` - SSH username
- `SSH_PORT` (optional, default: 22)
- `SERVICE_NAME` (optional, default: cv)
- `REPO_PATH` (optional, default: /home/txeo/Git/yo/cv)
### Consequences
- Automated quality checks on every PR
- Consistent deployment process
- Health check verification after deployment
- Coverage tracking with Codecov
- Binary artifacts available for download
---
## ADR-004: Application-Level Data Caching
**Status:** Accepted
**Date:** 2025-12-06
**Supersedes:** [ADR-001](#adr-001-no-data-caching)
### Context
As the CV site evolved to support multiple languages and increased usage, the original decision (ADR-001) to avoid caching was reconsidered. While the site traffic remains modest, the benefits of eliminating per-request file I/O became clear:
1. **Consistency**: Every request reads the same data
2. **Performance**: Eliminates disk I/O from hot paths
3. **Reliability**: Fail-fast at startup catches data errors early
4. **Simplicity**: No cache invalidation needed (data is static)
### Decision
**Implement application-level data caching with startup-time loading.**
The `internal/cache` package provides:
- `DataCache` struct holding CV and UI data for all supported languages
- Single load at application startup
- Thread-safe read access via `sync.RWMutex`
- Language-keyed retrieval (`GetCV(lang)`, `GetUI(lang)`)
### Implementation
```go
// At startup (main.go)
dataCache, err := cache.New([]string{"en", "es"})
if err != nil {
log.Fatalf("Failed to initialize data cache: %v", err)
}
// In handlers
cv := h.dataCache.GetCV(lang)
ui := h.dataCache.GetUI(lang)
```
### Rationale
1. **Zero Per-Request I/O**: Data loaded once, served from memory
2. **Fail-Fast**: All data issues caught at startup, not runtime
3. **Thread-Safe**: `sync.RWMutex` optimized for read-heavy workloads
4. **Minimal Complexity**: Simple map-based storage, no TTL/invalidation
5. **Testable**: 95.7% test coverage, including concurrency tests
### Consequences
- **Positive:**
- Faster request handling (no disk I/O)
- Earlier error detection (startup validation)
- Consistent data across requests
- Simple, well-tested implementation
- **Considerations:**
- Requires application restart to pick up data changes
- Memory usage increases slightly (minimal - ~KB per language)
- Deep copies required when handlers mutate data
### Documentation
See [23-DATA-CACHE.md](23-DATA-CACHE.md) for complete API reference and usage patterns.
---
## How to Add New Decisions
When making significant architectural decisions, add a new section following this template:
```markdown
## ADR-XXX: Title
**Status:** Proposed | Accepted | Deprecated | Superseded
**Date:** YYYY-MM-DD
### Context
What is the issue that we're seeing that is motivating this decision?
### Decision
What is the change that we're proposing?
### Rationale
Why is this the best choice?
### Consequences
What are the results of this decision?
```