Architecture - jegr78/ctc-manager GitHub Wiki
Architecture
Tech Stack
| 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 |
Package Structure
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
Data Model
Core Racing Hierarchy
Season
āāā Matchday
āāā Race
āāā RaceResult (per driver: position, quali, fastest lap)
Teams and Drivers
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)
Playoffs
Playoff (linked to Season)
āāā PlayoffRound (round of 8, quarterfinal, semifinal, final, ...)
āāā PlayoffMatchup (team vs team, best-of-legs)
Supporting Entities
| 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 |
Entity Relationships
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
Spring Profiles
| 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 (Open Session in View)
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.
Scoring System
Race Points (by finishing position)
| 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 |
Bonus Points
| Category |
1st |
2nd |
3rd |
| Qualifying |
3 |
2 |
1 |
| Fastest Lap |
2 |
- |
- |