MTG Search - Magic The Gathering Card Search Platform
A full-stack web application for searching and exploring Magic The Gathering cards with user authentication, built with Spring Boot, Vue.js, PostgreSQL, and deployed with Docker.
Architecture Overview
├── Backend (Java 21, Spring Boot 3.2.5)
│ ├── REST API with OpenAPI/Swagger documentation
│ ├── JWT-based authentication
│ ├── PostgreSQL database with jOOQ ORM
│ ├── Flyway database migrations
│ ├── Comprehensive logging with Logback
│ └── JUnit 5 and integration tests
│
├── Frontend (Vue 3, TypeScript, Vite)
│ ├── Single Page Application (SPA)
│ ├── Responsive UI with CSS Grid/Flexbox
│ ├── Pinia state management
│ ├── Vue Router with auth guards
│ └── Axios HTTP client with JWT interceptors
│
├── Database (PostgreSQL 16)
│ ├── Schema managed by Flyway migrations
│ ├── jOOQ-generated DTOs and repositories
│ └── Indexed queries for performance
│
└── Deployment
├── Docker multi-stage build
├── Docker Compose for local dev
└── GitLab CI/CD pipeline
Prerequisites
- Java 21 or later
- Node.js 20+ and npm 10+
- PostgreSQL 16+
- Docker & Docker Compose (for containerized setup)
- Git
Quick Start
Using Docker Compose (Recommended)
# Clone the repository
git clone <repository-url>
cd mtg-search
# Start all services (PostgreSQL, Backend, built Frontend)
docker-compose up --build
# Backend will be available at: http://localhost:8080
# Frontend will be served by the backend
Local Development Setup
1. Database Setup
# Start PostgreSQL (using Docker)
docker run --name mtgsearch-postgres \
-e POSTGRES_DB=mtgsearch \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
-d postgres:16-alpine
# Or use your local PostgreSQL installation
2. Backend Setup
cd backend
# Build the project
../gradlew build
# Run the application
../gradlew bootRun
# Backend starts on http://localhost:8080
# Swagger UI available at: http://localhost:8080/swagger-ui.html
# API Docs available at: http://localhost:8080/v3/api-docs
3. Frontend Setup
cd frontend
# Install dependencies
npm install
# Start development server
npm run dev
# Frontend starts on http://localhost:5173
API Endpoints
Authentication
-
POST
/api/v1/auth/register- Register a new user{ "username": "john_doe", "email": "john@example.com", "password": "SecurePassword123!" } -
POST
/api/v1/auth/login- Login and get JWT token{ "username": "john_doe", "password": "SecurePassword123!" }Returns:
{ "token": "eyJhbGc...", "id": 1, "username": "john_doe", "email": "john@example.com" } -
GET
/api/v1/auth/health- Health check (no auth required)
Protected Endpoints
All protected endpoints require JWT token in Authorization header:
Authorization: Bearer <token>
Building
Build Backend
./gradlew clean build
# Build outputs to: backend/build/libs/
Build Frontend
cd frontend
npm run build
# Build outputs to: backend/src/main/resources/static/
Build Full Docker Image
docker build -t mtgsearch:latest .
Testing
Backend Unit Tests
./gradlew test
Backend Integration Tests
./gradlew integrationTest
Frontend Tests
cd frontend
npm run test
npm run test:ui # Opens UI dashboard
All Tests with Coverage
./gradlew test jacocoTestReport
Configuration
Environment Variables
Create a .env file in the project root:
# Database
DB_URL=jdbc:postgresql://localhost:5432/mtgsearch
DB_USER=postgres
DB_PASSWORD=postgres
# JWT
JWT_SECRET=your-secret-key-change-in-production
JWT_EXPIRATION=86400
# Frontend
VITE_API_URL=http://localhost:8080
Application Properties
Backend configuration in backend/src/main/resources/application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mtgsearch
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: validate
app:
jwt:
secret: ${JWT_SECRET:your-secret-key}
expiration: ${JWT_EXPIRATION:86400}
Database Migrations
Migrations are managed by Flyway and located in backend/src/main/resources/db/migration/
Adding a New Migration
- Create a new file:
V2__Add_new_table.sql - Write SQL migration
- Run application - Flyway will auto-apply migrations
Example migration:
-- V2__Add_cards_table.sql
CREATE TABLE IF NOT EXISTS cards (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Logging
Logs are configured in backend/src/main/resources/logback-spring.xml
- Log Location:
logs/mtg-search.log - Error Logs:
logs/mtg-search-error.log - Max File Size: 100MB
- Retention: 30 days
- Compression: Automatic gzip compression
View logs:
tail -f logs/mtg-search.log
tail -f logs/mtg-search-error.log
Development Workflow
Code Generation
The project uses OpenAPI Generator and jOOQ for code generation:
# Generate server stubs from OpenAPI spec
./gradlew openApiGenerate
# Generate jOOQ entities from database schema
./gradlew generateJooqCode
Code Quality
# Format code
./gradlew spotlessApply
# Run static analysis
./gradlew check
# Frontend linting
cd frontend
npm run lint
Deployment
Staging Deployment
git checkout develop
git merge feature-branch
git push origin develop
# GitLab CI will automatically build and deploy to staging
Production Deployment
git tag v0.2.0
git push origin v0.2.0
# GitLab CI will build, test, and deploy to production
Manual Deployment
# Build Docker image
docker build -t mtgsearch:v0.1.0 .
docker tag mtgsearch:v0.1.0 your-registry/mtgsearch:v0.1.0
# Push to registry
docker push your-registry/mtgsearch:v0.1.0
# Pull and run on server
docker pull your-registry/mtgsearch:v0.1.0
docker run -d \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://db-host:5432/mtgsearch \
-e SPRING_DATASOURCE_USERNAME=postgres \
-e SPRING_DATASOURCE_PASSWORD=secure-password \
-e JWT_SECRET=your-production-secret \
-p 8080:8080 \
--name mtgsearch \
your-registry/mtgsearch:v0.1.0
CI/CD Pipeline
The project includes a comprehensive GitLab CI/CD pipeline (.gitlab-ci.yml):
-
Build Stage
- Compiles Java backend
- Builds Vue.js frontend
- Caches dependencies
-
Test Stage
- Unit tests
- Integration tests with PostgreSQL
- Code quality checks
-
Docker Stage
- Builds multi-stage Docker image
- Pushes to registry
-
Deploy Stage
- Deploys to staging with manual trigger
- Deploys to production on version tags
Project Structure
mtg-search/
├── backend/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/net/moustos/mtgsearch/
│ │ │ │ ├── MtgSearchApplication.java
│ │ │ │ ├── config/
│ │ │ │ ├── controller/
│ │ │ │ ├── service/
│ │ │ │ ├── repository/
│ │ │ │ ├── model/
│ │ │ │ └── security/
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ ├── logback-spring.xml
│ │ │ └── db/migration/
│ │ └── test/
│ │ └── java/
│ └── build.gradle.kts
│
├── frontend/
│ ├── src/
│ │ ├── pages/
│ │ ├── components/
│ │ ├── services/
│ │ ├── stores/
│ │ ├── router/
│ │ ├── types/
│ │ ├── main.ts
│ │ └── App.vue
│ ├── public/
│ ├── index.html
│ ├── package.json
│ ├── vite.config.ts
│ └── tsconfig.json
│
├── gradle/
├── build.gradle.kts
├── settings.gradle.kts
├── gradle.properties
├── gradlew
├── gradlew.bat
│
├── Dockerfile
├── docker-compose.yml
├── .gitlab-ci.yml
├── .gitignore
└── README.md
Troubleshooting
Backend won't start
# Check if port 8080 is already in use
lsof -i :8080
# Check PostgreSQL is running
psql -U postgres -h localhost -d mtgsearch -c "SELECT 1;"
# View logs
tail -f logs/mtg-search.log
Frontend connection issues
- Check backend is running on 8080
- Check browser console for errors
- Verify CORS settings in SecurityConfig.java
Database migration failures
# Check migration status
./gradlew flywayInfo
# Repair migrations (use with caution)
./gradlew flywayRepair
# Clean database (WARNING: deletes all data)
./gradlew flywayClean
Docker build fails
# Clear Docker cache
docker system prune -a
# Rebuild with no cache
docker build --no-cache -t mtgsearch:latest .
Performance Optimization
Backend
- Connection pooling: HikariCP configured with 10 max connections
- Database indexing on frequently queried columns
- Flyway async migration setup
- Request caching headers
Frontend
- Code splitting with Vite
- Lazy route loading
- Production build minification
- Gzip compression
Database
- Query result caching
- Indexed columns for search operations
- Batch operations optimization
Security
- Password Hashing: BCrypt with strength 12
- JWT Tokens: Auth0 library with HMAC256
- CORS: Configured for development (update for production)
- HTTPS: Required for production deployment
- SQL Injection: Protected via parameterized queries with jOOQ
- CSRF: Disabled for API (JWT-based auth)
Contributing
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
License
MIT License - see LICENSE file for details
Support
For issues and questions:
- Open an issue on GitLab
- Check existing documentation
- Review API Swagger docs at
/swagger-ui.html
Roadmap
- Card search functionality with filters
- Deck building feature
- Social features (friends, sharing)
- Mobile app
- Advanced analytics
- Magic Online API integration
- Performance tuning for large datasets