Skip to content

Add Player season hitting overview #57

Description

@Mattsface

Goal

Build the first real Player analytics vertical slice on top of the Player directory and persisted PlayerSeasonHitting foundation.

The page should answer one clear baseball question:

What did this player's overall offensive season look like?

This issue begins Player analytics after the UI/information-architecture work in #30. Keep the first slice intentionally small, season-level, DB-only, and based only on data already persisted locally.

Route

Add a real Player hitting destination using shareable query parameters, preferably:

/players/hitting?season=2025&player_id=592450

Do not add a generic Player-detail routing framework.

The Player directory should provide a real path into this page once a Player is selected.

Data source

Use the existing persisted Player foundation:

  • players
  • player_seasons
  • player_season_hitting
  • get_player(...)
  • get_player_season_hitting(...)

Normal browser rendering must remain DB-only.

Do not add new MLB ingestion, schema migrations, live API calls, or team-stint modeling in this issue.

Season and membership semantics

A Player hitting page must be tied to a real persisted Player/season selection.

  • player_id and season must be explicit and shareable.
  • Player identity alone does not establish season membership.
  • Preserve the Player catalog's season-membership semantics.
  • If the Player is not in the selected season's persisted catalog, render the established useful not-found state.
  • If catalog membership exists but hitting data has not been stored for that Player/season, render a clear data-unavailable state rather than fabricating zeroes or calling MLB.

Overview metrics

Derive familiar season-level hitting rates from the raw persisted counting stats rather than persisting duplicate rate statistics.

Candidate overview metrics:

  • Games
  • Plate Appearances
  • AVG
  • OBP
  • SLG
  • OPS
  • Home Runs
  • Walks
  • Strikeouts
  • Stolen Bases

Use standard baseball formulas from the stored components and handle zero denominators explicitly.

Do not silently coerce an undefined rate to zero.

First visualization

If the existing chart architecture supports it cleanly, add one small, interpretable Player visualization based on a shared denominator:

  • K% = strikeouts / plate appearances
  • BB% = walks / plate appearances
  • HR% = home runs / plate appearances

The chart should be described as a plate-appearance rate profile, not as a ranking or quality score.

Do not mix AVG, OBP, SLG, OPS, and counting stats into an arbitrary bar chart merely because they are available.

If the rate-profile visualization proves awkward or misleading during implementation, keep the page to the season overview and document why rather than forcing a chart.

Navigation / Player UI

Extend the real Player domain established in #56 without redesigning Team analytics.

The Player directory should remain the selection/search home.

Once a Player is selected and hitting data exists, provide a clear link to the hitting overview.

Establish Player-domain navigation only to the extent required by real destinations. Do not add dead future Player metric links.

Analytics ownership

Derived baseball calculations belong under app/analytics/, not in routes, templates, or repositories.

Prefer a small typed Player hitting analysis model/function over passing raw persistence models directly into presentation logic.

Keep routes thin.

Presentation

Follow the existing server-rendered FastAPI/Jinja/Plotly visual language:

  • existing shell and primary navigation
  • cards and typography
  • responsive layout
  • semantic HTML
  • visible keyboard focus
  • local Plotly only if a chart is included

Make clear that the page represents a full-season aggregate. It is not a game-log trend and does not provide historical team-stint detail.

Testing

Cover at minimum:

  • correct AVG/OBP/SLG/OPS formulas
  • correct PA-rate calculations if the visualization is included
  • zero-denominator behavior
  • selected Player must belong to the selected catalog season
  • missing hitting data produces a useful state
  • existing stored hitting data renders without MLB calls
  • shareable season and player_id
  • directory-to-hitting navigation
  • Player primary navigation remains correct
  • Team routes and /health remain unchanged
  • browser rendering remains DB-only

Out of scope

  • Player game logs
  • rolling Player trends
  • multi-season trend charts
  • Player-vs-MLB context
  • leaderboards/rankings
  • Player comparisons
  • Player pitching
  • team-stint history
  • new Player ingestion
  • schema migrations
  • generic metric/dashboard frameworks
  • route migrations for existing Team pages

Completion

A user can search/select a locally stored Player, navigate to a real Player season hitting overview, understand the Player's season-level offensive line from persisted data, and encounter honest empty/error states when the local database cannot support the view.

This should be the first Player analytics slice, not the entire Player analytics roadmap.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions