Phase 23: season history + division zone data + new route
CI / Build, lint & test (push) Failing after 1m19s

- migrations/0011_season_history.sql: persist one row per completed season
- models/season.rs: SeasonHistoryEntry struct; public SEASON_LENGTH /
  PROMOTION_PTS / RELEGATION_PTS consts; pts_above_safe, can_be_relegated,
  promotion_achievable helpers
- services/season.rs: write history entry on season rollover; get_history()
  returns last 20 seasons newest-first
- routes/division.rs: GET /division now includes promotion_pts, relegation_pts,
  season_length, pts_above_safe, promotion_achievable, can_be_relegated;
  new GET /division/history endpoint
- 3 new integration tests: history empty, history records after promotion,
  division response has zone fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-25 18:38:02 -07:00
parent c458b8cdbd
commit 28d7490555
6 changed files with 373 additions and 4 deletions
+14 -4
View File
@@ -4,15 +4,13 @@ use serde_json::{json, Value};
use crate::{
app::AppState,
error::AppResult,
models::season::{PROMOTION_PTS, RELEGATION_PTS, SEASON_LENGTH},
services::{club as club_svc, profile as profile_svc, season as season_svc},
};
pub async fn get_division(State(state): State<AppState>) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool).await?;
let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
// Ensure a season row exists (idempotent)
let _ = club; // suppress unused warning; we need club_id later if we extend this
let _club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
let season = season_svc::get_or_create(&state.pool, &profile.id).await?;
Ok(Json(json!({
@@ -21,6 +19,12 @@ pub async fn get_division(State(state): State<AppState>) -> AppResult<Json<Value
"season_points": season.season_points,
"matches_played": season.matches_played,
"matches_remaining": season.matches_remaining(),
"season_length": SEASON_LENGTH,
"promotion_pts": PROMOTION_PTS,
"relegation_pts": RELEGATION_PTS,
"pts_above_safe": season.pts_above_safe(),
"promotion_achievable": season.promotion_achievable(),
"can_be_relegated": season.can_be_relegated(),
"record": {
"wins": season.wins,
"draws": season.draws,
@@ -30,3 +34,9 @@ pub async fn get_division(State(state): State<AppState>) -> AppResult<Json<Value
"started_at": season.started_at,
})))
}
pub async fn get_division_history(State(state): State<AppState>) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool).await?;
let history = season_svc::get_history(&state.pool, &profile.id).await?;
Ok(Json(json!({ "history": history, "total": history.len() })))
}