diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a1a1b8c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement via GitHub issues +or by contacting the project maintainer directly. + +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6376dd2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,296 @@ +# Contributing to CV Site + +First off, thank you for considering contributing to this project! This CV site is a personal project, but contributions are welcome to improve the template, fix bugs, or add features that others might find useful. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [How Can I Contribute?](#how-can-i-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Enhancements](#suggesting-enhancements) + - [Pull Requests](#pull-requests) +- [Development Setup](#development-setup) +- [Style Guidelines](#style-guidelines) + - [Go Code Style](#go-code-style) + - [HTMX Patterns](#htmx-patterns) + - [CSS Style](#css-style) +- [Testing](#testing) +- [Commit Messages](#commit-messages) + +## Code of Conduct + +This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainer. + +## How Can I Contribute? + +### Reporting Bugs + +Before creating bug reports, please check existing issues to avoid duplicates. When creating a bug report, include as many details as possible: + +**Bug Report Template:** + +```markdown +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '...' +3. See error + +**Expected behavior** +What you expected to happen. + +**Environment:** +- Go version: [e.g., 1.21.5] +- OS: [e.g., macOS 14.0, Ubuntu 22.04] +- Browser (if applicable): [e.g., Chrome 120, Firefox 121] + +**Additional context** +Add any other context about the problem here. +``` + +### Suggesting Enhancements + +Enhancement suggestions are welcome! Please create an issue with: + +- **Clear title** describing the enhancement +- **Detailed description** of the proposed functionality +- **Use case** explaining why this would be useful +- **Implementation ideas** (optional) if you have thoughts on how to implement it + +### Pull Requests + +1. **Fork the repository** and create your branch from `main` +2. **Branch naming convention:** + - `feature/description` - New features (e.g., `feature/add-dark-mode`) + - `fix/description` - Bug fixes (e.g., `fix/pdf-export-fonts`) + - `docs/description` - Documentation updates (e.g., `docs/update-readme`) + - `refactor/description` - Code refactoring (e.g., `refactor/simplify-handlers`) + +3. **Make your changes:** + - Follow the [style guidelines](#style-guidelines) + - Add tests if adding new functionality (see [Testing](#testing)) + - Update documentation as needed + +4. **Test your changes:** + - Run `make dev` to test locally + - Test PDF export functionality + - Test both English and Spanish versions + - Test responsive design on different screen sizes + +5. **Commit your changes** with clear commit messages (see [Commit Messages](#commit-messages)) + +6. **Push to your fork** and submit a pull request to the `main` branch + +7. **Pull Request Template:** + +```markdown +**Description** +Brief description of what this PR does. + +**Type of change** +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update + +**How Has This Been Tested?** +Describe the tests you ran and how to reproduce them. + +**Checklist:** +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have tested the changes locally +``` + +## Development Setup + +### Prerequisites + +- **Go 1.21+** installed +- **Git** for version control +- **Make** (optional, but recommended) +- **Chrome/Chromium** for PDF generation testing + +### Setup Steps + +1. **Clone your fork:** + ```bash + git clone https://github.com/YOUR-USERNAME/cv.git + cd cv + ``` + +2. **Install dependencies:** + ```bash + go mod download + ``` + +3. **Set up environment:** + ```bash + cp .env.example .env + # Edit .env if needed + ``` + +4. **Run development server:** + ```bash + make dev + # Or: GO_ENV=development go run main.go + ``` + +5. **Open browser:** + ``` + http://localhost:1999 + ``` + +### Useful Make Commands + +- `make dev` - Run in development mode (hot-reload enabled) +- `make build` - Build production binary +- `make test` - Test endpoints (requires server running) +- `make clean` - Remove build artifacts +- `make help` - Show all available commands + +## Style Guidelines + +### Go Code Style + +- **Follow standard Go conventions:** + - Use `gofmt` to format code (runs automatically with most editors) + - Run `go vet` to catch common mistakes + - Use meaningful variable and function names + - Add comments for exported functions and complex logic + +- **Code organization:** + - Keep handlers in `main.go` or separate handler files + - Use the `internal/models` package for data structures + - Keep utilities in appropriate packages + +- **Error handling:** + ```go + // Good + if err != nil { + log.Printf("Error loading CV data: %v", err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + + // Avoid silent failures + // Bad: ignoring errors without logging + data, _ := loadCV() + ``` + +### HTMX Patterns + +- **Use semantic HTML:** + ```html + + + + + ``` + +- **Keep HTMX attributes organized:** + - `hx-get/post` first + - `hx-target` second + - `hx-swap` third + - Other attributes follow + +- **Progressive enhancement:** + - Ensure basic functionality works without JavaScript + - HTMX should enhance, not be required + +### CSS Style + +- **Organization:** + - Group related styles together + - Use comments to separate sections + - Keep selectors specific but not overly complex + +- **Naming:** + - Use semantic class names + - Prefer descriptive names over abbreviations + +- **Responsive design:** + - Mobile-first approach + - Use media queries for larger screens + - Test on multiple screen sizes + +## Testing + +**Current State:** This project does not yet have automated tests. This is a known gap. + +**When adding tests (future):** + +- Write unit tests for new utility functions +- Add integration tests for HTTP handlers +- Test PDF generation functionality +- Ensure tests pass before submitting PR: + ```bash + go test ./... + ``` + +**Manual testing requirements:** + +- Test both language versions (English/Spanish) +- Test PDF export (both server-side and browser print) +- Test responsive design (mobile, tablet, desktop) +- Test in multiple browsers (Chrome, Firefox, Safari) +- Verify console has no errors +- Check network tab for failed requests + +## Commit Messages + +Use clear, descriptive commit messages following this format: + +``` +type: brief description + +Optional longer description explaining what and why (not how). + +Fixes #123 +``` + +**Types:** +- `feat:` - New feature +- `fix:` - Bug fix +- `docs:` - Documentation changes +- `style:` - Code style changes (formatting, no logic change) +- `refactor:` - Code refactoring +- `perf:` - Performance improvements +- `test:` - Adding or updating tests +- `chore:` - Maintenance tasks, dependency updates + +**Examples:** + +``` +feat: add dark mode toggle + +Add user preference for dark mode with localStorage persistence. +Respects system preference on first visit. + +Fixes #42 +``` + +``` +fix: correct PDF font rendering in headless Chrome + +The custom Quicksand font wasn't loading properly in chromedp. +Updated to wait for fonts to load before PDF generation. + +Fixes #38 +``` + +## Questions? + +Feel free to open an issue with the `question` label if you need help or clarification on anything! + +## Thank You! + +Your contributions help make this project better for everyone. Thank you for taking the time to contribute! 🎉 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..aced3ad --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Juan Andrés Moreno Rubio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 3a59223..f97e2fa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,29 @@ # CV Site - Go + HTMX +[![Go Version](https://img.shields.io/badge/Go-1.21%2B-00ADD8?logo=go)](https://go.dev/) +[![HTMX](https://img.shields.io/badge/HTMX-1.9.10-3366CC)](https://htmx.org/) +[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) + **Modern, minimal curriculum vitae website** for Juan Andrés Moreno Rubio built with **Go** and **HTMX**. +A professional, bilingual CV site with server-side PDF generation, HTMX interactivity, and a clean paper design aesthetic. Perfect template for developers looking to create their own CV website with modern tech and minimal JavaScript. + +## 📑 Table of Contents + +- [Features](#-features) +- [Demo](#-demo) +- [Quick Start](#-quick-start) +- [Updating Your CV](#-updating-your-cv) +- [Export to PDF](#-export-to-pdf) +- [Key Technologies](#-key-technologies) +- [Documentation](#-documentation) +- [Deployment](#-deployment) +- [Customization](#-customization) +- [Contributing](#-contributing) +- [License](#-license) +- [Support](#-support) + ## 🚀 Features - ✅ **Bilingual Support** - Spanish and English with instant switching (no page reload) @@ -13,24 +35,55 @@ - ✅ **JSON-Based Content** - Easy to update without touching code - ✅ **AI Development Section** - Showcases modern AI-assisted development skills - ✅ **Fast & Lightweight** - Go backend with chromedp for PDF generation +- ✅ **Security Hardened** - CSP headers, XSS protection, secure defaults +- ✅ **Production Ready** - Docker support, systemd service, CI/CD workflows +- ✅ **Developer Friendly** - Hot reload, clear code structure, comprehensive Makefile + +## 📸 Demo + +**Live Features:** +- Single-page application with no page reloads +- Instant language switching (English ↔ Spanish) +- Professional PDF export with perfect font rendering +- Responsive design from mobile to desktop +- Clean paper aesthetic on gray background +- Print-friendly layouts + +**Note:** This is a personal CV site template. Fork it and customize the JSON files with your own information! ## 📋 Quick Start ### Prerequisites - **Go 1.21+** installed +- **Chrome/Chromium** (for PDF generation) +- **Make** (optional, recommended for easier development) -### Run +### Installation & Run \`\`\`bash -# Build and run +# Clone the repository +git clone https://github.com/yourusername/cv.git +cd cv + +# Option 1: Using Make (recommended) +make dev + +# Option 2: Using Go directly +go run main.go + +# Option 3: Build and run binary go build -o cv-server && ./cv-server \`\`\` -Open **http://localhost:1999** +### Access the Site -- 🇬🇧 English: http://localhost:1999/?lang=en -- 🇪🇸 Spanish: http://localhost:1999/?lang=es +Open **http://localhost:1999** in your browser + +- 🇬🇧 **English version:** http://localhost:1999/?lang=en +- 🇪🇸 **Spanish version:** http://localhost:1999/?lang=es + +**Language switching** is instant via HTMX - no page reload required! ## 📄 Updating Your CV @@ -66,11 +119,115 @@ No code changes needed - just refresh browser! ## 🎯 Key Technologies -- Backend: **Go** (stdlib net/http) -- PDF Generation: **chromedp** (headless Chrome automation) -- Frontend: **HTMX** 1.9.10 -- Styling: Custom **CSS** with Quicksand font -- Data: **JSON** files +- **Backend:** Go 1.21+ (stdlib `net/http`, graceful shutdown) +- **PDF Generation:** chromedp (headless Chrome automation) +- **Frontend:** HTMX 1.9.10 (hypermedia-driven interactions) +- **Styling:** Custom CSS with Quicksand font from Google Fonts +- **Data:** JSON files for easy content management +- **Deployment:** Docker, systemd service, GitHub Actions CI/CD + +## 📚 Documentation + +- **[ARCHITECTURE.md](ARCHITECTURE.md)** - System design, data flow, and technical decisions +- **[CONTRIBUTING.md](CONTRIBUTING.md)** - How to contribute (issues, PRs, code style) +- **[SECURITY.md](SECURITY.md)** - Security policy, vulnerability reporting, deployment considerations +- **[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)** - Community guidelines and standards +- **[LICENSE](LICENSE)** - MIT License + +## 🚀 Deployment + +This project is production-ready with multiple deployment options: + +### Docker Deployment + +\`\`\`bash +# Build Docker image +make docker-build + +# Run container +make docker-run +\`\`\` + +### Systemd Service + +\`\`\`bash +# Install as systemd service +make install-service + +# Update running service +make update-service +\`\`\` + +### Manual Deployment + +\`\`\`bash +# Build optimized binary +make build + +# Run in production mode +GO_ENV=production ./cv-server +\`\`\` + +**Environment Configuration:** Copy `.env.example` to `.env` and customize: +- `PORT` - Server port (default: 1999) +- `GO_ENV` - Environment (development/production) +- `TEMPLATE_HOT_RELOAD` - Enable template hot-reload in development + +**Security:** See [SECURITY.md](SECURITY.md) for production deployment best practices. + +## 🎨 Customization + +### Update Your CV Content + +1. Edit `data/cv-en.json` and `data/cv-es.json` with your information +2. No code changes required - just refresh the browser! + +### Customize Styling + +- **Main styles:** `static/css/main.css` +- **Colors:** Modify CSS variables in `:root` selector +- **Fonts:** Update Google Fonts import in HTML templates +- **Layout:** Edit templates in `templates/` directory + +### Add New Sections + +1. Update the `CV` struct in `internal/models/cv.go` +2. Add content to JSON files in `data/` +3. Update templates in `templates/` to display new sections + +## 🤝 Contributing + +Contributions are welcome! Whether it's: + +- 🐛 Bug reports +- 💡 Feature suggestions +- 📝 Documentation improvements +- 🔧 Code contributions + +Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on: +- Submitting issues +- Creating pull requests +- Code style and testing requirements +- Development workflow + +## 📄 License + +This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details. + +**TL;DR:** You can use this template for your own CV site, modify it, and distribute it. Just keep the original copyright notice. + +## 💬 Support + +- **Issues:** [GitHub Issues](https://github.com/yourusername/cv/issues) for bug reports and feature requests +- **Discussions:** [GitHub Discussions](https://github.com/yourusername/cv/discussions) for questions and ideas +- **Security:** See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities + +## 🙏 Acknowledgments + +- **HTMX** - For making hypermedia-driven applications enjoyable +- **chromedp** - For reliable headless Chrome automation +- **Go Community** - For excellent standard library and tooling +- **AI Assistance** - For accelerating development and documentation --- diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ad72521 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,205 @@ +# Security Policy + +## Supported Versions + +This project is actively maintained. Security updates will be provided for the latest release on the `main` branch. + +| Version | Supported | +| ------- | ------------------ | +| main | :white_check_mark: | +| < main | :x: | + +## Reporting a Vulnerability + +We take the security of this CV site seriously. If you discover a security vulnerability, please help us protect users by following responsible disclosure practices. + +### How to Report + +**DO NOT** open a public issue for security vulnerabilities. + +Instead, please report security vulnerabilities by: + +1. **GitHub Security Advisories** (Preferred): + - Go to the repository's Security tab + - Click "Report a vulnerability" + - Fill out the form with details + +2. **Direct Contact**: + - Open a private issue or contact the maintainer directly + - Use encrypted communication if the vulnerability is severe + +### What to Include + +Please provide the following information in your report: + +- **Description** of the vulnerability +- **Steps to reproduce** the issue +- **Potential impact** (e.g., data exposure, XSS, CSRF) +- **Affected versions** (if known) +- **Suggested fix** (if you have one) +- **Your contact information** for follow-up questions + +### Response Timeline + +- **Initial Response**: Within 48 hours +- **Status Update**: Within 7 days +- **Fix Timeline**: Depends on severity + - Critical: Within 7 days + - High: Within 14 days + - Medium: Within 30 days + - Low: Next release cycle + +### Disclosure Policy + +- We ask that you give us reasonable time to fix the vulnerability before public disclosure +- We will credit you in the security advisory (unless you prefer to remain anonymous) +- Once the fix is deployed, we will publish a security advisory with details + +## Security Considerations for Deployments + +If you're deploying this CV site, please be aware of these security considerations: + +### 1. PDF Generation Security + +The server uses headless Chrome (via chromedp) to generate PDFs: + +- **Risk**: Chromedp executes JavaScript and renders HTML, which could be exploited if user input is not sanitized +- **Mitigation**: + - The CV data comes from trusted JSON files, not user input + - If you modify the application to accept user input, ensure proper sanitization + - Consider running chromedp in a sandboxed environment + +### 2. Content Security Policy + +The application includes CSP headers: + +```go +Content-Security-Policy: default-src 'self'; + script-src 'self' 'unsafe-inline' https://unpkg.com; + style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; + font-src 'self' https://fonts.gstatic.com; + img-src 'self' data: +``` + +- Review and adjust CSP headers based on your deployment needs +- Remove `'unsafe-inline'` if possible by moving inline scripts/styles to separate files + +### 3. Environment Variables + +Sensitive configuration is managed via environment variables: + +- **Never commit** `.env` file to version control +- Use `.env.example` as a template +- In production, use secure secret management (e.g., HashiCorp Vault, AWS Secrets Manager) + +### 4. HTTPS in Production + +- **Always use HTTPS** in production +- Configure TLS certificates (Let's Encrypt recommended) +- Consider using a reverse proxy (nginx, Caddy) for TLS termination + +### 5. Rate Limiting + +The application does not include built-in rate limiting: + +- **Recommendation**: Use a reverse proxy (nginx, Caddy) to implement rate limiting +- Protect the `/export/pdf` endpoint to prevent PDF generation abuse + +### 6. Input Validation + +While this application primarily serves static CV data: + +- If you extend it to accept user input, implement strict validation +- Sanitize all inputs before rendering in templates +- Use Go's `html/template` package (which auto-escapes) for HTML rendering + +### 7. Dependency Management + +Keep dependencies up to date: + +```bash +# Check for outdated dependencies +go list -u -m all + +# Update dependencies +go get -u ./... +go mod tidy +``` + +### 8. Security Headers + +The application sets security headers: + +- `X-Content-Type-Options: nosniff` +- `X-Frame-Options: DENY` +- `X-XSS-Protection: 1; mode=block` +- `Content-Security-Policy: ...` + +Review and enhance these headers based on your deployment needs. + +### 9. Logging and Monitoring + +- Enable structured logging in production +- Monitor for unusual patterns (e.g., excessive PDF generation requests) +- Set up alerts for errors and anomalies + +### 10. Docker Security + +If deploying via Docker: + +- Use official, minimal base images +- Run container as non-root user +- Scan images for vulnerabilities (e.g., `docker scan`, Trivy) +- Keep base images updated + +## Known Security Considerations + +### PDF Generation Resource Usage + +- **Issue**: PDF generation uses headless Chrome, which consumes significant CPU/memory +- **Impact**: Potential DoS via excessive PDF generation requests +- **Mitigation**: + - Implement rate limiting on `/export/pdf` endpoint + - Consider caching generated PDFs + - Monitor resource usage + +### Third-Party Dependencies + +External dependencies loaded from CDNs: + +- HTMX from `https://unpkg.com` +- Google Fonts from `https://fonts.googleapis.com` + +**Recommendation**: For production, consider: +- Self-hosting these dependencies for better control +- Using Subresource Integrity (SRI) hashes +- Implementing a Content Security Policy + +## Security Best Practices + +If you're forking this project for your own CV: + +1. **Review all code** before deploying +2. **Update personal information** in JSON files +3. **Configure security headers** appropriate for your use case +4. **Enable HTTPS** with valid certificates +5. **Keep dependencies updated** regularly +6. **Monitor application logs** for suspicious activity +7. **Backup your data** regularly +8. **Test security** before going live + +## Security Updates + +Security updates will be announced via: + +- GitHub Security Advisories +- Release notes on GitHub +- Git commit messages tagged with `[SECURITY]` + +## Contact + +For security concerns, please contact the project maintainer via GitHub. + +## Acknowledgments + +We appreciate the security research community's efforts in responsibly disclosing vulnerabilities. Thank you for helping keep this project secure! diff --git a/data/cv-en.json b/data/cv-en.json index f11db34..4a3c2eb 100644 --- a/data/cv-en.json +++ b/data/cv-en.json @@ -664,6 +664,35 @@ } ], "courses": [ + { + "title": "Codecademy Certifications", + "institution": "Codecademy", + "courseLogo": "codecademy.png", + "location": "Online", + "date": "2022-2024", + "duration": "Various", + "shortDescription": "Professional development courses in AI and modern web technologies through Codecademy's interactive learning platform.", + "responsibilities": [ + "
Intro to AI Transformers Course April 2024: Comprehensive introduction to transformer architecture and AI models, covering attention mechanisms, encoder-decoder structures, and practical applications in natural language processing
", + "
Learn React Course March 2022: Complete React framework training covering components, state management, hooks, lifecycle methods, and modern React development practices
" + ] + }, + { + "title": "LinkedIn Learning Certifications", + "institution": "LinkedIn Learning", + "courseLogo": "linkedin.png", + "location": "Online", + "date": "2019-2020", + "duration": "Various", + "shortDescription": "Professional development courses in SAP technologies, UX design, security, and data analytics through LinkedIn Learning's comprehensive training platform.", + "responsibilities": [ + "
Aprende lectura rápida April 2020: Speed reading techniques and comprehension strategies for professional development and efficient information processing
", + "
A Tour of the SAP Cloud Platform February 2020: Comprehensive overview of SAP Cloud Platform services, architecture, and integration capabilities for enterprise cloud solutions
", + "
Learning Android Security February 2020: Android security best practices, encryption methods, secure coding practices, and mobile application security fundamentals
", + "
Persuasive UX: Creating Credibility January 2020: User experience design principles focused on building trust, credibility, and persuasive design patterns for web applications
", + "
Big Data Foundations: Techniques and Concepts December 2019: Fundamentals of big data technologies, distributed computing, data processing frameworks, and analytics techniques
" + ] + }, { "title": "Servoy World 2011", "institution": "Servoy", @@ -738,6 +767,8 @@ "projects": [ { "title": "Somos Una Ola - Beach Cleaning Initiative", + "projectName": "Somos Una Ola", + "projectDesc": "Beach Cleaning Initiative", "url": "https://somosunaola.org", "projectLogo": "somosunaola.png", "location": "La Palma, Canary Islands", @@ -753,6 +784,8 @@ }, { "title": "Herrumbre Vivo Arte - Artist Portfolio Website", + "projectName": "Herrumbre Vivo Arte", + "projectDesc": "Artist Portfolio Website", "url": "https://herrumbrevivoarte.com", "projectLogo": "herrumbre-vivo.png", "location": "Fuencaliente, La Palma", @@ -768,6 +801,8 @@ }, { "title": "La Porra.club - Football Prediction Platform", + "projectName": "La Porra.club", + "projectDesc": "Football Prediction Platform", "url": "https://laporra.club", "projectLogo": "laporra.png", "gitRepoUrl": "/Users/txeo/laporra", @@ -784,6 +819,8 @@ }, { "title": "CDC Starter Kit - SAP Customer Data Cloud Demo", + "projectName": "CDC Starter Kit", + "projectDesc": "SAP Customer Data Cloud Demo", "url": "https://gigyademo.com/cdc-starter-kit/", "projectLogo": "sap.png", "location": "Online", diff --git a/data/cv-es.json b/data/cv-es.json index 6c1efd6..7c9c28e 100644 --- a/data/cv-es.json +++ b/data/cv-es.json @@ -669,6 +669,35 @@ } ], "courses": [ + { + "title": "Certificaciones Codecademy", + "institution": "Codecademy", + "courseLogo": "codecademy.png", + "location": "Online", + "date": "2022-2024", + "duration": "Varios", + "shortDescription": "Cursos de desarrollo profesional en IA y tecnologías web modernas a través de la plataforma de aprendizaje interactivo de Codecademy.", + "responsibilities": [ + "
Intro to AI Transformers Course Abril 2024: Introducción completa a la arquitectura de transformers y modelos de IA, cubriendo mecanismos de atención, estructuras encoder-decoder y aplicaciones prácticas en procesamiento de lenguaje natural
", + "
Learn React Course Marzo 2022: Formación completa en React framework cubriendo componentes, gestión de estado, hooks, métodos de ciclo de vida y prácticas modernas de desarrollo con React
" + ] + }, + { + "title": "Certificaciones LinkedIn Learning", + "institution": "LinkedIn Learning", + "courseLogo": "linkedin.png", + "location": "Online", + "date": "2019-2020", + "duration": "Varios", + "shortDescription": "Cursos de desarrollo profesional en tecnologías SAP, diseño UX, seguridad y análisis de datos a través de la plataforma de formación integral de LinkedIn Learning.", + "responsibilities": [ + "
Aprende lectura rápida Abril 2020: Técnicas de lectura rápida y estrategias de comprensión para desarrollo profesional y procesamiento eficiente de información
", + "
A Tour of the SAP Cloud Platform Febrero 2020: Visión general completa de servicios de SAP Cloud Platform, arquitectura y capacidades de integración para soluciones empresariales en la nube
", + "
Learning Android Security Febrero 2020: Mejores prácticas de seguridad Android, métodos de encriptación, prácticas de codificación segura y fundamentos de seguridad de aplicaciones móviles
", + "
Persuasive UX: Creating Credibility Enero 2020: Principios de diseño de experiencia de usuario enfocados en generar confianza, credibilidad y patrones de diseño persuasivo para aplicaciones web
", + "
Big Data Foundations: Techniques and Concepts Diciembre 2019: Fundamentos de tecnologías big data, computación distribuida, frameworks de procesamiento de datos y técnicas de análisis
" + ] + }, { "title": "Servoy World 2011", "institution": "Servoy", @@ -743,6 +772,8 @@ "projects": [ { "title": "Somos Una Ola - Iniciativa de Limpieza de Playas", + "projectName": "Somos Una Ola", + "projectDesc": "Iniciativa de Limpieza de Playas", "url": "https://somosunaola.org", "projectLogo": "somosunaola.png", "location": "La Palma, Islas Canarias", @@ -758,6 +789,8 @@ }, { "title": "Herrumbre Vivo Arte - Sitio Web Portfolio de Artista", + "projectName": "Herrumbre Vivo Arte", + "projectDesc": "Sitio Web Portfolio de Artista", "url": "https://herrumbrevivoarte.com", "projectLogo": "herrumbre-vivo.png", "location": "Fuencaliente, La Palma", @@ -773,6 +806,8 @@ }, { "title": "La Porra.club - Plataforma de Predicción de Fútbol", + "projectName": "La Porra.club", + "projectDesc": "Plataforma de Predicción de Fútbol", "url": "https://laporra.club", "projectLogo": "laporra.png", "gitRepoUrl": "/Users/txeo/laporra", @@ -789,6 +824,8 @@ }, { "title": "CDC Starter Kit - Demo de SAP Customer Data Cloud", + "projectName": "CDC Starter Kit", + "projectDesc": "Demo de SAP Customer Data Cloud", "url": "https://gigyademo.com/cdc-starter-kit/", "projectLogo": "sap.png", "location": "Online", diff --git a/internal/models/cv.go b/internal/models/cv.go index 23a4ed0..f122d43 100644 --- a/internal/models/cv.go +++ b/internal/models/cv.go @@ -101,13 +101,15 @@ type Language struct { type Project struct { Title string `json:"title"` + ProjectName string `json:"projectName,omitempty"` // Optional: linkable part of title + ProjectDesc string `json:"projectDesc,omitempty"` // Optional: non-linkable description part URL string `json:"url"` - ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename - GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates + ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename + GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates Location string `json:"location"` - StartDate string `json:"startDate,omitempty"` // Optional static start date + StartDate string `json:"startDate,omitempty"` // Optional static start date Current bool `json:"current"` - MaintainedBy string `json:"maintainedBy,omitempty"` // Optional maintainer name (e.g., "SAP") + MaintainedBy string `json:"maintainedBy,omitempty"` // Optional maintainer name (e.g., "SAP") Technologies []string `json:"technologies"` ShortDescription string `json:"shortDescription"` Responsibilities []string `json:"responsibilities"` diff --git a/static/css/main.css b/static/css/main.css index 642c1b3..7405210 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -779,6 +779,11 @@ iconify-icon { margin-top: 0.5rem; } +.duration-text { + color: #999; + font-weight: normal; +} + .responsibilities { list-style: none; margin-top: 1rem; diff --git a/static/images/courses/codecademy.png b/static/images/courses/codecademy.png new file mode 100644 index 0000000..078c2bd Binary files /dev/null and b/static/images/courses/codecademy.png differ diff --git a/static/images/courses/linkedin.png b/static/images/courses/linkedin.png new file mode 100644 index 0000000..09aa8a0 Binary files /dev/null and b/static/images/courses/linkedin.png differ diff --git a/templates/cv-content.html b/templates/cv-content.html index 633e9a2..68ca334 100644 --- a/templates/cv-content.html +++ b/templates/cv-content.html @@ -91,7 +91,7 @@ {{end}}
- {{.Position}}{{if .Company}} - {{if .CompanyURL}}{{.Company}}{{else}}{{.Company}}{{end}}{{end}}
+ {{.Position}}{{if .Company}} - {{if .CompanyURL}}{{.Company}}{{else}}{{.Company}}{{end}}{{if .Duration}} {{.Duration}}{{end}}{{end}}
{{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} - ({{.Location}}) {{if .ShortDescription}} @@ -186,7 +186,13 @@
{{end}}
- {{if .URL}}{{.Title}}{{else}}{{.Title}}{{end}}
+ + {{if .ProjectName}} + {{if .URL}}{{.ProjectName}}{{else}}{{.ProjectName}}{{end}}{{if .ProjectDesc}} - {{.ProjectDesc}}{{end}} + {{else}} + {{if .URL}}{{.Title}}{{else}}{{.Title}}{{end}} + {{end}} +
{{if .StartDate}}{{.StartDate}}{{if .Current}}{{if .DynamicDate}} / {{.DynamicDate}}{{else}} / {{if eq $.Lang "es"}}presente{{else}}now{{end}}{{end}}{{end}}{{end}} - ({{.Location}}) {{if .ShortDescription}} diff --git a/templates/index.html b/templates/index.html index 4238b56..70f687a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -277,28 +277,41 @@ } } + // Flag to keep header visible after navigation + let keepHeaderVisible = false; + // Scroll to section smoothly function scrollToSection(sectionId) { event.preventDefault(); // Prevent default anchor behavior const section = document.getElementById(sectionId); if (section) { - const actionBarHeight = document.querySelector('.action-bar').offsetHeight; - const menuHeight = document.querySelector('.navigation-menu').offsetHeight; - const offset = actionBarHeight + (menuHeight || 0) + 20; // Add 20px padding + // Ensure header is visible before scrolling + const actionBar = document.querySelector('.action-bar'); + const navMenu = document.querySelector('.navigation-menu'); + actionBar.classList.remove('header-hidden'); + navMenu.classList.remove('header-hidden'); - const elementPosition = section.getBoundingClientRect().top; - const offsetPosition = elementPosition + window.pageYOffset - offset; - - window.scrollTo({ - top: offsetPosition, - behavior: 'smooth' - }); + // Set flag to keep header visible + keepHeaderVisible = true; // Close menu after clicking - const menu = document.getElementById('navigation-menu'); - menu.classList.remove('menu-open'); + navMenu.classList.remove('menu-open'); document.querySelector('.hamburger-btn').setAttribute('aria-expanded', 'false'); + + // Wait a bit for header to be visible, then calculate offset + setTimeout(() => { + const actionBarHeight = actionBar.offsetHeight; + const offset = actionBarHeight + 20; // Add 20px padding + + const elementPosition = section.getBoundingClientRect().top; + const offsetPosition = elementPosition + window.pageYOffset - offset; + + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth' + }); + }, 100); } } @@ -348,9 +361,11 @@ if (toggle.checked) { paper.classList.add('cv-long'); paper.classList.remove('cv-short'); + localStorage.setItem('cv-length', 'long'); } else { paper.classList.add('cv-short'); paper.classList.remove('cv-long'); + localStorage.setItem('cv-length', 'short'); } // Restore scroll position after DOM updates @@ -368,8 +383,10 @@ if (toggle.checked) { paper.classList.add('show-logos'); + localStorage.setItem('cv-logos', 'show'); } else { paper.classList.remove('show-logos'); + localStorage.setItem('cv-logos', 'hide'); } // Restore scroll position after DOM updates @@ -412,10 +429,31 @@ }, 100); } - // Initialize with short version, logos enabled, and saved theme + // Initialize with saved preferences or defaults document.addEventListener('DOMContentLoaded', function() { - document.querySelector('.cv-paper').classList.add('cv-short'); - document.querySelector('.cv-paper').classList.add('show-logos'); + const paper = document.querySelector('.cv-paper'); + + // Restore CV length preference + const savedLength = localStorage.getItem('cv-length') || 'short'; + if (savedLength === 'long') { + paper.classList.add('cv-long'); + paper.classList.remove('cv-short'); + document.getElementById('lengthToggle').checked = true; + } else { + paper.classList.add('cv-short'); + paper.classList.remove('cv-long'); + document.getElementById('lengthToggle').checked = false; + } + + // Restore logos preference + const savedLogos = localStorage.getItem('cv-logos') || 'show'; + if (savedLogos === 'show') { + paper.classList.add('show-logos'); + document.getElementById('logoToggle').checked = true; + } else { + paper.classList.remove('show-logos'); + document.getElementById('logoToggle').checked = false; + } // Restore theme preference const savedTheme = localStorage.getItem('cv-theme') || 'default'; @@ -436,10 +474,15 @@ const currentScroll = window.pageYOffset || document.documentElement.scrollTop; const isMenuOpen = navMenu.classList.contains('menu-open'); + // If scrolling up, reset the keepHeaderVisible flag + if (currentScroll < lastScrollTop) { + keepHeaderVisible = false; + } + // Hide/show header based on scroll direction if (currentScroll > scrollThreshold) { - if (currentScroll > lastScrollTop) { - // Scrolling down - hide header + if (currentScroll > lastScrollTop && !keepHeaderVisible) { + // Scrolling down - hide header (only if keepHeaderVisible is false) actionBar.classList.add('header-hidden'); // Only hide menu if it's open if (isMenuOpen) {