2025-11-30 09:29:35 +00:00
# Architectural Decisions
This document records key architectural decisions made for this project.
## Table of Contents
2025-12-06 17:51:20 +00:00
- [ADR-001: No Data Caching ](#adr-001-no-data-caching ) * (Superseded by ADR-004) *
2025-11-30 09:29:35 +00:00
- [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 )
2025-12-06 17:51:20 +00:00
- [ADR-004: Application-Level Data Caching ](#adr-004-application-level-data-caching )
2025-11-30 09:29:35 +00:00
---
## ADR-001: No Data Caching
2025-12-06 17:51:20 +00:00
**Status: ** Superseded by [ADR-004 ](#adr-004-application-level-data-caching )
2025-11-30 09:29:35 +00:00
**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
---
2025-12-06 17:51:20 +00:00
## 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.
---
2025-11-30 09:29:35 +00:00
## 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?
```