Repository navigation
Architecture
Jens Gross edited this page Mar 31, 2026
·
2 revisions
| Component | Technology |
|---|---|
| Language | Java 25 |
| Framework | Spring Boot 4.x |
| Build | Maven |
| Admin UI | Thymeleaf (server-side rendering) |
| Database | MariaDB (prod/local/docker), H2 in-memory (dev) |
| Migrations | Flyway |
| Unit Tests | JUnit 5, Mockito |
| E2E Tests | Playwright, Jsoup |
| External API | Google Sheets API v4 |
org.ctc
├── admin
│ ├── controller # Admin CRUD controllers (Season, Matchday, Race, Team, Driver, ...)
│ └── dto # Form and display DTOs (CarForm, RaceForm, RaceResultForm, ...)
├── dataimport # CSV/Google Sheets import, fuzzy driver matching
│ ├── CsvImportController / CsvImportService
│ ├── GoogleSheetsService
│ ├── ScorecardParser
│ └── DriverMatchingService
├── domain
│ ├── model # JPA Entities
│ ├── repository # Spring Data JPA Repositories
│ └── service # Business logic (Scoring, Standings, Rankings, Playoffs, Swiss Pairing)
├── gt7sync # GT7 car/track scraping and sync
│ ├── Gt7ScraperService / Gt7SyncService
│ └── Gt7SyncController
└── sitegen # Static site generation for GitHub Pages
├── SiteGeneratorService
├── SiteGeneratorController
└── model # View models for generated pages
Season
└── Matchday
└── Race
└── RaceResult (per driver: position, quali, fastest lap)
Team
└── Team (sub-teams, self-referencing parent)
Driver (PSN ID, nickname)
└── SeasonDriver (driver ↔ season assignment with team)
MatchdayLineup (which drivers race on a given matchday)
Playoff (linked to Season)
└── PlayoffRound (round of 8, quarterfinal, semifinal, final, ...)
└── PlayoffMatchup (team vs team, best-of-legs)
| Entity | Purpose |
|---|---|
Car |
Gran Turismo car master data (name, manufacturer, GT7 ID, image) |
Track |
Gran Turismo track master data (name, GT7 ID, image) |
RaceAttachment |
Files or links attached to a race |
AttachmentType |
Enum: FILE, LINK |
SeasonFormat |
Enum: LEAGUE, SWISS |
Season ──1:N──> Matchday ──1:N──> Race ──1:N──> RaceResult
Season ──1:N──> SeasonDriver ──N:1──> Driver
Season ──1:N──> Playoff ──1:N──> PlayoffRound ──1:N──> PlayoffMatchup
Race ──N:1──> Track
Race ──1:N──> RaceAttachment
RaceResult ──N:1──> Driver
RaceResult ──N:1──> Car
Team ──1:N──> Team (sub-teams)
Matchday ──1:N──> MatchdayLineup ──N:1──> SeasonDriver
| Profile | Database | Port | Purpose |
|---|---|---|---|
dev |
H2 in-memory | 9090 | Development, tests |
dev,demo |
H2 in-memory | 9090 | Like dev, auto-imports all GT7 cars and tracks with images |
local |
MariaDB (localhost) | 9091 | Local MariaDB development |
docker |
MariaDB (container db) |
8080 | Docker Compose deployment |
prod |
Cloud DB (env vars) | 8080 | Production deployment |
OSIV is intentionally enabled (spring.jpa.open-in-view=true). The Hibernate session stays open until the HTTP request completes, allowing Thymeleaf templates to render lazy-loaded entity fields without requiring eager fetching or DTOs for every view. This is the correct approach for a server-side rendered admin application.
| Position | 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | 8th | 9th | 10th | 11th | 12th |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Points | 20 | 17 | 14 | 12 | 10 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
| Category | 1st | 2nd | 3rd |
|---|---|---|---|
| Qualifying | 3 | 2 | 1 |
| Fastest Lap | 2 | - | - |