A modernized, full-stack personal portfolio. What started as a static HTML/JS site has evolved into a robust decoupled application featuring a Vanilla JavaScript frontend and a resilient Golang backend powered by SQLite.
- Frontend: Pure HTML5, CSS3, and Vanilla JavaScript. Deployed statically to GitHub Pages. Focuses on performance and SEO.
- Backend: Go 1.26 API following Clean Architecture/DDD patterns.
- Database: SQLite with automated initial seeding (embedded JSON data).
- Security & Reliability: Built-in CORS configuration, IP-based Rate Limiting, and graceful failure handling.
- CI/CD & DevOps: Automated via GitHub Actions. Tests are enforced (50%+ coverage required). Backend is packaged into a Docker container and deployed via SSH to a DigitalOcean Droplet.
- Dynamic Content: Projects are served from a SQLite database rather than hardcoded static files.
- Automated Seeding: If the database is empty, the backend automatically seeds initial data at runtime using Go's
//go:embeddirective. - Contact Form Integration: Includes an SMTP sender to natively dispatch emails when the contact form is submitted.
- Resilient Infrastructure: Backend runs containerized with persistent volumes to ensure data survives across restarts.
portfolio/
├── frontend/
│ ├── index.html # Entry point
│ ├── css/ # Styling (CSS Modules)
│ ├── js/ # Client logic and API fetching
│ └── package.json # Test dependencies (Vitest)
│
├── backend/
│ ├── cmd/server/ # Entrypoint & Seeder logic
│ ├── internal/
│ │ ├── domain/ # Entities (Project, ContactMessage)
│ │ ├── handler/ # HTTP Controllers
│ │ ├── middleware/ # Security (CORS, Rate Limiter)
│ │ ├── repository/ # SQLite persistence layer
│ │ └── sender/ # External SMTP service
│ ├── Dockerfile # Multi-stage build definition
│ └── go.mod
│
└── .github/workflows/ # Automated Deployment Pipelines
- Go 1.26+
- Node.js & npm (for frontend tests)
cd backend
# The backend will start on port 8080 and create portfolio.db automatically
go run cmd/server/main.goThe frontend points to http://localhost:8080 by default during local development. Simply open frontend/index.html in your browser, or use a local static server:
cd frontend
python3 -m http.server 3000
# Open http://localhost:3000To fully run the backend in production (or locally with email capabilities), set the following environment variables:
| Variable | Description | Default |
|---|---|---|
PORT |
The port the HTTP server listens on. | 8080 |
DB_PATH |
Path to the SQLite database file. | portfolio.db |
ALLOWED_ORIGIN |
CORS allowed origin (Frontend URL). | * |
ADMIN_TOKEN |
Token for securing POST /api/projects and /api/experiences. | supersecret123 |
SMTP_HOST |
Hostname of your email provider (e.g., smtp.gmail.com). | empty |
SMTP_PORT |
Port for your SMTP server (e.g., 587). | empty |
SMTP_USER |
SMTP authentication username. | empty |
SMTP_PASSWORD |
SMTP authentication password/app token. | empty |
CONTACT_TO_EMAIL |
Destination email to receive contact form submissions. | empty |
(Note: If SMTP variables are missing, the backend will still run but will fallback to logging contact messages to the console).
You can dynamically add new projects and experiences to your database without touching the code. Make a POST request to the API with the header Authorization: Bearer <ADMIN_TOKEN>.
curl -X POST "https://jellyfish-app-ows8l.ondigitalocean.app/api/experiences" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"company": "Huawei",
"role": "Backend Maintenance Engineer - Sistema Django em Produção",
"period": "2024",
"duties": [
"Manutenção proativa e troubleshooting do principal sistema Django em produção",
"Implementação de correções e otimizações de performance",
"Suporte técnico a equipes de negócio e operações"
]
}'Experience Fields:
company(string): Company namerole(string): Job title/positionperiod(string): Employment period (e.g., "fev 2023 - ago 2024")duties(array): List of responsibilities and accomplishments
curl -X POST "https://jellyfish-app-ows8l.ondigitalocean.app/api/projects" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Portfolio API",
"description": "REST API desenvolvida em Go com SQLite para gerenciar experiências, projetos e contatos. Inclui autenticação por Bearer token, CORS e rate limiting.",
"github": "https://github.com/schulzdimitri/portfolio",
"tags": ["Go", "SQLite", "REST API", "Docker", "CI/CD", "GitHub Actions"]
}'Project Fields:
title(string): Project namedescription(string): Detailed description of the projectgithub(string): GitHub repository URLtags(array): Technologies and skills used
This project utilizes two independent GitHub Actions workflows:
- Frontend Pipeline (
frontend-ci.yml): Triggers on UI changes. Runs Vitest unit tests, injects the productionBACKEND_URL, and deploys statically to GitHub Pages. - Backend Pipeline (
backend-ci.yml): Triggers on backend changes. Runs Go tests, enforces coverage, builds a Docker image to GitHub Container Registry (GHCR), and triggers a rolling update via SSH to the DigitalOcean Droplet.