No description
  • HTML 57.3%
  • Java 39.5%
  • CSS 3.1%
Find a file
fabian19921 046d95a5ab
Merge pull request #96 from fabian19921/development/82
Zoek-een-buddy: chatvenster i.p.v. losse reactie-notificatie
2026-08-21 11:07:25 +02:00
.github Trivy-resultaat zichtbaar in oogopslag: badge in README + job summary 2026-07-17 14:23:18 +02:00
.mvn/wrapper Initial commit 2026-04-27 14:36:09 +02:00
docs Fase 1 performance-analyse: PR-historie met verloopgrafiek 2026-07-18 14:31:26 +02:00
src Zoek-een-buddy: chatvenster i.p.v. losse reactie-notificatie 2026-08-21 11:05:12 +02:00
.gitattributes Initial commit 2026-04-27 14:36:09 +02:00
.gitignore Initial commit 2026-04-27 14:36:09 +02:00
CLAUDE.md Nieuwe GlobalExceptionHandler (controller/GlobalExceptionHandler.java) 2026-07-05 19:45:46 +02:00
Dockerfile development-04: aanpassing Dockerfile 2026-04-27 16:22:14 +02:00
mvnw Punt 8 is opgelost met Forgejo Actions, en de eerste dependency-scan leverde direct resultaat op: 12 fixbare HIGH/CRITICAL CVE's, verholpen met een Spring Boot-bump naar 4.0.7. Alles staat klaar in de 2026-07-17 13:55:04 +02:00
mvnw.cmd Initial commit 2026-04-27 14:36:09 +02:00
pom.xml development-80: trivy oplossen 2026-08-07 11:03:07 +02:00
README.md 76: mobility toegevoegd 2026-07-26 15:19:35 +02:00

AR-8 — CrossFit Training App

Een full-stack CrossFit training tracking app voor AR-8. Gebruikers kunnen trainingen bekijken, scores loggen, personal records bijhouden, events aanmelden en hun level opbouwen via een puntensysteem.

Live: https://ar-8.nl
GitHub: https://github.com/fabian19921/AR8 (privé)

Dependency-scan CI


Tech Stack

Laag Technologie
Backend Spring Boot 4, Java 21
Database PostgreSQL
Frontend Thymeleaf + plain JavaScript
Auth JWT (JSON Web Tokens)
Foto opslag Cloudinary
Hosting Render.com
Package com.laverman.STM1D

Lokaal opstarten

Vereisten

  • Java 21
  • Maven
  • PostgreSQL database

Stappen

# 1. Clone de repo
git clone https://github.com/fabian19921/AR8.git
cd AR8

# 2. Maak een lokale PostgreSQL database aan
createdb ar8_db

# 3. Stel omgevingsvariabelen in (zie hieronder)

# 4. Start de app
mvn spring-boot:run

De app draait op http://localhost:8080


Omgevingsvariabelen

Zet deze in application.properties of als environment variables op Render:

# Database
spring.datasource.url=jdbc:postgresql://localhost:5432/ar8_db
spring.datasource.username=jouw_gebruikersnaam
spring.datasource.password=jouw_wachtwoord

# JWT
jwt.secret=jouw_jwt_secret

# Cloudinary
cloudinary.cloud-name=jouw_cloud_name
cloudinary.api-key=jouw_api_key
cloudinary.api-secret=jouw_api_secret

# Email (wachtwoord reset)
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=jouw_email
spring.mail.password=jouw_app_wachtwoord

Database migraties

Schemawijzigingen gaan via Flyway (src/main/resources/db/migration); de app voert ontbrekende migraties automatisch uit bij het opstarten:

  • Nieuwe (lege) database: V1__baseline.sql zet het volledige schema neer.
  • Bestaande database zonder Flyway-historie: wordt eenmalig gebaselined op versie 1 (spring.flyway.baseline-on-migrate=true), het baseline-script wordt dan overgeslagen.

Een nieuwe schemawijziging is een nieuw versioneerd script (V2__beschrijving.sql, V3__...). Hibernate staat op ddl-auto=validate en controleert bij het opstarten of het schema bij de entities past — handmatige SQL op productie is niet meer nodig.


Functionaliteiten

Gebruikers

  • Registreren / inloggen via JWT
  • Wachtwoord reset via email
  • Profielpagina met foto upload (Cloudinary + Cropper.js)
  • Rollen: USER en ADMIN

Trainingen

  • Trainingsplan per dag aanmaken (ADMIN)
  • Blokken: warming up, kracht, WOD, oefenblok, accessory
  • Score typen: kg, tijd, rondes, reps, meter, geen
  • RX / Scaled toggle per blokje
  • Vinkje voor blokjes zonder score
  • Buddy workout systeem (max 4 personen)
  • Personal Records automatisch bijhouden, met historie (pr_history) en verloopgrafiek per oefening
  • Weekbalk met navigatie
  • Vast Mobility-blok onderaan elke dag (los van het trainingsplan, ook op dagen zonder geplande training): atleet logt zelf zijn tijd (mm:ss), invulling vrij (GoWod, Pliability, Flexy, eigen routine)

Puntensysteem (50 levels)

  • +1 punt per ingevuld score blokje of vinkje (ook voor Mobility)
  • +5 bonus punten als alle blokjes van een dag gedaan zijn (minimaal 3 blokjes); Mobility telt hier niet in mee
  • +5 bonus punten als de som van Mobility-tijd in een ISO-week (ma t/m zo) minimaal 105 minuten is (7×15 min, vrij te verdelen over de week)
  • +25 punten per event met eindranking ingevuld
  • Buddy gebruikers krijgen dezelfde punten als de captain
  • 50 levels van Rookie → Always Ready
  • Voortgangsbalk op home pagina
  • Maandelijks leaderboard (reset elke maand, toont top 5); sta je zelf buiten de top 5, dan toont de app je eigen positie, punten deze maand en het gat tot plek 5

Events

  • Events aanmaken met foto (ADMIN)
  • Registreren als individueel, buddy of team
  • Foto upload per deelnemer met Cropper.js
  • Eindranking invullen
  • Atleten overzichtspagina per event

WOD Timer

  • For Time (telt op, optioneel tijdslimiet)
  • EMOM (instelbaar rondes + tijdsduur)
  • Interval (werk + rusttijd + rondes)
  • 10 seconden aftellen bij start
  • Geluidsignalen via Web Audio API
  • Scherm blijft aan via Wake Lock API

Overig

  • Notities per dag
  • Contact pagina
  • AR-8 Atleet aanmelding + goedkeuring door admin

Mappenstructuur

src/main/
├── java/com/laverman/STM1D/
│   ├── config/          # CloudinaryConfig, SecurityConfig
│   ├── controller/      # REST controllers
│   ├── dto/             # Request/response DTO's (records met Bean Validation)
│   ├── model/           # JPA entities
│   ├── repository/      # Spring Data repositories
│   └── service/         # Business logic
└── resources/
    ├── templates/        # Thymeleaf HTML pagina's
    │   └── static/      # style.css, images
    └── application.properties

Deployment op Render

  1. Push naar GitHub (main branch)
  2. Render pikt automatisch de nieuwe versie op (auto-deploy aan)
  3. Flyway voert database-migraties automatisch uit bij het opstarten
  4. Environment variables staan ingesteld onder Environment in het Render dashboard
  5. Health-check: /actuator/health (Actuator, zonder token bereikbaar) — in te stellen als health-check-pad in het Render dashboard; andere Actuator-endpoints zijn niet geëxposed

CI (GitHub Actions)

  • .github/workflows/ci.yml: draait ./mvnw verify (build + alle tests) bij elke pull request en elke push naar main, tegen een PostgreSQL-servicecontainer. De tests draaien met het ci-profiel (src/test/resources/application-ci.properties, dummy-secrets).
  • .github/workflows/dependency-scan.yml: scant de Maven-dependencies wekelijks (en bij wijzigingen aan pom.xml) op bekende CVE's met Trivy; HIGH/CRITICAL kwetsbaarheden met een beschikbare fix laten de workflow falen. Fixes lopen vrijwel altijd via een patch-bump van de Spring Boot-parent in pom.xml.
  • .github/dependabot.yml: wekelijkse update-PR's voor Maven-dependencies en de workflow-actions.

Security

  • XSS-bescherming in de frontend: alle dynamische waarden (namen, scores, notificaties, event-/qualifier-velden) worden ge-escaped met de gedeelde helper esc() uit static/js/esc.js voordat ze via innerHTML gerenderd worden. Nieuwe templates die innerHTML met dynamische data gebruiken moeten /js/esc.js includen en esc() toepassen.
  • Security headers: SecurityConfig zet een Content-Security-Policy (o.a. connect-src 'self' tegen token-exfiltratie, frame-ancestors 'none' tegen clickjacking). Externe bronnen die zijn toegestaan: cdnjs.cloudflare.com (cropper.js) en res.cloudinary.com (foto's).
  • Brute-force-bescherming: RateLimitService (Bucket4j, in-memory per instance) limiteert /auth/login (10 pogingen per e-mail / 20 per IP per 15 min) en /api/password/forgot (3 per e-mail / 10 per IP per uur); daarboven volgt HTTP 429.
  • Wachtwoordbeleid: minimaal 10 tekens bij registratie, wijzigen en reset. Per gebruiker is maximaal één reset-token tegelijk actief; een nieuwe aanvraag maakt oude tokens ongeldig.
  • Foutafhandeling: GlobalExceptionHandler (@RestControllerAdvice) vangt onverwachte fouten af — generieke melding naar de client, volledige stacktrace naar de log. Controllers horen geen eigen catch (Exception) met foutdetails richting de client te hebben.
  • Request-validatie: endpoints nemen geen JPA-entities of losse Maps als request body aan, maar DTO-records uit dto/ met Bean Validation-annotaties en @Valid in de controller (tegen mass assignment). Validatiefouten geven een 400 met een Nederlandstalige melding als platte tekst.
  • Ingelogde gebruiker: controllers parsen het Authorization-header niet zelf — de JwtAuthFilter verifieert het token en zet een Authentication (principal = e-mailadres). Endpoints nemen Authentication als parameter en halen de gebruiker op via CurrentUserService.getUser(authentication).
  • Rol uit de database: het JWT bevat geen rol-claim; de JwtAuthFilter laadt de rol per request uit de database. Een gebruiker degraderen werkt daardoor per direct, en een token van een verwijderde gebruiker geeft geen toegang meer.
  • Geen persoonsdata in logs: EmailMaskingConverter (gekoppeld via %maskedMsg in logback-spring.xml) maskeert e-mailadressen in álle logmeldingen naar p***@domein.nl. Logregels hoeven daar zelf niets voor te doen.
  • Tests hiervoor staan in src/test/java/com/laverman/STM1D/ (o.a. SecurityHeadersTest, RateLimitServiceTest, LoginControllerTest, PasswordResetControllerTest, AdminEndpointSecurityTest). Wie een admin-endpoint toevoegt, hoort in AdminEndpointSecurityTest een 403-test voor een gewone USER toe te voegen.

Bekende limieten

  • Leaderboard berekent punten real-time voor alle gebruikers — bij >100 gebruikers eventueel caching toevoegen
  • Geen push notificaties (Garmin API vereist zakelijke goedkeuring)
  • trainingplan.html heeft een bekend responsive probleem op kleine schermen (< 380px)