eb92f64e93
Mobile fixes: - Add click toggle handler for hamburger menu (was hover-only) - Menu now opens/closes on tap and closes when clicking outside - Keep hover support for desktop iPad fixes: - Sidebar content now visible on touch devices (901-1280px) - Added (hover: hover) media query to prevent hide-on-hover on tablets Security improvements: - Replace exec.CommandContext with go-git library for git operations - Add path traversal and command injection prevention - Fix race condition in template hot reload - Add environment-based cookie Secure flag Code quality: - Add constants.go for magic numbers - Remove unused code (ParsePreferenceToggleRequest, DomainError) - Add FOUC prevention with inline critical CSS - Add Makefile dev/run/clean targets - Fix README git clone URL - Add doc/DECISIONS.md for architectural decisions Tests: - Add hamburger menu click toggle tests - Add iPad sidebar visibility tests - Update security tests for go-git implementation - Add cookie Secure flag tests
173 lines
4.3 KiB
Markdown
173 lines
4.3 KiB
Markdown
# 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)
|
|
- [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-001: No Data Caching
|
|
|
|
**Status:** Accepted
|
|
**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
|
|
|
|
---
|
|
|
|
## 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?
|
|
```
|