Fix all 45 audited bugs from bug-fixes.md

Verified every finding against the code, then fixed correctness (redirects,
advancement reset, duplicate heats, high-jump attempt entry, placement
ranking with tie handling, delete-dependency 500s), security (secrets out of
config, config-driven admin seed, login lockout, role authorization with
school scoping, heat-time IDOR, forwarded headers, last-admin guards),
schema integrity (nullable+filtered ExistingStudentId, unique indexes for
rounds/heats/bar heights via SchemaIntegrityFixes migration), performance
(N+1 removal in high jump/reports/standings/dashboard, SQL-side student
paging), and hygiene (duplicate notifications, auto-dismiss scope, local
bootstrap-icons, orphaned files, test-data.sql tournament creation).

FluentValidation is now registered; AutoMapper bumped to 14.0.0 (advisory
fully patched only in licence-changed 15.1.1 — documented). 11 new tests;
63/63 passing. Credential rotation and deploy-time DB_CONNECTION_STRING are
required manual follow-ups, documented in bug-fixes.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 08:30:53 -04:00
parent 78c526ee35
commit 810f721e48
93 changed files with 3251 additions and 1606 deletions

View File

@@ -2,8 +2,9 @@
-- test-data.sql
-- Bulk sample data for the Dominica Sports Division app.
--
-- Adds, for BOTH seeded tournaments (1 = Inter-Zone Championship 2026,
-- 2 = National Championship 2026):
-- Creates two sample tournaments if they do not already exist
-- (Inter-Zone Championship 2026 and National Championship 2026 — the app's
-- seeder deliberately seeds no tournaments), then adds for BOTH of them:
-- * 60 students (30 male / 30 female) spread across the secondary schools
-- * Under-16 Boys & Under-16 Girls event levels for EVERY individual
-- (non-relay) event in the catalogue
@@ -99,12 +100,28 @@ WHERE NOT EXISTS (
);
-- ---------------------------------------------------------------------------
-- 2. TOURNAMENT EVENT LEVELS (every _ev event x U16 Boys/Girls x 2 tournaments)
-- 2. TOURNAMENTS (created idempotently; IDs are resolved by name, never
-- assumed — the application seeder does not create any tournaments)
-- ---------------------------------------------------------------------------
INSERT INTO "Tournaments" ("Name", "StartDate", "EndDate", "SchoolLevel", "IsArchived", "Status")
SELECT v.name, v.sdate::date, v.edate::date, 'Secondary', false, 'InProgress'
FROM (VALUES
('Inter-Zone Championship 2026', '2026-03-16', '2026-03-20'),
('National Championship 2026', '2026-04-13', '2026-04-17')
) AS v(name, sdate, edate)
WHERE NOT EXISTS (SELECT 1 FROM "Tournaments" t WHERE t."Name" = v.name);
CREATE TEMP TABLE _tt ON COMMIT DROP AS
SELECT "TournamentId" AS tid FROM "Tournaments"
WHERE "Name" IN ('Inter-Zone Championship 2026', 'National Championship 2026');
-- ---------------------------------------------------------------------------
-- 3. TOURNAMENT EVENT LEVELS (every _ev event x U16 Boys/Girls x 2 tournaments)
-- Age restriction waived so the U16 sample athletes are always eligible.
-- ---------------------------------------------------------------------------
WITH combos AS (
SELECT t.tid, e."EventId" AS eid, el."EventLevelId" AS lid
FROM (VALUES (1), (2)) AS t(tid)
FROM _tt t
CROSS JOIN _ev
CROSS JOIN (VALUES ('Under 16 Boys'), ('Under 16 Girls')) AS lv(name)
JOIN "Events" e ON e."Name" = _ev.ename
@@ -120,14 +137,14 @@ WHERE NOT EXISTS (
);
-- ---------------------------------------------------------------------------
-- 3. REGISTRATIONS (~16 sample students per event level, sex-matched)
-- 4. REGISTRATIONS (~16 sample students per event level, sex-matched)
-- ---------------------------------------------------------------------------
WITH testtels AS (
SELECT tel."TournamentEventLevelId" AS tid, el."Sex" AS sex
FROM "TournamentEventLevels" tel
JOIN "EventLevels" el ON el."EventLevelId" = tel."EventLevelId"
JOIN "Events" e ON e."EventId" = tel."EventId"
WHERE tel."TournamentId" IN (1, 2)
WHERE tel."TournamentId" IN (SELECT tid FROM _tt)
AND el."Name" IN ('Under 16 Boys', 'Under 16 Girls')
AND e."Name" IN (SELECT ename FROM _ev)
),
@@ -158,7 +175,7 @@ CREATE TEMP TABLE _tel ON COMMIT DROP AS
FROM "TournamentEventLevels" tel
JOIN "EventLevels" el ON el."EventLevelId" = tel."EventLevelId"
JOIN "Events" e ON e."EventId" = tel."EventId"
WHERE tel."TournamentId" IN (1, 2)
WHERE tel."TournamentId" IN (SELECT tid FROM _tt)
AND el."Name" IN ('Under 16 Boys', 'Under 16 Girls')
AND e."Name" IN (SELECT ename FROM _ev);
@@ -338,8 +355,10 @@ COMMIT;
-- Summary (informational; safe to run repeatedly)
-- ---------------------------------------------------------------------------
SELECT 'students (TD-)' AS metric, count(*) AS value FROM "Students" WHERE "ExistingStudentId" LIKE 'TD-%'
UNION ALL SELECT 'event levels (t1)', count(*) FROM "TournamentEventLevels" WHERE "TournamentId" = 1
UNION ALL SELECT 'event levels (t2)', count(*) FROM "TournamentEventLevels" WHERE "TournamentId" = 2
UNION ALL SELECT 'event levels (both tournaments)', count(*)
FROM "TournamentEventLevels" tel
JOIN "Tournaments" t ON t."TournamentId" = tel."TournamentId"
WHERE t."Name" IN ('Inter-Zone Championship 2026', 'National Championship 2026')
UNION ALL SELECT 'registrations (total)', count(*) FROM "EventRegistrations"
UNION ALL SELECT 'scores (total)', count(*) FROM "Scores"
UNION ALL SELECT 'track heat lanes', count(*) FROM "HeatLanes"