A modern full-stack personal projects homepage built with Vue 3, TypeScript, and Node.js
- Overview
- Architecture
- Quick Start
- Project Structure
- Development
- Testing
- Docker Deployment
- Configuration
- Contributing
- Documentation
- License
Toomas633's Dungeon is a full-stack web application showcasing personal projects, technical skills, and interactive features. The application combines a modern Vue 3 frontend with a robust Node.js backend, designed for performance, maintainability, and scalability.
- 🎨 Modern UI: Responsive design with Vuetify 4 Material Design components
- 📧 Contact System: Integrated email service with rate limiting and validation
- 🗺️ Interactive Maps: Leaflet integration for location visualization
- 📊 Project Showcase: Dynamic galleries with GitHub integration
- 🔒 Security: CORS protection, rate limiting, and security headers
- 🐳 Containerized: Full Docker support with multi-stage builds
- ✅ Tested: Comprehensive test coverage with Vitest
- 📈 Quality: SonarCloud integration for code quality analysis
- 📚 API Documentation: Interactive Swagger UI for API exploration
- Framework: Vue 3.5.34 with Composition API
- Language: TypeScript 6.0.3
- UI Library: Vuetify 4.0.7
- Build Tool: Vite 8.0.14
- Router: Vue Router 5.0.7
- HTTP Client: Axios 1.16.1
- Maps: Leaflet 1.9.4
- Testing: Vitest 4.1.7
- Runtime: Node.js 18+ (24+ recommended)
- Framework: Express.js 5.2.1
- Language: TypeScript 6.0.3 with ESM modules
- Build Tool: esbuild 0.28.0
- Email: Nodemailer 8.0.9
- HTTP Client: Axios 1.16.1
- Security: CORS 2.8.6, Rate Limiting 8.5.2
- API Docs: Swagger UI 5.0.1 with OpenAPI 3.0
- Testing: Vitest 4.1.7
This is a multi-workspace project with separate frontend and backend modules, designed for independent development and deployment.
┌─────────────────────────────────────────────────────────┐
│ Production Docker Container │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Nginx (Port 80) │ │
│ │ ┌──────────────────┐ ┌──────────────────────┐ │ │
│ │ │ Static Files │ │ API Proxy │ │ │
│ │ │ (Vue 3 dist/) │ │ /api/* → backend:3000 │ │ │
│ │ └──────────────────┘ └──────────┬───────────┘ │ │
│ └───────────────────────────────────────┼────────────┘ │
│ │ │
│ ┌──────────────────────────────────────▼────────────┐ │
│ │ Backend API (Port 3000) │ │
│ │ • Express.js 5 with TypeScript │ │
│ │ • Email Service (Nodemailer) │ │
│ │ • Health Monitoring │ │
│ │ • CORS & Rate Limiting │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ PM2 Process Manager │
│ (nginx + backend with auto-restart) │
└─────────────────────────────────────────────────────────┘
homepage/
├── frontend/ # Vue 3 application
│ ├── src/
│ │ ├── components/ # Reusable Vue components
│ │ ├── views/ # Page components
│ │ ├── router/ # Vue Router configuration
│ │ ├── services/ # API service layer
│ │ ├── helpers/ # Utility functions & composables
│ │ ├── types/ # TypeScript type definitions
│ │ └── assets/ # Static assets (images, styles)
│ ├── tests/ # Vitest tests
│ ├── vite.config.ts # Vite build configuration
│ └── package.json # Frontend dependencies
│
├── backend/ # Express.js API
│ ├── src/
│ │ ├── routes/ # API route handlers
│ │ ├── services/ # Business logic
│ │ ├── middleware/ # Express middleware
│ │ ├── types/ # TypeScript interfaces
│ │ ├── config/ # Environment configuration
│ │ └── app.ts # Application entry point
│ ├── tests/ # Vitest + Supertest tests
│ ├── tsconfig.json # TypeScript configuration
│ └── package.json # Backend dependencies
│
├── Dockerfile # Multi-stage production build
├── docker-compose.yml # Container orchestration
├── nginx.conf # Nginx web server config
├── ecosystem.config.cjs # PM2 process management
├── sonar-project.properties # SonarCloud configuration
└── Homepage.code-workspace # VS Code workspace
| Technology | Version | Required |
|---|---|---|
| Node.js | 24.x | ✅ |
| npm | 10.x+ | ✅ |
| Docker | 20+ | 🔧 Optional |
Note: The frontend toolchain targets Node.js 24+. The backend supports Node.js 18+ (see backend/package.json engines).
git clone https://github.com/Toomas633/homepage.git
cd homepagecd frontend
cp .env.example .env
# Edit .env with your configuration
npm install
npm run dev
# Frontend runs on http://localhost:5173cd backend
cp .env.example .env
# Edit .env with SMTP credentials
npm install
npm run dev
# Backend runs on http://localhost:3000Visit http://localhost:5173 to see the application.
For containerized deployment with both frontend and backend:
# Using docker-compose (recommended)
docker-compose up -d
# Or manual build
docker build -t toomas633-dungeon .
docker run -d -p 80:80 --env-file backend/.env toomas633-dungeonSee Docker Deployment section below for detailed instructions, or docs/DEPLOYMENT.md for production deployment guide.
This project uses a multi-folder VS Code workspace. Open Homepage.code-workspace in VS Code for optimal development experience with module-specific settings.
cd frontend
# Install dependencies
npm install
# Development server with hot reload (port 5173)
npm run dev
# Build for production
npm run build
# Preview production build
npm run serve
# Linting & formatting
npm run lint
npm run stylelint
npm run prettier
npm run type-checkKey Files:
vite.config.ts- Build configuration with pluginssrc/main.ts- Application entry pointsrc/router/- Vue Router configurationsrc/plugins/vuetify.ts- Vuetify setup
See Frontend Documentation for detailed patterns and conventions, or frontend/.github-copilot-instructions.md for AI-assisted development patterns.
cd backend
# Install dependencies
npm install
# Development with hot reload (tsx watch)
npm run dev
# Build TypeScript to JavaScript
npm run build
# Start production server
npm start
# Linting & formatting
npm run lint
npm run prettier
npm run type-checkKey Files:
src/app.ts- Express application setupsrc/routes/- API endpoint handlerssrc/middleware/- CORS, rate limiting, etc.src/services/- Business logic services
See Backend Documentation for detailed patterns and conventions, or backend/.github-copilot-instructions.md for AI-assisted development patterns.
- Start backend:
cd backend && npm run dev - Start frontend:
cd frontend && npm run dev - Make changes with hot reload
- Run tests:
npm run testin respective directory - Check quality:
npm run lintandnpm run type-check - Build:
npm run buildbefore committing
Both frontend and backend use Vitest for unit and integration testing with comprehensive coverage reporting.
cd frontend
# Run tests in watch mode (interactive)
npm run test
# Run with coverage report
npm run test:coveragecd backend
# Run tests in watch mode (interactive)
npm run test
# Run with coverage report
npm run test:coverage- Framework: Vitest + Vue Test Utils + happy-dom
- Location:
frontend/tests/directory - Setup:
tests/setup.tswith Vuetify stubs - Config:
vitest.config.tswith Vue plugin support
Example Test Files:
tests/helpers/isBot.spec.ts- Utility function teststests/App.spec.ts- Component testing exampletests/services/- Service layer tests
- Framework: Vitest + Supertest for API testing
- Location:
backend/tests/directory - Setup:
tests/setup.tsfor global configuration - Config:
vitest.config.tsfor Node.js environment
Example Test Files:
tests/routes/health.spec.ts- API endpoint tests with supertesttests/services/emailService.spec.ts- Service tests with mockingtests/middleware/- Middleware unit tests
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
describe('MyComponent', () => {
it('renders with props', () => {
const wrapper = mount(MyComponent, {
props: { title: 'Test Title' }
})
expect(wrapper.text()).toContain('Test Title')
})
})import { describe, it, expect } from 'vitest'
import request from 'supertest'
import express from 'express'
import healthRouter from '@/routes/health'
describe('Health Route', () => {
it('returns health status', async () => {
const app = express()
app.use('/health', healthRouter)
const response = await request(app).get('/health')
expect(response.status).toBe(200)
expect(response.body.status).toBe('healthy')
})
})Coverage reports are generated in coverage/ with multiple formats:
- Console: Summary output after test run
- HTML: Interactive report at
coverage/index.html - LCOV:
coverage/lcov.infofor SonarCloud integration - JSON: Programmatic access via
coverage/coverage-final.json
Coverage Exclusions:
- Test files (
**/*.spec.ts,**/*.test.ts) - Type definitions (
**/*.d.ts) - Configuration and setup files
Tests run automatically in GitHub Actions:
- SonarCloud Workflow: Runs tests with coverage on push/PR
- Quality Gates: Coverage thresholds enforced by SonarCloud
- Multi-module: Separate coverage reports for frontend and backend
The application supports containerized deployment with a multi-stage Docker build that combines both frontend and backend services.
The Docker container runs:
- Nginx (Port 80) - Serves frontend static files and proxies API requests
- Backend API (Port 3000) - Express.js server
- PM2 - Process manager for both services with auto-restart
# Build and start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down# Build the image
docker build -t toomas633-dungeon .
# Run the container
docker run -d \
--name toomas633-dungeon \
-p 80:80 \
-p 3000:3000 \
--env-file backend/.env \
--restart unless-stopped \
toomas633-dungeon
# View logs
docker logs -f toomas633-dungeonCreate a .env file in the root directory (or use backend/.env):
# Email service configuration
EMAIL_HOST=smtp.gmail.com
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
EMAIL_TO=recipient@example.com
# CORS configuration
ALLOWED_ORIGINS=https://yourdomain.com,http://localhost:5173Default ports:
- 80: Frontend (Nginx) and API proxy
- 3000: Backend API direct access
Custom ports:
docker run -p 8080:80 -p 3001:3000 ...The Dockerfile uses multi-stage builds for optimization:
- Frontend Build: Compiles Vue 3 app with Vite
- Backend Build: Compiles TypeScript to JavaScript
- Production: Combines both with Nginx and PM2
Features:
- Uses
node:24-alpinefor minimal image size - Non-root user (
appuser) for security - Health checks built-in
- Optimized layer caching
# Via Nginx proxy
curl http://localhost/api/health
# Direct backend access
curl http://localhost:3000/api/healthHealthy Response:
{
"status": "healthy",
"timestamp": "2025-11-23T12:00:00.000Z",
"version": "2.1.0",
"email": {
"status": "connected",
"responseTime": "150ms"
}
}Built-in Docker health monitoring:
# Check container health status
docker inspect --format='{{.State.Health.Status}}' toomas633-dungeon
# View health check logs
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' toomas633-dungeonHealth check configuration:
- Interval: 30 seconds
- Timeout: 10 seconds
- Retries: 3
- Start Period: 40 seconds
# Start/stop/restart
docker start toomas633-dungeon
docker stop toomas633-dungeon
docker restart toomas633-dungeon
# Remove container
docker rm toomas633-dungeon
# View logs (follow mode)
docker logs -f toomas633-dungeon
# Shell access
docker exec -it toomas633-dungeon /bin/bash# List running processes
docker exec toomas633-dungeon pm2 list
# View process logs
docker exec toomas633-dungeon pm2 logs
# Process details
docker exec toomas633-dungeon pm2 show backend
docker exec toomas633-dungeon pm2 show nginx
# Restart individual process
docker exec toomas633-dungeon pm2 restart backend
docker exec toomas633-dungeon pm2 restart nginx# Container logs
docker logs toomas633-dungeon
# Nginx logs (inside container)
docker exec toomas633-dungeon cat /var/log/nginx/access.log
docker exec toomas633-dungeon cat /var/log/nginx/error.log
# Running processes
docker exec toomas633-dungeon ps aux# Check container logs
docker logs toomas633-dungeon
# Inspect container details
docker inspect toomas633-dungeon
# Check port conflicts (PowerShell)
netstat -ano | findstr :80
netstat -ano | findstr :3000# Test health endpoint
curl http://localhost/api/health
curl http://localhost:3000/api/health
# Verify processes
docker exec toomas633-dungeon pm2 list
# Check nginx configuration
docker exec toomas633-dungeon nginx -t# View backend logs
docker exec toomas633-dungeon pm2 logs backend
# Check environment variables
docker exec toomas633-dungeon env | findstr EMAILVerify SMTP credentials are correct in your .env file. Common issues:
- Incorrect SMTP host or port
- Invalid authentication credentials
- Firewall blocking SMTP traffic (port 587)
- 2FA requiring app-specific password
# Using docker-compose
docker-compose down
docker-compose up -d --build
# Manual rebuild
docker stop toomas633-dungeon
docker rm toomas633-dungeon
docker build -t toomas633-dungeon .
docker run -d --name toomas633-dungeon -p 80:80 --env-file backend/.env toomas633-dungeon# Remove unused images
docker image prune
# Remove all stopped containers
docker container prune
# Full cleanup (careful!)
docker system prune -a- ✅ Use reverse proxy (Traefik, Caddy, Nginx Proxy Manager) for HTTPS
- ✅ Configure proper logging and log rotation
- ✅ Use Docker secrets or vault for sensitive credentials
- ✅ Set up automated backups
- ✅ Configure container restart policies
- ✅ Monitor health checks and set up alerts
- ✅ Use specific version tags instead of
latest
version: '3.8'
services:
app:
image: toomas633-dungeon:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`toomas633.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
env_file: backend/.env
restart: unless-stopped
networks:
- traefikLocated in frontend/.env:
| Variable | Description | Required | Example |
|---|---|---|---|
VITE_API_URL |
Backend API endpoint | ✅ | http://localhost:3000/api |
Located in backend/.env:
| Variable | Description | Required | Example |
|---|---|---|---|
EMAIL_HOST |
SMTP server hostname | ✅ | smtp.gmail.com |
EMAIL_USER |
SMTP username | ✅ | info@example.com |
EMAIL_PASS |
SMTP password/app password | ✅ | your-app-password |
EMAIL_TO |
Recipient email | ✅ | admin@example.com |
EMAIL_PORT |
SMTP server port | ✅ | 587 |
EMAIL_TLS |
Use TLS/STARTTLS (true/false) | ✅ | true |
ALLOWED_ORIGINS |
CORS allowed origins (comma-sep) | ✅ | http://localhost:5173,https://example.com |
GITHUB_TOKEN |
GitHub API token (optional) | ❌ | ghp_xxxxxxxxxxxxxxxxxxxx |
| Endpoint | Method | Description | Rate Limit |
|---|---|---|---|
/health |
GET | Server health status | 60 req / 1 min |
/api/health |
GET | Health check (via Nginx) | 60 req / 1 min |
/api/send-email |
POST | Send contact form email | 10 req / 15 min |
/api/github |
POST | Get GitHub repository info | 60 req / 1 min |
For detailed API documentation with request/response examples, see docs/API.md.
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Install dependencies in both modules
- Make changes following project conventions
- Test thoroughly:
npm run testandnpm run test:coverage - Lint your code:
npm run lintandnpm run prettier - Type check:
npm run type-check - Build to verify:
npm run build - Commit with clear messages
- Push and create a Pull Request
For detailed contribution guidelines, coding standards, and development workflow, see CONTRIBUTING.md.
- ✅ TypeScript strict mode enabled
- ✅ ESLint for code linting
- ✅ Prettier for code formatting
- ✅ Vitest for testing (maintain >80% coverage)
- ✅ SonarCloud quality gates must pass
- ✅ Follow existing patterns and conventions
- Frontend: See frontend/.github-copilot-instructions.md
- Backend: See backend/.github-copilot-instructions.md
- CONTRIBUTING.md - Contribution guidelines and development workflow
- CHANGELOG.md - Version history and release notes
- Frontend Documentation - Vue 3 setup, components, and patterns
- Backend Documentation - Express.js API, services, and middleware
- API Documentation - Complete API reference with code examples
- Deployment Guide - Production deployment (Docker, VPS, SSL/TLS)
- Troubleshooting Guide - Common issues and solutions
- Docker Linting - Docker best practices and linting
- Nginx Configuration - Web server and proxy settings
- PM2 Configuration - Process management setup
- Docker Compose - Container orchestration
- SonarCloud Project - Code quality dashboard
- Live Site: toomas633.com
- GitHub Repository: Toomas633/homepage
- Vue.js Documentation: vuejs.org
- Vuetify Documentation: vuetifyjs.com
- Express.js Documentation: expressjs.com
- Vitest Documentation: vitest.dev
This project is licensed under the GPL-3.0-only License - see the LICENCE file for details.
Built with modern web technologies:
- Vue.js 3 & Vuetify 4 for the frontend
- Node.js & Express.js for the backend
- TypeScript for type safety
- Vitest for testing
- Docker for containerization
- Nginx for web serving
- PM2 for process management
Made with ❤️ by Toomas633