Files
sports-division/project.md
2026-03-01 15:14:42 -04:00

47 KiB
Raw Blame History

Dominica Sports Division Application — Project Management Document

1. Project Overview

Project Name: Dominica Sports Division Application Platform: ASP.NET Core MVC (.NET 10) Purpose: A web application for the Dominica Sports Division to manage school athletics tournaments — from student registration and event setup through score tracking, school points tallying, and printable report generation.

Current State: Fresh dotnet new mvc scaffold with default HomeController, ErrorViewModel, and standard layout views. No domain logic, no database, no authentication.

Target Architecture: Clean Architecture (detailed in Section 10).


2. Requirements Summary

# Requirement Priority
R1 Student Registration High
R2 Three Event Categories (Track, Field, High Jump) High
R3 Event Levels (18 divisions by age/label + sex) High
R4 School Levels (Primary, Secondary, College) High
R5 Adjustable Heights for Jumps Medium
R6 Event Definitions with Equipment Specs High
R7 Zones High
R8 Tournaments (with archive option) High
R9 Register Students to Events (age/sex rules) High
R10 User Management & Role Management High
R11 Event Score Tracking & School Points High
R12 Admin Dashboard & Printable Reports High
R13 Refactor to Clean Architecture High

3. Detailed Requirements

R1 — Student Registration

Each student record contains:

Field Type Constraints
StudentId int Primary Key, auto-increment
ExistingStudentId string Candidate Key (unique, required) — the student's pre-existing school-assigned ID number
FirstName string Required, max 100 chars
LastName string Required, max 100 chars
DateOfBirth date Required, must be in the past
Sex enum Male, Female
SchoolId FK Required — references the School entity
IsActive bool Defaults to true

Key design:

  • StudentId is the internal surrogate primary key (auto-increment integer). Used in all foreign key relationships.
  • ExistingStudentId is the natural/business key — the ID the student already has from their school (e.g., school registration number). It has a unique index and can be used to look up students. This prevents duplicate registrations of the same real-world student.

Derived fields (computed, not stored):

  • Age — calculated from DateOfBirth relative to the tournament date (or current date).
  • EventLevel — resolved from Age, Sex, and school level using the Event Level rules (R3).

Business rules:

  • A student must belong to exactly one school.
  • Deactivated students (IsActive = false) cannot be registered to new events but their historical scores are preserved.

R2 — Three Event Categories

Events are classified into three categories because their scoring mechanics differ fundamentally:

Category Measurement Scoring Basis Competition Format Examples
Track Events Time (seconds) Lower is better — Points = A * (B - T)^C Seeding → Heats → (Semi-finals) → Finals 100m, 200m, 400m, 800m, 1200m, 4x100m Relay
Field Events Distance (metres) Higher is better — Points = A * (D - B)^C Best of N attempts Long Jump, Triple Jump, Shot Put, Discus, Javelin
High Jump Height (metres) Higher is better — Points = A * (M - B)^C with attempt/clearance tracking Progressive bar heights with 3 attempts per height High Jump

Why High Jump is separate: High Jump has a unique competition format. Athletes choose heights to attempt, get three attempts per height, and are eliminated after three consecutive failures. The bar height progresses upward. This requires tracking individual attempts (clear / fail / pass) at each height — a data model fundamentally different from track (single time) or field (best of N throws/jumps).

Track Event Round Progression (Seeding, Heats, Semi-finals, Finals)

Track events follow a multi-round elimination structure. The number of rounds depends on participant count.

Rounds (in order):

Round Purpose Required
Heats First round — split registered students across multiple heats to reduce field size Yes (if > 1 heat needed)
Semi-finals Intermediate round — top qualifiers from heats compete to advance to finals Skippable — only used if participant count warrants it
Finals Deciding round — determines placement and points Yes

When to skip semi-finals: Semi-finals are skipped when the number of registered students is small enough that heats can feed directly into finals. The admin configures the round structure per TournamentEventLevel based on registration count. Typical thresholds:

Registered Students Round Structure
≤ 8 (1 heat) Finals only (no heats, no semis)
9 24 Heats → Finals
25+ Heats → Semi-finals → Finals

These thresholds are guidelines, not hard rules. The admin has full control to add or skip semi-finals for any event.

Seeding: Before heats begin, registered students are seeded (assigned to heats and lanes). Seeding can be:

  • Random — students are randomly distributed across heats.
  • By performance — if prior times are available (e.g., from zone prelims), students are spread across heats so each heat has a mix of fast and slow runners (serpentine seeding).
  • Manual — admin manually assigns students to heats and lanes.

Advancement rules: After each round, students advance to the next round based on:

  • Top N per heat — e.g., top 3 from each heat advance automatically.
  • Fastest losers — additional qualifiers taken from remaining athletes by best time across all heats (e.g., "top 3 + 2 fastest losers").
  • The admin configures AdvanceTopN and AdvanceFastestLosers per round.

Lane assignment: Each student (or relay team) in a heat is assigned a lane number. Lane count depends on the facility (typically 6 or 8 lanes).

Track Round Entities

Round:

Field Type Notes
RoundId int PK, auto-increment
TournamentEventLevelId FK The tournament-event-level this round belongs to
RoundType enum Heat, SemiFinal, Final
RoundOrder int 1 = Heats, 2 = Semi-finals, 3 = Finals (or 1 = Heats, 2 = Finals if semis skipped)
AdvanceTopN int (nullable) Top N per heat auto-advance (null for Finals)
AdvanceFastestLosers int (nullable) Additional qualifiers by best time across heats (null for Finals)
Status enum Pending, InProgress, Completed

Heat:

Field Type Notes
HeatId int PK, auto-increment
RoundId FK The round this heat belongs to
HeatNumber int e.g., Heat 1, Heat 2, Heat 3
Status enum Pending, InProgress, Completed

HeatLane (lane assignment per student per heat):

Field Type Notes
HeatLaneId int PK, auto-increment
HeatId FK
RegistrationId FK The student's event registration
LaneNumber int 18 (or facility max)
Time decimal (nullable) Recorded time in seconds
IsAdvanced bool Did this student advance to the next round?
AdvanceReason enum (nullable) TopN, FastestLoser, Manual — how they qualified
RecordedBy FK (nullable) Official who recorded the time
RecordedAt datetime (nullable)

Workflow:

  1. Admin creates round structure for a track TournamentEventLevel (e.g., Heats + Finals, or Heats + Semis + Finals).
  2. Admin or system seeds students into Heat 1, Heat 2, etc. with lane assignments.
  3. Officials record times per lane per heat.
  4. System identifies qualifiers (top N + fastest losers) and marks IsAdvanced = true.
  5. Next round's heats are populated from advancing students (re-seeded for semis/finals).
  6. Finals results determine placement and school points. Only the Finals round produces placement points.

R3 — Event Levels

An Event Level is the competitive division in which a student participates. It combines a division name (age-based or label-based) with sex. Event levels are a first-class entity in the system, not just an enum.

Primary School Event Levels

Primary schools do not use age-based divisions because groups are too small. Instead, they use label-based divisions:

Event Level Sex School Level
Junior Boys Male Primary
Junior Girls Female Primary
Senior Boys Male Primary
Senior Girls Female Primary

The distinction between "Junior" and "Senior" at the primary level is determined by the school or tournament admin (e.g., grades 1-3 vs 4-6). There is no strict age cutoff enforced by the system for these levels.

Secondary / College Event Levels

Secondary and College competitions use age-based divisions:

Event Level Sex Max Age School Level(s)
Under 14 Boys Male 13 Secondary
Under 14 Girls Female 13 Secondary
Under 15 Boys Male 14 Secondary
Under 15 Girls Female 14 Secondary
Under 16 Boys Male 15 Secondary
Under 16 Girls Female 15 Secondary
Under 17 Boys Male 16 Secondary / College
Under 17 Girls Female 16 Secondary / College
Under 20 Boys Male 19 Secondary / College
Under 20 Girls Female 19 Secondary / College
Under 21 Boys Male 20 Secondary / College
Under 21 Girls Female 20 Secondary / College
Open Boys Male No limit Secondary / College
Open Girls Female No limit Secondary / College

Age calculation: A student's age is determined as of the tournament start date (not the current date), ensuring consistency throughout a tournament.

Compete-up rule (R9): For age-based levels, students may compete in a level above their age but never below. For example, an Under 14 student may enter Under 16 events but not the reverse. "Open" levels have no age ceiling.

Age Limit Waiver

Some events may have their age restriction waived on a per-tournament basis when the number of eligible registrants is too small to form a viable competition group. An admin can toggle an AgeRestrictionWaived flag on any tournament-event-level combination, which opens the event to all students in that sex category regardless of age. This is common in smaller zones where strict event leveling would result in events with very few competitors.

EventLevel Entity

Field Type Notes
EventLevelId int PK, auto-increment
Name string e.g., "Junior Boys", "Under 17 Girls", "Open Boys"
Sex enum Male or Female
MaxAge int (nullable) Age ceiling; null for Primary levels (Junior/Senior) and Open levels
SchoolLevel enum Primary, Secondary, College — which school level(s) this level applies to
IsAgeBased bool false for Junior/Senior (Primary); true for Under-X and Open (Secondary/College)
SortOrder int Display ordering
IsActive bool Soft delete

R4 — School Levels

School Level Typical Ages Event Levels
Primary 5 12 Junior Boys/Girls, Senior Boys/Girls (no age cutoffs)
Secondary 12 18 Under 14 through Under 21, Open (age-based, by sex)
College 16 20 Under 17 through Under 21, Open (age-based, by sex)

Key rule: Secondary and College students compete together because there are only three colleges on the island (DSC, BTC, ACADEMIX). The system must support a combined competition bracket for Secondary/College while still tracking school-level origin for reporting.

School entity fields:

Field Type Notes
SchoolId int PK, auto-increment
Name string Required, e.g., "Convent High School"
ShortName string (nullable) Abbreviation, e.g., "CHS". Primarily used by Secondary/College schools.
SchoolLevel enum Primary, Secondary, College
ZoneId FK Required — references Zone
IsActive bool Defaults to true

R5 — Adjustable Heights for Jumps

High Jump events require configurable height progressions per tournament:

Field Type Notes
EventId FK The High Jump event
TournamentId FK The tournament
StartingHeight decimal (m) The first bar height
HeightIncrement decimal (m) Default increment between rounds
Heights collection Ordered list of heights to be attempted

Admins can:

  • Set the starting height and default increment.
  • Manually add, remove, or reorder individual heights in the progression.
  • Adjust heights mid-competition if needed.

Attempt tracking per student per height:

Field Type Values
StudentId FK
Height decimal (m)
Attempt1 enum Clear, Fail, Pass
Attempt2 enum Clear, Fail, Pass, null
Attempt3 enum Clear, Fail, Pass, null

A student is eliminated after three consecutive failures (across any combination of heights). A student may pass a height to conserve attempts.


R6 — Event Definitions

Events are the specific competitions students can enter. Each event belongs to exactly one category (R2). Equipment weight is part of the event name (e.g., "Shot Put 3kg" and "Shot Put 5kg" are distinct events, not one event with variable weight).

Complete Event List (32 unique events)

Track Events (15)

# Event Name Primary Secondary/College Relay Notes
1 80m Yes No Primary only
2 100m Yes No
3 150m Yes No Primary only
4 200m Yes No
5 300m Yes No Primary only
6 400m Yes No
7 800m Yes No
8 1200m Yes No Primary only
9 1500m Yes No
10 3000m Yes No
11 5000m Yes No
12 80mH Yes No 80m Hurdles
13 4X80m Relay Yes Yes Primary only; 4 students per school
14 4X100m Relay Yes Yes 4 students per school
15 4X400m Yes Yes 4 students per school

Field Events (16)

# Event Name Primary Secondary/College Notes
16 Long Jump Yes Yes Both levels
17 Triple Jump Yes
18 Shot Put 3kg Yes
19 Shot Put 4kg Yes
20 Shot Put 5kg Yes
21 Shot Put 6kg Yes
22 Discus 1kg Yes
23 Discus 1.25kg Yes
24 Discus 1.5kg Yes
25 Discus 1.75kg Yes
26 Javelin 400g Yes
27 Javelin 500g Yes
28 Javelin 600g Yes
29 Javelin 700g Yes
30 Javelin 800g Yes
31 Throwing the Cricket Ball Yes Primary only

High Jump (1)

# Event Name Primary Secondary/College Notes
32 High Jump Yes Yes Both levels; bar heights adjustable per tournament

School Level Summary

  • Primary only (8): 80m, 150m, 300m, 1200m, 4X80m Relay, Throwing the Cricket Ball, (+ Long Jump & High Jump shared)
  • Secondary/College only (22): 100m, 200m, 400m, 800m, 1500m, 3000m, 5000m, 80mH, 4X100m Relay, 4X400m, Triple Jump, all Shot Put/Discus/Javelin variants, (+ Long Jump & High Jump shared)
  • Both levels (2): Long Jump, High Jump

Event entity fields:

Field Type Notes
EventId int PK, auto-increment
Name string e.g., "100m", "Shot Put 3kg", "Throwing the Cricket Ball"
Category enum Track, Field, HighJump
IsRelay bool If true, registration is per-school team
PrimarySchool bool Available for primary school tournaments
SecondarySchool bool Available for secondary/college tournaments
AllowedEventLevels collection Which EventLevels this event can be offered at (many-to-many)
IsActive bool Soft delete

Tournament-Event-Level link (TournamentEventLevel):

This junction entity defines which events are offered at which levels in a specific tournament. It is the core scheduling unit.

Field Type Notes
TournamentId FK
EventId FK
EventLevelId FK References the EventLevel (e.g., "Under 17 Boys")
AgeRestrictionWaived bool When true, the level's age limit is ignored — all students of the matching sex may register. Used when groups are too small.

R7 — Zones

Dominica is divided into geographic zones for organizing preliminary competitions:

Zone Code
North West NW
North N
South S
South East SE
North East NE
South West SW
West Central WC
Secondary School / College SSC

Notes:

  • The first seven zones are geographic and primarily serve primary schools.
  • The "Secondary School / College" zone is a special zone that groups all secondary schools and colleges together for their combined competitions.
  • Each school belongs to exactly one zone.
  • Tournaments can be scoped to a single zone (zone preliminaries) or island-wide (national championships).

R8 — Tournaments

A tournament represents a competition event (e.g., "2026 Independence Athletics Championship — North East Zone Preliminaries" or "2026 National Primary Schools Championship").

Field Type Notes
Name string Required
StartDate date Used for student age calculation
EndDate date
ZoneId FK (nullable) Null = island-wide; otherwise zone-specific
SchoolLevel enum (nullable) Filter by Primary / Secondary / College or null for all
IsArchived bool Archived tournaments are read-only and hidden from active lists
Status enum Draft, Registration, InProgress, Completed, Archived

Tournament lifecycle:

  1. Draft — Admin creates the tournament and configures events, event levels, and height progressions.
  2. Registration — Coaches/principals register their students to events.
  3. InProgress — Competition is underway; scores are being recorded.
  4. Completed — All events are scored; results are final.
  5. Archived — Tournament is archived for historical reference; no further edits allowed.

Archive feature: Admins can archive any completed tournament. Archived tournaments:

  • Do not appear in active tournament lists (unless a filter is toggled).
  • Remain fully accessible in read-only mode for reports and historical reference.
  • Can be un-archived by an admin if corrections are needed.

R9 — Register Students to Events

Registration rules:

  1. Event level matching: A student can only be registered to an event at an EventLevel that matches their sex and school level.
  2. Primary school levels (Junior/Senior): No age restrictions — the student's sex must match the level's sex. The choice of Junior vs Senior is at the coach's/admin's discretion.
  3. Secondary/College age-based levels: The student's age (computed from DOB and tournament start date) must be ≤ the level's MaxAge. Students may compete up (enter a higher age level) but never down. "Open" levels have no age ceiling.
  4. Age limit waiver: If AgeRestrictionWaived is true on the TournamentEventLevel, the age check is skipped — any student of the matching sex may register.
  5. School level: The student's school level must be compatible with the EventLevel's school level.
  6. Active status: Only students with IsActive = true can be registered.
  7. Relay teams: For relay events, the coach registers a team of 4 students from the same school, all meeting level eligibility.
  8. Duplicate prevention: A student cannot be registered to the same event-level twice in the same tournament.

Registration entity:

Field Type Notes
TournamentId FK
EventId FK
EventLevelId FK The level the student is competing at (e.g., "Under 17 Boys")
StudentId FK References Student.StudentId; null for relay teams
RelayTeamId FK (nullable) References a relay team if applicable
RegisteredBy FK The user (coach/principal/admin) who registered them
RegisteredAt datetime

R10 — User Management & Role Management

Roles

Role Permissions School Required
Student View own profile, view own scores and results Yes
Coach Register students from their school to events, view school results Yes
Principal Same as Coach + approve registrations, view school reports Yes
Sports Division Official Record scores, manage event logistics during tournaments No
Sports Division Admin Full system access: CRUD all entities, manage users/roles, run reports, archive tournaments No

Business rules:

  • Students, Coaches, and Principals must belong to a school upon registration.
  • Sports Division Officials and Admins do not belong to a school.
  • A user can hold only one role.
  • User authentication will use ASP.NET Core Identity.

User entity fields:

Field Type Notes
Email string Used for login
FirstName string
LastName string
Role enum One of the five roles
SchoolId FK (nullable) Required for Student, Coach, Principal; null for officials/admins
IsActive bool

R11 — Event Score Tracking & Points

Scoring Formula (World Athletics Standard)

All three event categories use the World Athletics polynomial scoring formula with event-specific constants:

Track Events (lower time = better):

Points = A * (B - T)^C

Where T = time in seconds; if T >= B, points = 0.

Field Events (greater distance = better):

Points = A * (D - B)^C

Where D = distance in metres; if D <= B, points = 0.

High Jump (greater height = better):

Points = A * (M - B)^C

Where M = height cleared in centimetres; if M <= B, points = 0.

Points are truncated to integers (not rounded).

Reference Constants (Combined Events / Decathlon Standard)

Event A B C Unit
100m 25.4347 18 1.81 seconds
400m 1.53775 82 1.81 seconds
1500m 0.03768 480 1.85 seconds
110m Hurdles 5.74352 28.5 1.92 seconds
Long Jump 0.14354 220 1.4 centimetres
Triple Jump 0.14354 220 1.4 centimetres
High Jump 0.8465 75 1.42 centimetres
Shot Put 51.39 1.5 1.05 metres
Discus 12.91 4 1.1 metres
Javelin 10.14 7 1.08 metres

Note: The admin should be able to view and adjust scoring constants in the system to accommodate future World Athletics updates or local adaptations. Constants are stored in the database, not hard-coded.

School Points

School rankings within a tournament are determined by aggregating individual student points:

  • Each event awards placement points to the top finishers (e.g., 1st = 10 pts, 2nd = 8 pts, 3rd = 6 pts, 4th = 5 pts, 5th = 4 pts, 6th = 3 pts, 7th = 2 pts, 8th = 1 pt). These values should be admin-configurable.
  • Relay events also award placement points to the school.
  • The school with the highest total placement points wins the tournament (or zone championship).
  • Ties are broken by number of 1st-place finishes, then 2nd-place finishes, etc.

Score entity:

Scores represent the final result for a student in an event (used for placement and school points). For track events, this is derived from the Finals round. For field events and high jump, it is recorded directly.

Field Type Notes
ScoreId int PK, auto-increment
RegistrationId FK Links to the student's event registration
RawPerformance decimal Best time in seconds (track), distance in metres (field), or height in cm (high jump)
CalculatedPoints int From the scoring formula
Placement int (nullable) 1st, 2nd, 3rd, etc.
PlacementPoints int Points awarded to the school
RecordedBy FK The official who entered the score
RecordedAt datetime

Track events: The final Score record is created from the student's Finals HeatLane.Time. Heat and semi-final times are stored in HeatLane and used only for advancement, not for placement points. If a student does not reach Finals, no Score record is created for them.


R12 — Admin Dashboard & Printable Reports

Dashboard

The admin dashboard provides at-a-glance metrics for the active tournament:

  • Total registered students (by gender, by school level)
  • Events in progress / completed / upcoming
  • Top schools by points
  • Recent score entries

Reports (all printable to PDF)

Report Description Filters
Score Sheets Blank or pre-filled score sheets for officials. For track events: one sheet per heat showing lane assignments and time columns. For field/high jump: lists registered students with performance columns. Event, Event Level, Round, Heat
Popular Events Ranked list of events by registration count. Tournament, School Level, Zone
Registration by Gender Breakdown of registrations by Male / Female across events and event levels. Tournament, Zone, School
Event-Gender-Level Report Matrix of events vs. gender vs. event level showing registration counts and results. Tournament
Event-School Report For each event, lists participating schools and their students' results. Tournament, Event, Event Level
Students by School Report For each school, lists all registered students and their events. Tournament, School, Zone
Scores by Event Report Detailed results for an event: all students ranked by performance with points. Tournament, Event, Event Level
Student Points Report Individual student point totals across all events in a tournament. Tournament, School, Zone

Print requirements:

  • All reports should render cleanly for A4 paper printing via browser print or PDF export.
  • Reports should include the tournament name, date, and generation timestamp in the header.
  • School crests/logos are optional future enhancements.

R13 — Refactor to Clean Architecture

The current scaffolded MVC project will be restructured into Clean Architecture layers:

Target Project Structure

SportsDivision.sln
|
+-- src/
|   +-- SportsDivision.Domain/              # Core domain entities, enums, interfaces
|   |   +-- Entities/
|   |   |   +-- Student.cs
|   |   |   +-- School.cs
|   |   |   +-- Zone.cs
|   |   |   +-- Event.cs
|   |   |   +-- Tournament.cs
|   |   |   +-- EventLevel.cs
|   |   |   +-- TournamentEventLevel.cs
|   |   |   +-- EventRegistration.cs
|   |   |   +-- Score.cs
|   |   |   +-- HighJumpAttempt.cs
|   |   |   +-- HighJumpHeight.cs
|   |   |   +-- Round.cs
|   |   |   +-- Heat.cs
|   |   |   +-- HeatLane.cs
|   |   |   +-- RelayTeam.cs
|   |   |   +-- ScoringConstant.cs
|   |   |   +-- PlacementPointConfig.cs
|   |   |   +-- EquipmentSpec.cs
|   |   |   +-- User.cs
|   |   +-- Enums/
|   |   |   +-- Sex.cs
|   |   |   +-- SchoolLevel.cs
|   |   |   +-- EventCategory.cs
|   |   |   +-- TournamentStatus.cs
|   |   |   +-- UserRole.cs
|   |   |   +-- HighJumpAttemptResult.cs
|   |   |   +-- RoundType.cs
|   |   |   +-- RoundStatus.cs
|   |   |   +-- AdvanceReason.cs
|   |   |   +-- SeedingMethod.cs
|   |   +-- Interfaces/
|   |   |   +-- IStudentRepository.cs
|   |   |   +-- ISchoolRepository.cs
|   |   |   +-- IEventRepository.cs
|   |   |   +-- ITournamentRepository.cs
|   |   |   +-- IScoreRepository.cs
|   |   |   +-- IUnitOfWork.cs
|   |   +-- SportsDivision.Domain.csproj
|   |
|   +-- SportsDivision.Application/         # Use cases, DTOs, service interfaces
|   |   +-- DTOs/
|   |   |   +-- StudentDto.cs
|   |   |   +-- EventDto.cs
|   |   |   +-- ScoreDto.cs
|   |   |   +-- TournamentDto.cs
|   |   |   +-- ReportDtos/
|   |   +-- Interfaces/
|   |   |   +-- IStudentService.cs
|   |   |   +-- IEventService.cs
|   |   |   +-- ITournamentService.cs
|   |   |   +-- IScoringService.cs
|   |   |   +-- IRegistrationService.cs
|   |   |   +-- IHeatService.cs
|   |   |   +-- IReportService.cs
|   |   +-- Services/
|   |   |   +-- StudentService.cs
|   |   |   +-- EventService.cs
|   |   |   +-- TournamentService.cs
|   |   |   +-- ScoringService.cs
|   |   |   +-- RegistrationService.cs
|   |   |   +-- HeatService.cs
|   |   |   +-- ReportService.cs
|   |   +-- Validators/
|   |   |   +-- RegistrationValidator.cs
|   |   +-- Mappings/
|   |   |   +-- MappingProfile.cs
|   |   +-- SportsDivision.Application.csproj
|   |
|   +-- SportsDivision.Infrastructure/      # EF Core, Identity, external services
|   |   +-- Data/
|   |   |   +-- ApplicationDbContext.cs
|   |   |   +-- Configurations/            # EF Fluent API entity configs
|   |   |   +-- Migrations/
|   |   +-- Repositories/
|   |   |   +-- StudentRepository.cs
|   |   |   +-- SchoolRepository.cs
|   |   |   +-- EventRepository.cs
|   |   |   +-- TournamentRepository.cs
|   |   |   +-- ScoreRepository.cs
|   |   |   +-- UnitOfWork.cs
|   |   +-- Identity/
|   |   |   +-- ApplicationUser.cs
|   |   +-- SportsDivision.Infrastructure.csproj
|   |
|   +-- SportsDivision.Web/                 # ASP.NET Core MVC (presentation)
|       +-- Controllers/
|       +-- Views/
|       +-- ViewModels/
|       +-- wwwroot/
|       +-- Program.cs
|       +-- SportsDivision.Web.csproj
|
+-- tests/
    +-- SportsDivision.Domain.Tests/
    +-- SportsDivision.Application.Tests/
    +-- SportsDivision.Infrastructure.Tests/

Dependency Flow

Web --> Application --> Domain
 |          |
 +-----> Infrastructure --> Domain
  • Domain has zero external dependencies (pure C#).
  • Application depends only on Domain. Defines service interfaces and use cases.
  • Infrastructure implements interfaces from Domain and Application (EF Core, Identity).
  • Web is the composition root — wires up DI, hosts controllers and views.

4. Domain Model (Entity Relationship Overview)

Zone (1) ----< School (1) ----< Student (PK: StudentId, CK: ExistingStudentId)
                  |                 |
                  |                 +----< EventRegistration
                  |                 |             |
                  +----< User       |             +---- Score
                                    |
                          RelayTeam >----< Student
                              |
                              +---- EventRegistration

EventRegistration >---- TournamentEventLevel

Tournament (1) ----< TournamentEventLevel >---- Event
                            |
                            +---- EventLevel
                            +-- AgeRestrictionWaived (bool)
                            |
                            +----< Round (Heat/SemiFinal/Final)
                                      |
                                      +----< Heat
                                                |
                                                +----< HeatLane >---- EventRegistration
                                                         |
                                                         +-- LaneNumber, Time, IsAdvanced

Tournament (1) ----< HighJumpHeight ----< HighJumpAttempt >---- Student

EventLevel (18 levels: Junior/Senior Boys/Girls + Under 14-21 Boys/Girls + Open Boys/Girls)

Event (1) ----< EquipmentSpec (per EventLevel)
Event (1) ----< ScoringConstant (A, B, C per event)
Event (1) >----< EventLevel (allowed levels, many-to-many)

PlacementPointConfig (placement rank -> points, per tournament or global)

Notes:
- Student.StudentId = auto-increment PK (surrogate key)
- Student.ExistingStudentId = unique candidate key (natural/business key)
- EventLevel combines division + sex (e.g., "Under 17 Boys", "Junior Girls")
- Primary levels (Junior/Senior): no age cutoff, school determines division
- TournamentEventLevel.AgeRestrictionWaived = true skips age check for that level
- Track events: TournamentEventLevel has Rounds → Heats → HeatLanes (with times)
- Semi-finals are optional; admin configures round structure per event
- Only Finals round produces Score records (placement + school points)

5. Technology Stack

Layer Technology
Framework .NET 10, ASP.NET Core MVC
ORM Entity Framework Core 10
Database PostgreSQL (via Npgsql.EntityFrameworkCore.PostgreSQL)
Authentication ASP.NET Core Identity
Authorization Role-based (5 roles) via [Authorize(Roles = "...")]
Mapping AutoMapper
Validation FluentValidation
PDF Reports QuestPDF or similar
Front-end Razor Views, Bootstrap 5, jQuery for interactivity
Testing xUnit, Moq

6. Implementation Phases

Phase 1 — Foundation (Clean Architecture + Core Entities)

  • Restructure solution into Clean Architecture (4 projects + tests)
  • Define Domain entities: Zone, School, Student, EventLevel
  • Define Enums: Sex, SchoolLevel, EventCategory, TournamentStatus, UserRole, HighJumpAttemptResult, RoundType, RoundStatus, AdvanceReason, SeedingMethod
  • Seed all 18 EventLevel records (Junior/Senior Boys/Girls + Under 1421 Boys/Girls + Open Boys/Girls)
  • Set up EF Core DbContext with entity configurations
  • Configure database connection and run initial migration
  • Set up dependency injection in Web project

Phase 2 — User Management & Authentication

  • Integrate ASP.NET Core Identity with custom ApplicationUser
  • Implement role seeding (Student, Coach, Principal, Official, Admin)
  • Build registration and login views
  • Enforce school-required rule for Student/Coach/Principal roles
  • Build user management CRUD for admins

Phase 3 — Core Domain (Events, Tournaments, Zones)

  • Build Zone CRUD
  • Build School CRUD (with zone assignment and school level)
  • Build EventLevel management (admin can add/edit levels)
  • Build Event CRUD (with category, allowed event levels, relay flag)
  • Build Equipment Spec management per event/event level
  • Build Tournament CRUD with status lifecycle
  • Build TournamentEventLevel setup (assign events to levels per tournament, with age waiver toggle)
  • Implement tournament archiving and un-archiving

Phase 4 — Student Registration & Event Registration

  • Build Student CRUD (with StudentId PK, ExistingStudentId unique candidate key, school assignment, age calculation)
  • Build event registration workflow
  • Implement event level eligibility validation (sex match, school level match)
  • Implement Primary level registration (Junior/Senior — no age check)
  • Implement Secondary/College age-based level validation (compete-up rule)
  • Implement age limit waiver per TournamentEventLevel
  • Implement sex eligibility validation
  • Implement relay team registration (4 students per school)
  • Build registration views for coaches/principals

Phase 5 — Track Event Heats & Rounds

  • Build HeatService for round/heat/lane management
  • Implement round structure configuration per TournamentEventLevel (Heats only, Heats + Finals, Heats + Semis + Finals)
  • Implement seeding logic (random, by performance, manual)
  • Build heat/lane assignment UI for admins
  • Build time recording UI for officials (per heat per lane)
  • Implement advancement logic (top N per heat + fastest losers)
  • Implement auto-population of next round from advancing students
  • Allow admin to skip semi-finals or adjust round structure mid-tournament

Phase 6 — Scoring Engine

  • Build ScoringService with World Athletics formula
  • Store scoring constants (A, B, C) per event in the database, seed defaults
  • Implement track event scoring — derive final Score from Finals round HeatLane times
  • Implement field event scoring (distance-based)
  • Implement high jump scoring with attempt tracking and adjustable heights
  • Build score entry UI for officials (field events + high jump)
  • Implement placement calculation and placement points
  • Implement school points aggregation with tiebreaker logic
  • Build admin UI for configuring scoring constants and placement point values

Phase 7 — Dashboard & Reports

  • Build admin dashboard (stats, top schools, recent scores)
  • Implement report generation service
  • Build each report:
    • Score Sheets (blank + pre-filled)
    • Popular Events
    • Registration by Gender
    • Event-Gender-Level Report
    • Event-School Report
    • Students by School Report
    • Scores by Event Report
    • Student Points Report
  • Implement print-friendly CSS and/or PDF export
  • Add report filters (tournament, zone, school, event, event level)

Phase 8 — Polish & Testing

  • Write unit tests for Domain logic (age calculation, eligibility, scoring)
  • Write unit tests for Application services
  • Write integration tests for repositories
  • UI/UX review and polish
  • Role-based access control testing across all controllers
  • Performance testing with realistic data volumes
  • Seed database with sample data for demonstration

7. Key Business Rules (Quick Reference)

  1. Event Levels combine division + sex (e.g., "Under 17 Boys", "Junior Girls") and are a first-class entity.
  2. Primary levels (Junior/Senior) have no age cutoffs — all primary students compete; division is at coach/admin discretion.
  3. Secondary/College levels are age-based (Under 14 through Under 21, plus Open) — student age is computed from DOB relative to tournament start date.
  4. Students may compete up in age level, never down (Secondary/College only). Open has no age ceiling.
  5. Events can have their age restriction waived per tournament-event-level when groups are too small.
  6. Secondary and College students compete together in the SSC zone.
  7. Students, Coaches, and Principals must belong to a school.
  8. Relay teams consist of exactly 4 students from the same school, all meeting eligibility.
  9. Track events progress through rounds: Heats → (Semi-finals) → Finals. Semi-finals are skippable.
  10. Seeding assigns students to heats/lanes (random, by performance, or manual).
  11. Advancement from heats/semis is by top N per heat + fastest losers (admin-configurable).
  12. Only the Finals round produces placement points for track events. Heat/semi times are for advancement only.
  13. High Jump tracks individual attempts (Clear/Fail/Pass) at each height; three consecutive failures = elimination.
  14. Scoring constants are stored in the database and are admin-editable.
  15. Placement points are admin-configurable (default: 1st=10, 2nd=8, 3rd=6, 4th=5, 5th=4, 6th=3, 7th=2, 8th=1).
  16. Tiebreakers for school rankings: most 1st-place finishes, then 2nd, then 3rd, etc.
  17. Archived tournaments are read-only but remain accessible for reports.
  18. StudentId is the auto-increment surrogate PK; ExistingStudentId is the unique candidate key (school-assigned ID).

8. Seed Data Requirements

The following data should be seeded for development and demonstration:

  • 8 Zones as listed in R7
  • 18 Event Levels: Junior Boys/Girls, Senior Boys/Girls (Primary); Under 14/15/16/17/20/21 Boys/Girls, Open Boys/Girls (Secondary/College)
  • 69 Schools — the complete list below (all real Dominica schools)
  • Standard events: All events listed in R6 with their equipment specs
  • Scoring constants: Seeded from the World Athletics table
  • Default placement points: 10-8-6-5-4-3-2-1
  • Admin user: Default admin account for initial access
  • 5 roles: Seeded via Identity role manager

Complete School List (69 schools)

Secondary School / College Zone (17 schools)

School Name Short Name Level
Academic School of Learning ACADEMIX College
Arthur Waldron Seventh-day Adventist Academy AWSDAA Secondary
Business Training Center BTC College
Castle Bruce Secondary School CBSS Secondary
Convent High School CHS Secondary
Dominica Community High School DCHS Secondary
Dominica Grammar School DGS Secondary
Dominica State College DSC College
Goodwill Secondary School GSS Secondary
Isaiah Thomas Secondary School ITSS Secondary
North East Comprehensive School NECS Secondary
Orion Academy ORION Secondary
Pierre Charles Secondary School PCSS Secondary
Portsmouth Secondary School PSS Secondary
St Martin's Secondary School SMSS Secondary
St Mary's Academy SMA Secondary
Wesley High School WHS Secondary

North West Zone (8 schools)

School Name Short Name Level
Cambell Primary School Primary
Colihaut Primary School Primary
Coulibistrie Primary School Primary
Dublanc Primary School Primary
Kelleb Laurent Primary School Primary
Mahaut Primary School Primary
Salisbury Primary School Primary
Warner Primary School Primary

North Zone (9 schools)

School Name Short Name Level
Baroness Patricia Scotland Primary School Primary
Bense Primary School Primary
Clifton Primary School Primary
Paix Bouche Primary School Primary
Penville Primary School Primary
Roosevelt Douglas Primary School Primary
Savanne Paille Primary School Primary
St. John's Primary School Primary
Thibaud Primary School Primary

North East Zone (8 schools)

School Name Short Name Level
Atkinson Primary School Primary
Calibishie Primary School Primary
Concord Primary School Primary
Lighthouse Christian Academy Primary
Salybia Primary School Primary
Wesley Primary School Primary
Wills Stratmore Steven Primary School Primary
Woodford Hill Primary School Primary

South East Zone (8 schools)

School Name Short Name Level
Belles Primary School Primary
Castle Bruce Primary School Primary
Delices Primary School Primary
Grand Fond Primary School Primary
Jones Beaupierre Primary School Primary
Morne Jaune Primary School Primary
San Sauver Primary School Primary
Sineku Primary School Primary

South Zone (5 schools)

School Name Short Name Level
Bagatelle Primary School Primary
Bellevue Chopin Primary Primary
Grand Bay Primary School Primary
Petite Savanne Primary School Primary
Tete Morne Primary School Primary

South West Zone (7 schools)

School Name Short Name Level
Giraudel Primary School Primary
Morne Prosper Primary School Primary
Newtown Primary School Primary
Soufriere Primary School Primary
St. Luke's Primary School Primary
Trafalgar Primary School Primary
Wotton Waven Primary School Primary

West Central Zone (7 schools)

School Name Short Name Level
Berean Academy Primary
Christian Union Primary Primary
Goodwill Primary School Primary
Massacre Primary School Primary
Pioneer Preparatory Primary
St. Martin's Primary School Primary
St. Mary's Primary Primary

9. Security Considerations

  • All passwords hashed via ASP.NET Core Identity (bcrypt/PBKDF2).
  • Role-based authorization on every controller action.
  • CSRF protection via antiforgery tokens on all forms.
  • Input validation on both client (JavaScript) and server (FluentValidation).
  • SQL injection prevention via EF Core parameterized queries.
  • HTTPS enforced in production.
  • Sensitive configuration (connection strings) stored in user secrets or environment variables, not in appsettings.json.

10. Glossary

Term Definition
Advancement Process of qualifying students from one round to the next (top N per heat + fastest losers)
Age Limit Waiver An admin toggle on a TournamentEventLevel that removes the age check, opening the event to all students of the matching sex
Compete-Up Rule allowing Secondary/College students to enter events at a higher age-based level than their own
Event Category One of Track, Field, or High Jump
Event Level A competitive division combining division name + sex (e.g., "Under 17 Boys", "Junior Girls"). First-class entity with 18 seeded records.
ExistingStudentId The student's pre-existing school-assigned ID number, used as a unique candidate key
Fastest Losers Non-automatic qualifiers who advance to the next round by having the best times among athletes who didn't finish top N in their heat
Heat A single race within a round; multiple heats run when there are more athletes than lanes
HeatLane Assignment of a student to a specific lane in a specific heat, with recorded time and advancement status
Placement Points Points awarded to a school based on a student's finishing position in an event's Finals
Round A stage of a track event: Heats, Semi-finals (optional), or Finals
Scoring Constants The A, B, C coefficients used in the World Athletics scoring formula
Seeding Assigning students to heats and lanes before a round begins (random, by performance, or manual)
StudentId Auto-increment surrogate primary key for the Student entity
TournamentEventLevel Junction entity linking a Tournament + Event + EventLevel, with optional age waiver flag. The core scheduling/registration unit.
Zone A geographic (or organizational) grouping of schools for preliminary competitions
SSC Zone The Secondary School / College zone where secondary and college students compete together