feat(sports): add inter-house fixtures with clash detection and derived standings (fixes #305) - #310
Open
MOHITKOURAV01 wants to merge 1 commit into
Open
Conversation
…ed standings Fixtures for the inter-house championship, with the points table computed from results rather than stored. The clash check is the reason the module exists. createFixture and updateFixture both run it against every non-cancelled fixture on the same date, comparing integer minute ranges rather than time strings, and reject three cases with a 409 naming the fixture that already owns the slot: a house already playing, a venue already booked, an official already committed. It runs on update as well as create, because the double booking that actually happens is a time being moved rather than a fixture being added. Standings are folded out of completed and walkover fixtures on every request. There is no standings model to fall out of step with the results, and the ordering breaks every tie down to house name so two identical requests cannot come back in a different order. Abandoned fixtures are excluded rather than counted as goalless draws. The outcome of a match is derived from its scoreline in a pre-validate hook, so a client sending 1-3 alongside an outcome of 'home' is corrected rather than believed, and a result cannot be recorded against a fixture whose date has not arrived. The /sports page shows the same table to everyone and puts result entry inline for staff.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Closes #305
Description
Fixtures for the inter-house championship, with the points table computed from results rather than stored.
The clash check is the reason the module exists.
createFixtureandupdateFixtureboth run the same check against every non-cancelled fixture on that date, comparing integer minute ranges rather than time strings, and reject three cases with a409naming the fixture that already owns the slot:It runs on update as well as create. The double booking that actually happens in a school is a time being moved, not a fixture being added, and an update path that skips the check is the same as having no check. There is no override flag — a flag would be used by exactly the person in a hurry on the morning of the match.
Standings are derived, never stored.
GET /standingsfolds completed and walkover fixtures into a table on every request. There is no standings document that can drift away from the results it came from, so the table and the scorelines printed beside it cannot disagree. The ordering breaks every tie — points, wins, score difference, score for, head-to-head between exactly the tied pair, then house name — so two identical requests can never come back in a different order. Abandoned fixtures are excluded rather than counted as goalless draws, because those are different things and only one of them can be replayed.The outcome is a function of the scoreline. A client sending
homeScore: 1, awayScore: 3alongsideoutcome: "home"is corrected in the model's pre-validate hook, not believed. A walkover has no scoreline but must name a house that is actually playing. A result cannot be recorded against a fixture whose date has not arrived, andclearResultreopens a fixture for correction so a mistyped score is fixable without touching the table by hand.The
/sportspage shows the same standings to everyone and puts result entry inline for staff, rather than keeping a separate admin screen that drifts out of sync.Pages / Components Added or Modified
backend/models/Fixture.js— new; clash primitives, derived outcome,buildStandingsbackend/controllers/sportsController.js— new;findClashesruns on create and updatebackend/routes/sportsRoutes.js— new;/api/sportsfrontend/src/pages/SportsBoard.jsx— new; standings / fixtures / day schedulebackend/server.js— +5 lines, one self-contained require-and-mount blockfrontend/src/App.jsx— +8 lines, one lazy import and one routeScreenshots
No screenshots attached. The page needs a populated fixture list and a live MongoDB to show anything meaningful, and I did not want to attach a screenshot of an empty state and imply it had been exercised against real data. The layout is standard Tailwind and matches the existing pages.
Checklist
npx eslint srcpasses — 18 problems, unchanged fromorigin/main; none in the files this PR addsnpx vite buildsucceedsnode --checkpasses on every backend file added or changedmd:grid breakpoints throughout)Merge conflicts
Checked rather than assumed. This branch was merged pairwise against all 22 other open feature PRs: no conflicts with any of them. The three shared files are additions-only (
server.js+5/-0,App.jsx+8/-0), and the insertion points were deliberately chosen to sit clear of the lines every other open PR is appending to.Eight of the other open PRs already conflict with each other on
server.js,App.jsxandTeacherDashboard.jsx. That set is identical with and without this branch, so none of it originates here.