Full-stack monorepo: Vue 3 + Vite frontend, Spring Boot 3.3 (Java 21) backend. JWT auth, PostgreSQL, Flyway, OpenAPI, Docker Compose. Zero external account dependencies.
# Create project from template
gh repo create my-app --template faizkhairi/vue-springboot-boilerplate --private --clone
cd my-app- Backend: Spring Boot 3.3, Spring Security + JWT (access + refresh), Spring Data JPA, Flyway, Spring Mail + Thymeleaf, springdoc-openapi
- Frontend: Vue 3, Vite, Pinia, Vue Router, Tailwind; Axios with 401 refresh retry
- Testing: Backend JUnit 5 + Testcontainers (PostgreSQL); Frontend Vitest (unit), Playwright (e2e)
- Docker: PostgreSQL + Mailpit; optional backend + frontend Dockerfiles and Compose services
cd backend
# Ensure Java 21 and Gradle are installed, or use ./gradlew
./gradlew bootRun
# Or: export DATABASE_URL=jdbc:postgresql://localhost:5432/vue_springboot && ./gradlew bootRun- API: http://localhost:8080
- Swagger UI: http://localhost:8080/swagger-ui.html
cd frontend
pnpm install
pnpm devOption A — PostgreSQL + Mailpit only (run backend/frontend on host):
cd docker
docker compose up -d postgres mailpit
# Backend: DATABASE_URL=jdbc:postgresql://localhost:5432/vue_springboot
# Mailpit UI: http://localhost:8025Option B — Full stack (backend + frontend in containers):
cd docker
docker compose up -d
# Frontend: http://localhost (port 80)
# Backend API: http://localhost:8080
# Mailpit UI: http://localhost:8025Backend (application.yml / env):
DATABASE_URL,DATABASE_USER,DATABASE_PASSWORDJWT_SECRET(min 256-bit for HS256)SMTP_HOST,SMTP_PORT(dev: localhost:1025 for Mailpit)APP_URL,SMTP_FROM(for email links and sender)
Frontend:
VITE_API_BASE_URL— backend base URL (e.g. http://localhost:8080)
The backend uses springdoc-openapi to automatically generate OpenAPI 3.0 documentation from Spring annotations.
Access Swagger UI:
- Start the backend:
cd backend && ./gradlew bootRun - Navigate to: http://localhost:8080/swagger-ui.html
- Explore all available endpoints with request/response schemas
OpenAPI JSON Spec:
- Available at: http://localhost:8080/v3/api-docs
- Use this spec for client code generation (e.g., TypeScript Axios client via
openapi-generator-cli)
Key Endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/auth/login |
POST | Authenticate with email/password, returns JWT tokens |
/api/auth/register |
POST | Create new user account |
/api/auth/refresh |
POST | Refresh access token using refresh token |
/api/users/me |
GET | Get authenticated user profile |
Authentication:
Most endpoints require a valid JWT access token. In Swagger UI:
- Use
/api/auth/loginto get tokens - Copy the
accessTokenfrom the response - Click "Authorize" button at the top
- Enter:
Bearer {accessToken} - All subsequent requests will include the token
Backend (SLF4J + Logback):
- Logs are written to
logs/application.log(rolling daily, 30-day retention) - Audit events (auth, security) are logged to
logs/audit.log(90-day retention) - Log levels: DEBUG (dev), INFO (prod) — configured in
logback-spring.xml
Frontend (Structured Logger):
- Development: logs to browser console with timestamps
- Production: logs can be sent to backend or third-party service (see
src/utils/logger.ts)
- Backend:
cd backend && ./gradlew test(JUnit 5 + Testcontainers PostgreSQL). CI runs build with-x test; run tests locally. - Frontend:
cd frontend && npm run test(Vitest),npm run test:e2e(Playwright; run dev server or setPLAYWRIGHT_BASE_URL).
backend/ — Spring Boot (Java 21, Gradle), Dockerfile
frontend/ — Vue 3 + Vite, Pinia, Vue Router, Dockerfile, Vitest, Playwright
docker/ — docker-compose (PostgreSQL, Mailpit, optional backend + frontend)
Faiz Khairi — faizkhairi.github.io — @faizkhairi