Files
HIPCTF2/.kilo/plans/907.md
T

7.0 KiB
Raw Blame History

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 consumes EventStatusStore for its anchor-based one-second countdown and ChallengesStore/ChallengesApiService for board, detail, solve, and SSE data. Pure countdown helpers are currently duplicated in frontend/src/app/core/services/event-status.pure.ts and frontend/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 dedicated tests/frontend/ tree. Root npm test executes backend and frontend projects through tests/jest.config.js, while npm run test:frontend provides 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, /data assets, or setup steps are required. Existing Angular HttpClient, Jest, jsdom, and ts-jest are sufficient; setup.sh does not need modification. Verification should use the existing root npm test and npm run build scripts; 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 with include=solvers so the modal receives the servers 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 sends include=solvers and 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

  1. Database / Schema Migration: No migration. Solver records, event state, scoring, and backend detail assembly are already correct and must remain unchanged.
  2. Backend Logic & APIs: No backend implementation change. The existing GET /api/v1/challenges/:id flow in backend/src/modules/challenges/challenges.controller.ts and ChallengesService.getDetail() already retrieves solvers. Preserve the current API contract and add the clients expected include=solvers query parameter rather than changing solve/event-state behavior.
  3. Frontend UI Integration:
    1. Change the countdown formatter contract from DD:HH:MM to a second-bearing representation while preserving all four units, e.g. DD:HH:MM:SS; compute seconds = floor(totalSeconds) % 60, zero-pad every component, and retain the existing 00:00:00:00 fallback for negative/non-finite input. This makes values such as 24, 23, and 22 render distinctly and lets the existing EventStatusStore.tick signal drive visible one-second updates without introducing another timer.
    2. 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.countdownText and EventStatusStore.countdownText on the same output contract.
    3. Update ChallengesApiService.getDetail() to pass typed query params containing include: 'solvers' alongside withCredentials: true. Keep URL encoding and existing catchError envelope conversion unchanged.
    4. Leave modal submission state handling intact: successful and idempotent solve responses already replace the modals solver signal from resp.solvers. The detail-query fix addresses newly opened/reopened modals by ensuring their initial server fetch explicitly requests solver data.
    5. 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.

4. Test Strategy

  • Target Unit Test File:
    • tests/frontend/event-status.store.spec.ts: assert final-minute formatting (for example, 24 -> 00:00:00:24 and 23 -> 00:00:00:23) plus representative multi-day formatting and invalid input.
    • tests/frontend/challenges.pure.spec.ts and tests/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: instantiate ChallengesApiService with Angulars HTTP testing providers, call getDetail(id), assert the request URL/method, withCredentials, and include=solvers, flush a small ChallengeDetail, 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() plus provideHttpClientTesting()/HttpTestingController for the detail request. Flush an in-memory detail payload and call verify() after each HTTP test. Do not start NestJS, SQLite, SSE, timers requiring real waiting, a browser, or visual tooling; no persistent /data fixture is needed. Run all automated checks from the repository root with npm test, then npm run build for Angular/NestJS compilation.