7.0 KiB
7.0 KiB
Implementation Plan: Challenges Page and Challenge Solve Modal 1.03
1. Architectural Reconnaissance
- Codebase style & conventions: Node.js monorepo with an Angular 17 standalone SPA and NestJS API, written in TypeScript. Frontend state uses root-provided signal stores with private mutable signals and readonly/computed public state; HTTP calls are isolated in injectable services and return typed RxJS
Observables. The challenges page consumesEventStatusStorefor its anchor-based one-second countdown andChallengesStore/ChallengesApiServicefor board, detail, solve, and SSE data. Pure countdown helpers are currently duplicated infrontend/src/app/core/services/event-status.pure.tsandfrontend/src/app/features/challenges/challenges.pure.ts, and both drop seconds. - Data Layer: SQLite through TypeORM in the NestJS backend. No schema or persistence change is needed: the event store already recalculates remaining seconds every second, solve persistence is correct,
ChallengesService.getDetail()already loads solver rows, and solve responses already return the updated solver list. - Test Framework & Structure: Jest 29 with
ts-jest; frontend tests use jsdom and live under the dedicatedtests/frontend/tree. Rootnpm testexecutes backend and frontend projects throughtests/jest.config.js, whilenpm run test:frontendprovides the focused frontend run. Keep coverage at pure/helper and HTTP-service boundaries without browser/visual tests. - Required Tools & Dependencies: No new system tools, global CLIs, npm packages,
/dataassets, or setup steps are required. Existing AngularHttpClient, Jest, jsdom, andts-jestare sufficient;setup.shdoes not need modification. Verification should use the existing rootnpm testandnpm run buildscripts; the repository exposes no lint or standalone typecheck script.
2. Impacted Files
- To Modify:
frontend/src/app/core/services/event-status.pure.ts— format countdown output with the actual seconds remaining so computed text changes on every one-second store tick.frontend/src/app/features/challenges/challenges.pure.ts— keep the challenges-page formatter consistent with the shared event-status formatter (or re-export/delegate to one source of truth) so the gate also displays seconds.frontend/src/app/features/challenges/challenges.service.ts— request challenge detail withinclude=solversso the modal receives the server’s current solver list after an event resume and solve.tests/frontend/event-status.store.spec.ts— add/update focused assertions for the final-minute countdown and second-level decrement behavior.tests/frontend/challenges.pure.spec.ts— update the feature formatter contract to include seconds and retain invalid-input coverage.tests/frontend/challenges-page.spec.ts— update countdown expectations/documentation and cover final-minute values used by the page gate.tests/frontend/challenge-modal-submit.spec.ts— update the incidental formatter assertion to the new output shape, keeping solve-modal tests aligned.tests/frontend/challenges.service.spec.ts— add a minimal HTTP boundary regression test asserting that detail loading sendsinclude=solversand preserves the typed detail payload.
- To Create:
tests/frontend/challenges.service.spec.ts— only if no existing service test is present at implementation time; keep it in the dedicated test tree and use Angular HTTP testing utilities rather than a manual browser or backend environment.
3. Proposed Changes
- Database / Schema Migration: No migration. Solver records, event state, scoring, and backend detail assembly are already correct and must remain unchanged.
- Backend Logic & APIs: No backend implementation change. The existing
GET /api/v1/challenges/:idflow inbackend/src/modules/challenges/challenges.controller.tsandChallengesService.getDetail()already retrieves solvers. Preserve the current API contract and add the client’s expectedinclude=solversquery parameter rather than changing solve/event-state behavior. - Frontend UI Integration:
- Change the countdown formatter contract from
DD:HH:MMto a second-bearing representation while preserving all four units, e.g.DD:HH:MM:SS; computeseconds = floor(totalSeconds) % 60, zero-pad every component, and retain the existing00:00:00:00fallback for negative/non-finite input. This makes values such as 24, 23, and 22 render distinctly and lets the existingEventStatusStore.ticksignal drive visible one-second updates without introducing another timer. - Eliminate behavioral drift between the core and challenges formatters by having the challenges pure module delegate to/re-export the shared core formatter, or otherwise apply the exact same implementation if repository import constraints require it. Keep
ChallengesPage.countdownTextandEventStatusStore.countdownTexton the same output contract. - Update
ChallengesApiService.getDetail()to pass typed query params containinginclude: 'solvers'alongsidewithCredentials: true. Keep URL encoding and existingcatchErrorenvelope conversion unchanged. - Leave modal submission state handling intact: successful and idempotent solve responses already replace the modal’s solver signal from
resp.solvers. The detail-query fix addresses newly opened/reopened modals by ensuring their initial server fetch explicitly requests solver data. - Update directly relevant documentation strings/comments or API/countdown labels only if implementation validation confirms they are part of the maintained contract; do not add unrelated UI or backend work.
- Change the countdown formatter contract from
4. Test Strategy
- Target Unit Test File:
tests/frontend/event-status.store.spec.ts: assert final-minute formatting (for example,24 -> 00:00:00:24and23 -> 00:00:00:23) plus representative multi-day formatting and invalid input.tests/frontend/challenges.pure.spec.tsandtests/frontend/challenges-page.spec.ts: update focused formatter/page-gate expectations so seconds are retained rather than frozen at zero.tests/frontend/challenges.service.spec.ts: instantiateChallengesApiServicewith Angular’s HTTP testing providers, callgetDetail(id), assert the request URL/method,withCredentials, andinclude=solvers, flush a smallChallengeDetail, and verify the observable result.tests/frontend/challenge-modal-submit.spec.ts: update only the existing formatter assertion affected by the contract; rely on existing success-path tests for solve-response solver replacement.
- Mocking Strategy: Use pure function calls for countdown coverage and
provideHttpClient()plusprovideHttpClientTesting()/HttpTestingControllerfor the detail request. Flush an in-memory detail payload and callverify()after each HTTP test. Do not start NestJS, SQLite, SSE, timers requiring real waiting, a browser, or visual tooling; no persistent/datafixture is needed. Run all automated checks from the repository root withnpm test, thennpm run buildfor Angular/NestJS compilation.