refactor: move Gradle wrapper to repo root, add convenience tasks

Move gradlew, gradle/wrapper, and settings.gradle from backend/ to
the repo root so build commands run from the top-level directory.
This follows the standard multi-project Gradle layout where the build
tool lives alongside docker-compose.yml and all submodules.

- Move gradlew + gradle/wrapper/* from backend/ to repo root
- Move settings.gradle to root with rootProject.name and include 'backend'
- Create root build.gradle with convenience tasks: check, up, down, reset
- check task chains frontend lint → frontend test → backend check
- Update docker-compose.yml backend volume from ./backend:/app to .:/app
- Update backend.Dockerfile entrypoint to ./gradlew :backend:bootRun
- Update AGENTS.md: document ./gradlew check, up, down, reset
- Delete backend/settings.gradle (now at root)
- Add .gradle/ and build/ to .gitignore
- Add !gradle/wrapper/gradle-wrapper.jar exception (blocked by *.jar rule)

All 38 frontend tests and 33 backend tests pass via ./gradlew check.
This commit is contained in:
Joakim Mörling 2026-05-01 18:40:18 +02:00
parent 4c6094446b
commit d70196112d
9 changed files with 68 additions and 8 deletions

4
.gitignore vendored
View file

@ -39,6 +39,10 @@ Thumbs.db
docker-compose.override.yml docker-compose.override.yml
certs/ certs/
# Gradle
.gradle/
build/
# Java # Java
*.hprof *.hprof

View file

@ -24,11 +24,23 @@ PostgreSQL 16. Deployed via Docker Compose.
Always run these after making changes to verify nothing is broken. Always run these after making changes to verify nothing is broken.
Gradle lives at repo root. All commands below run from the repo root unless noted.
### Quick start (everything) ### Quick start (everything)
```bash ```bash
cp .env.example .env # first time only, then fill in keys cp .env.example .env # first time only, then fill in keys
docker compose up -d # starts postgres, backend, frontend docker compose up -d # starts postgres, backend, frontend
./gradlew up # same as above (Gradle wrapper)
```
### All-in-one
```bash
./gradlew check # frontend lint → frontend test → backend test → integration test
./gradlew up # docker compose up -d
./gradlew down # docker compose down
./gradlew reset # docker compose down -v && docker compose up -d (full DB reset)
``` ```
### Frontend (Vue.js 3 + Vite) ### Frontend (Vue.js 3 + Vite)
@ -45,10 +57,8 @@ npm run test # vitest
### Backend (Spring Boot 4 + Java 21) ### Backend (Spring Boot 4 + Java 21)
```bash ```bash
cd backend ./gradlew :backend:bootRun # dev server on :8080
./gradlew bootRun # dev server on :8080 ./gradlew :backend:test # JUnit 5 + Mockito (backend only)
./gradlew test # JUnit 5 + Mockito
./gradlew check # full verification including integration tests
``` ```
### Stripe webhooks (local testing) ### Stripe webhooks (local testing)
@ -80,7 +90,8 @@ bilhej/
│ │ ├── router/ # Vue Router config │ │ ├── router/ # Vue Router config
│ │ └── assets/ # Static files, CSS │ │ └── assets/ # Static files, CSS
│ └── ... │ └── ...
├── backend/ # Spring Boot 4 (Java 21) ├── backend/ # Spring Boot 4 (Java 21) — Gradle subproject
│ ├── build.gradle # Spring Boot plugin, Java deps, test config
│ ├── src/main/java/se/bilhalsning/ │ ├── src/main/java/se/bilhalsning/
│ │ ├── config/ # @Configuration classes │ │ ├── config/ # @Configuration classes
│ │ ├── controller/ # REST controllers │ │ ├── controller/ # REST controllers
@ -96,7 +107,7 @@ bilhej/
│ ├── application-docker.yml # docker profile (PostgreSQL) │ ├── application-docker.yml # docker profile (PostgreSQL)
│ └── db/migration/ # Flyway migrations │ └── db/migration/ # Flyway migrations
├── docker/ # Dockerfiles ├── docker/ # Dockerfiles
│ ├── backend.Dockerfile # dev: JDK 21 + gradle bootRun │ ├── backend.Dockerfile # dev: JDK 21 + gradle :backend:bootRun
│ ├── backend.prod.Dockerfile # prod: multi-stage (Gradle build → JRE Alpine, non-root) │ ├── backend.prod.Dockerfile # prod: multi-stage (Gradle build → JRE Alpine, non-root)
│ ├── frontend.Dockerfile # dev: Node 24 + vite dev server │ ├── frontend.Dockerfile # dev: Node 24 + vite dev server
│ ├── frontend.prod.Dockerfile # prod: multi-stage (Node build → nginx) │ ├── frontend.prod.Dockerfile # prod: multi-stage (Node build → nginx)
@ -104,6 +115,11 @@ bilhej/
│ └── entrypoint.sh # prod: self-signed cert generation │ └── entrypoint.sh # prod: self-signed cert generation
├── docker-compose.yml # dev: postgres + backend (bootRun) + frontend (Vite HMR) ├── docker-compose.yml # dev: postgres + backend (bootRun) + frontend (Vite HMR)
├── docker-compose.prod.yml # prod: multi-stage images, no source mounts, restart always ├── docker-compose.prod.yml # prod: multi-stage images, no source mounts, restart always
├── gradlew # Gradle wrapper (repo root)
├── gradle/
│ └── wrapper/
├── settings.gradle # rootProject.name + include 'backend'
├── build.gradle # convenience tasks: check, up, down, reset
├── .env.example ├── .env.example
├── AGENTS.md # This file ├── AGENTS.md # This file
├── README.md ├── README.md

38
build.gradle Normal file
View file

@ -0,0 +1,38 @@
plugins {
id 'base'
}
tasks.register('frontendLint', Exec) {
description = 'Run ESLint in the frontend directory'
workingDir = file("${rootProject.projectDir}/frontend")
commandLine 'npm', 'run', 'lint'
}
tasks.register('frontendTest', Exec) {
description = 'Run Vitest in the frontend directory'
dependsOn frontendLint
workingDir = file("${rootProject.projectDir}/frontend")
commandLine 'npm', 'run', 'test'
}
tasks.named('check').configure {
dependsOn frontendLint, frontendTest
}
tasks.register('up', Exec) {
description = 'Start all services via Docker Compose'
workingDir = rootProject.projectDir
commandLine 'docker', 'compose', 'up', '-d'
}
tasks.register('down', Exec) {
description = 'Stop all Docker Compose services'
workingDir = rootProject.projectDir
commandLine 'docker', 'compose', 'down'
}
tasks.register('reset', Exec) {
description = 'Wipe database and restart all services'
workingDir = rootProject.projectDir
commandLine 'bash', '-c', 'docker compose down -v && docker compose up -d'
}

View file

@ -36,7 +36,7 @@ services:
postgres: postgres:
condition: service_healthy condition: service_healthy
volumes: volumes:
- ./backend:/app - .:/app
- gradle-cache:/root/.gradle - gradle-cache:/root/.gradle
frontend: frontend:

View file

@ -1,3 +1,3 @@
FROM eclipse-temurin:21-jdk FROM eclipse-temurin:21-jdk
WORKDIR /app WORKDIR /app
ENTRYPOINT ["./gradlew", "bootRun", "--no-daemon"] ENTRYPOINT ["./gradlew", ":backend:bootRun", "--no-daemon"]

View file

View file

@ -1 +1,3 @@
rootProject.name = 'bilhej' rootProject.name = 'bilhej'
include 'backend'