No description
Find a file
2026-05-29 17:55:31 +00:00
deploy Repo now this 2026-03-08 03:12:21 +00:00
gradle/wrapper Bootstrap Spring Boot authentication service 2026-01-03 16:30:05 -07:00
src FEATURE - Auth improvements 2026-05-29 17:55:31 +00:00
.env.example Repo deployment 2026-03-07 21:39:20 +00:00
.gitattributes Bootstrap Spring Boot authentication service 2026-01-03 16:30:05 -07:00
.gitignore Repo deployment 2026-03-07 21:39:20 +00:00
.gitlab-ci.yml Increase test coverage 2026-03-15 00:11:03 +00:00
build.gradle FEATURE - Auth improvements 2026-05-29 17:55:31 +00:00
CLAUDE.md Delete old migration files 2026-02-14 19:32:19 -07:00
docker-compose.yml Repo now this 2026-03-08 03:12:21 +00:00
Dockerfile Don't produce plain JAR at all 2026-03-06 23:09:35 -07:00
gradlew Bootstrap Spring Boot authentication service 2026-01-03 16:30:05 -07:00
gradlew.bat Bootstrap Spring Boot authentication service 2026-01-03 16:30:05 -07:00
guitartech-auth-service.code-workspace Enable spotless and Google Java Format 2026-01-24 10:43:27 -07:00
PLAN.md Working controllers 2026-02-07 21:48:36 -07:00
README.md Repo fail on low coverage 2026-03-08 05:15:10 +00:00
settings.gradle Bootstrap Spring Boot authentication service 2026-01-03 16:30:05 -07:00

guitartech-auth-service

A Spring Boot 4.0.1 REST API for user authentication and management. Implements JWT-based authentication with user registration, login, and profile management endpoints.

Quick Start

Prerequisites

  • JDK 21+
  • PostgreSQL 16 (running locally or via Docker)
  • Gradle (included via wrapper: ./gradlew)

Local Development

  1. Set up environment variables:

    source .env.local
    

    This loads JWT_SECRET and DB_PASSWORD for local development.

  2. Start PostgreSQL:

    docker run -d \
      --name guitartech-postgres \
      -e POSTGRES_DB=guitartech_auth_service \
      -e POSTGRES_PASSWORD=postgres \
      -p 5432:5432 \
      postgres:16-alpine
    
  3. Run the application: Using the Spring Boot Dashboard extension in VS Code:

    • Source .env.local in your terminal: source .env.local
    • Click the run button in the Dashboard

    Or via CLI:

    source .env.local
    ./gradlew bootRun
    
  4. Verify it's running:

    curl http://localhost:8080/actuator/health
    

The application will automatically apply Liquibase database migrations on startup.

API Endpoints

Public Endpoints

  • POST /api/auth/register — Register a new user

    {
      "username": "john_doe",
      "password": "SecurePass123!",
      "email": "john@example.com"
    }
    
  • POST /api/auth/login — Authenticate and get JWT token

    {
      "usernameOrEmail": "john_doe",
      "password": "SecurePass123!"
    }
    

Protected Endpoints (Require JWT Bearer Token)

  • PUT /api/users/{id} — Update your profile
    Authorization: Bearer <jwt-token>
    

Building & Testing

./gradlew clean build          # Full clean build
./gradlew build -x test        # Build without tests
./gradlew test                 # Run all tests
./gradlew test --tests SomeTest # Run a specific test

Tests use Testcontainers with a real PostgreSQL database (containerized), not an in-memory DB.

macOS Note: For best performance with Testcontainers, use Orbstack instead of Docker Desktop. Orbstack is lightweight, faster, and handles container networking better on macOS.

Environment Variables

Create a .env.local file (git-ignored) with:

export JWT_SECRET="your-secret-min-64-chars"
export DB_PASSWORD="postgres"

Or set them directly:

JWT_SECRET=my-secret DB_PASSWORD=postgres ./gradlew bootRun

For Deployed Environments

The app reads these environment variables at runtime:

  • JWT_SECRET — JWT signing secret (required in production)
  • SPRING_DATASOURCE_URL — Database URL (defaults to localhost)
  • SPRING_DATASOURCE_USERNAME — Database user
  • SPRING_DATASOURCE_PASSWORD — Database password

Database

Local Setup

The default application.properties connects to:

jdbc:postgresql://localhost:5432/guitartech_auth_service
username: postgres
password: postgres

Start PostgreSQL with the Docker command above, and migrations run automatically on app startup.

Resetting the Database Locally

# Connect to PostgreSQL
psql -U postgres -d guitartech_auth_service

# Drop tables to reset
DROP TABLE auth_user CASCADE;
DROP TABLE database_changelog CASCADE;
DROP TABLE database_changelog_lock CASCADE;

Then restart the app — migrations will re-apply.

Security

This project uses GitLab's free SAST (Static Application Security Testing) to automatically scan for vulnerabilities:

  • Semgrep — Scans Java source code for security issues and code quality problems
  • SpotBugs — Detects common Java bugs
  • Runs on all merge requests and branches before code can be merged
  • Results appear in the Merge Request pipeline UI

To view SAST reports:

  1. Go to your merge request in GitLab
  2. Click the Checks or Pipeline tab
  3. Look for SAST job details and any detected issues

Deployment

This service deploys to production only via GitLab CI/CD:

  • Production (guitartech.app) — Manual deployment to VPS (requires manual trigger in GitLab pipeline)

The pipeline automatically runs:

  1. Build — Compiles code
  2. Test — Runs tests + SAST security scanning
  3. Containerize — Builds Docker image
  4. Publish — Pushes image to registry (main branch only)
  5. Deploy — Manual production deployment (main branch only)

Local Development: Run locally with source .env.local && ./gradlew bootRun

Production Setup: Runs in Docker Compose on a 2GB VPS with Postgres. See docker-compose.yml for configuration.

Project Structure

src/main/java/tech/guitar/auth/
├── GuitartechAuthServiceApplication.java  # Entry point
├── config/SecurityConfig.java             # Spring Security + JWT config
├── controller/                            # REST endpoints
├── service/                               # Business logic
├── repository/                            # Data access (JPA)
├── entity/                                # JPA entities
├── dto/                                   # Request/response DTOs
├── filter/                                # JWT validation filter
├── mapper/                                # Entity converters
└── exception/                             # Error handling

src/main/resources/
├── application.properties                 # Configuration
└── db/changelog/                          # Liquibase migrations

src/test/
├── AbstractIntegrationTest.java          # Base test class
├── repository/                           # Repository tests
└── testutil/                             # Test utilities

Key Features

  • JWT Authentication — HS512 algorithm, 24-hour expiration
  • Password Security — BCrypt hashing (strength factor 12)
  • Input Validation — DTO-level with Jakarta validation annotations
  • Database Migrations — Liquibase with UTC timestamps
  • Global Exception Handling — Consistent error responses
  • Comprehensive Tests — Integration tests with real DB

Development Workflow

  1. Create a feature branch off main
  2. Write tests first (repository, service, controller layers)
  3. Implement the feature
  4. Run all tests locally: ./gradlew test
  5. Open a merge request
  6. GitLab CI automatically runs:
    • Build: Compiles code
    • Test: Runs unit/integration tests + SAST security scanning
    • Containerize: Builds Docker image
    • All must pass before merge
  7. Merge to main once approved
  8. Publish: Image is pushed to GitLab Container Registry
  9. Manually trigger production deployment from the GitLab pipeline UI (only available for main branch)

Test Coverage

The project enforces 80% minimum code coverage on the main branch:

  • On main branch: Pipeline fails if coverage drops below 80%
  • On merge requests: Coverage below 80% is flagged as a warning (doesn't block merge)
  • View locally: ./gradlew jacocoTestReport to generate coverage report

This ensures code quality stays consistent while allowing flexibility during feature development on branches.

Useful Commands

# Format and check code
./gradlew spotlessApply      # Auto-format code

# View test coverage
./gradlew jacocoTestReport

# Clean up everything
./gradlew clean

# Run integration tests only
./gradlew test -i integration

Troubleshooting

"Could not connect to PostgreSQL"

  • Ensure PostgreSQL is running: docker ps | grep postgres
  • Check credentials match .env.local or application.properties

"JWT_SECRET is not set"

  • Run source .env.local before starting the app
  • Or set: export JWT_SECRET=<value>

"Liquibase migration failed"

  • Check database permissions and connectivity
  • Review migration files in src/main/resources/db/changelog/migrations/

Support

For issues or questions, refer to CLAUDE.md for detailed architecture and testing guidelines.