feat: add internal match detail links
Add internal match detail links for recent matches without safe external URLs while preserving external links when available.
This commit is contained in:
212
ai/tasks/done/TASK-113-add-internal-match-detail-links.md
Normal file
212
ai/tasks/done/TASK-113-add-internal-match-detail-links.md
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
id: TASK-113
|
||||
title: Add internal match detail links
|
||||
status: pending
|
||||
type: frontend
|
||||
team: Frontend Senior
|
||||
supporting_teams:
|
||||
- Backend Senior
|
||||
roadmap_item: historical
|
||||
priority: high
|
||||
---
|
||||
|
||||
# TASK-113 - Add internal match detail links
|
||||
|
||||
## Goal
|
||||
|
||||
Add implementation support so every card in "Ultimas partidas registradas" links to available match data without fabricating unsafe external scoreboard URLs for synthetic RCON competitive-window match IDs.
|
||||
|
||||
## Context
|
||||
|
||||
The historical page now renders recent matches, but the latest backend response for `/api/historical/snapshots/recent-matches?server=all-servers&limit=5` can return `selected_source: "rcon"` and items with `capture_basis: "rcon-competitive-window"` and no `match_url`.
|
||||
|
||||
The previous implementation correctly renders external "Ver partida" links only when a safe source URL exists. However, current RCON competitive-window matches can use synthetic IDs such as `31:2026-04-13T13:59:26.174488Z`, which are not direct scoreboard `/games/{id}` URLs.
|
||||
|
||||
Product decision:
|
||||
|
||||
- Keep using a safe external `match_url` when one exists.
|
||||
- For matches without a safe external URL, provide an internal match detail page/link.
|
||||
- Do not invent external scoreboard URLs for synthetic RCON match IDs.
|
||||
- Preserve HLL Vietnam's military, Vietnam, tactical and sober visual identity.
|
||||
- Do not reintroduce paused MVP/Elo UI.
|
||||
- Do not reintroduce Comunidad Hispana #03.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Move this task from `ai/tasks/pending/` to `ai/tasks/in-progress/`.
|
||||
2. Inspect the listed files first.
|
||||
3. Confirm the recent matches response shape for `/api/historical/snapshots/recent-matches?server=all-servers&limit=5`, including RCON competitive-window items without `match_url`.
|
||||
4. Keep the existing safe external `match_url` behavior:
|
||||
- If a recent match item has a safe external `match_url`, render "Ver partida" or "Abrir en scoreboard".
|
||||
- Keep `target="_blank"` and `rel="noopener noreferrer"`.
|
||||
5. Add internal match detail links for recent matches without an external URL:
|
||||
- Render a visible link/button, for example "Ver detalles".
|
||||
- Point it to an internal frontend route/page, for example `historico-partida.html?server={serverSlug}&match={encodedMatchId}`.
|
||||
- URL-encode the match ID.
|
||||
6. Add a simple internal match detail frontend page:
|
||||
- Suggested file: `frontend/historico-partida.html`.
|
||||
- Preserve the current visual identity.
|
||||
- Read `server` and `match` from the query string.
|
||||
- Call a backend endpoint to get available match details.
|
||||
- Show a graceful unavailable or partial-data state if only limited RCON data exists.
|
||||
7. Add or reuse a backend endpoint for match details:
|
||||
- Prefer `/api/historical/matches/detail?server={serverSlug}&match={matchId}`.
|
||||
- Return available data for both persisted scoreboard matches and RCON competitive-window matches when available.
|
||||
- At minimum return `server`, `match_id`, `map`, `started_at`, `ended_at` or `closed_at`, `duration_seconds` if available, `player_count` or `peak_players` if available, `result` or `score` if available, `capture_basis` or `capabilities` if available, and external `match_url` if a safe one exists.
|
||||
- Do not fabricate external scoreboard URLs for synthetic RCON IDs.
|
||||
8. Preserve the existing historical page sections and selector behavior:
|
||||
- summary
|
||||
- basic rankings
|
||||
- recent matches
|
||||
- server selector with only Todos, Comunidad Hispana #01 and Comunidad Hispana #02
|
||||
9. Keep these blocks paused or hidden:
|
||||
- MVP mensual V1
|
||||
- MVP mensual V2
|
||||
- Comparativa V1 vs V2
|
||||
- Elo/MMR mensual
|
||||
10. Validate the result with all checks listed below.
|
||||
11. Move this task to `ai/tasks/done/` only after validation is complete and document the outcome in this file.
|
||||
12. Commit and push the completed implementation branch.
|
||||
|
||||
## Files to Read First
|
||||
|
||||
- `ai/architecture-index.md`
|
||||
- `ai/repo-context.md`
|
||||
- `ai/orchestrator/frontend-senior.md`
|
||||
- `ai/orchestrator/backend-senior.md`
|
||||
- `frontend/historico.html`
|
||||
- `frontend/assets/js/historico.js`
|
||||
- `frontend/assets/css/historico.css`
|
||||
- `backend/app/routes.py`
|
||||
- `backend/app/payloads.py`
|
||||
- `backend/app/historical_storage.py`
|
||||
- `backend/app/historical_snapshots.py`
|
||||
- any RCON competitive/recent match read model modules
|
||||
- `scripts/run-integration-tests.ps1`
|
||||
- `docs/decisions.md`
|
||||
|
||||
## Expected Files to Modify
|
||||
|
||||
- `frontend/historico.html`
|
||||
- `frontend/assets/js/historico.js`
|
||||
- `frontend/assets/css/historico.css`
|
||||
- possibly new `frontend/historico-partida.html`
|
||||
- possibly new `frontend/assets/js/historico-partida.js`
|
||||
- possibly `backend/app/routes.py`
|
||||
- possibly `backend/app/payloads.py`
|
||||
- possibly `backend/app/historical_storage.py`
|
||||
- possibly historical snapshot/read model modules
|
||||
- possibly tests under `backend/tests/`
|
||||
- this task file, moved to `ai/tasks/done/`
|
||||
|
||||
If additional files become necessary, explain why in the task outcome and commit message.
|
||||
|
||||
## Expected Files Not to Modify
|
||||
|
||||
- Docker/Compose config
|
||||
- local `.env`
|
||||
- database migrations unless absolutely required and justified
|
||||
- persisted data
|
||||
- Elo/MMR backend implementation files
|
||||
- unrelated frontend pages
|
||||
|
||||
## Constraints
|
||||
|
||||
- Keep the change focused on internal detail links and match detail data.
|
||||
- Do not delete backend code, migrations, persisted data, snapshots or endpoints.
|
||||
- Do not change historical ingestion policy.
|
||||
- Do not reintroduce Comunidad Hispana #03.
|
||||
- Do not reintroduce MVP/Elo UI.
|
||||
- Do not add real credentials.
|
||||
- Do not introduce unnecessary frontend frameworks or dependencies.
|
||||
- Preserve direct browser compatibility where applicable.
|
||||
- Preserve HLL Vietnam branding and product identity.
|
||||
- Do not use public "snapshot" wording in user-facing copy.
|
||||
- Confirm `backend/runtime/` is not created or committed.
|
||||
|
||||
## Validation
|
||||
|
||||
Before completing the task, run:
|
||||
|
||||
- `git status`
|
||||
- `node --check frontend/assets/js/historico.js`
|
||||
- If a new frontend JS file is added, run `node --check` on it too.
|
||||
- `powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`
|
||||
- `docker compose down`
|
||||
- `docker compose up -d --build`
|
||||
- `docker compose ps`
|
||||
- `Invoke-WebRequest http://localhost:8000/health | Select-Object -ExpandProperty Content`
|
||||
- `Invoke-WebRequest http://localhost:8080 | Select-Object -ExpandProperty StatusCode`
|
||||
- `Invoke-WebRequest "http://localhost:8000/api/historical/snapshots/recent-matches?server=all-servers&limit=5" | Select-Object -ExpandProperty Content`
|
||||
- Validate the new match detail endpoint for at least one recent match ID.
|
||||
|
||||
Manual or served HTML verification:
|
||||
|
||||
- Recent match cards show either external "Ver partida" or internal "Ver detalles".
|
||||
- The internal detail page opens and displays available data.
|
||||
- No server #03 appears.
|
||||
- No paused MVP/Elo blocks appear.
|
||||
- No public "snapshot" wording appears.
|
||||
- No migrations or persisted data changed unless explicitly justified.
|
||||
- `backend/runtime/` is not created or committed.
|
||||
|
||||
Before committing, also review:
|
||||
|
||||
- `git diff --name-only`
|
||||
- changed files match the expected scope
|
||||
|
||||
## Commit And Push Requirements
|
||||
|
||||
- Run validation before committing.
|
||||
- Run `git status`.
|
||||
- Stage only intended files.
|
||||
- Commit with a clear message, for example `feat: add internal match detail links`.
|
||||
- Push the branch to origin.
|
||||
- Do not leave completed work only in local.
|
||||
|
||||
## Outcome
|
||||
|
||||
Document the validation performed, notable implementation decisions, and any follow-up task that should be created instead of expanding this task.
|
||||
|
||||
Completed.
|
||||
|
||||
Validation performed:
|
||||
|
||||
- Confirmed `/api/historical/snapshots/recent-matches?server=all-servers&limit=5` returns `selected_source: "rcon"` with RCON competitive-window items such as `31:2026-04-13T13:59:26.174488Z`, `capture_basis: "rcon-competitive-window"` and no `match_url`.
|
||||
- Ran `node --check frontend/assets/js/historico.js`.
|
||||
- Ran `node --check frontend/assets/js/historico-partida.js`.
|
||||
- Ran Python syntax compilation for the touched backend modules.
|
||||
- Ran `powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`; the script reports no product integration tests are configured for this platform-only scope and passed the backend startup import check.
|
||||
- Ran `docker compose down`.
|
||||
- Ran `docker compose up -d --build`.
|
||||
- Ran `docker compose ps`; backend and frontend were up on ports 8000 and 8080.
|
||||
- Verified `http://localhost:8000/health`.
|
||||
- Verified `http://localhost:8080`.
|
||||
- Verified `http://localhost:8000/api/historical/snapshots/recent-matches?server=all-servers&limit=5`.
|
||||
- Verified `http://localhost:8000/api/historical/matches/detail?server=comunidad-hispana-01&match=31%3A2026-04-13T13%3A59%3A26.174488Z` returns the RCON detail internally with `match_url: null`.
|
||||
- Used headless Chrome against `http://localhost:8080/historico.html`; recent RCON cards render `Ver detalles`.
|
||||
- Used headless Chrome against `http://localhost:8080/historico-partida.html?...`; the internal detail page renders available RCON data and the `Ventana competitiva RCON` capture basis.
|
||||
- Confirmed no `backend/runtime/` path exists.
|
||||
|
||||
Implementation decisions:
|
||||
|
||||
- Preserved the existing safe external `match_url` behavior and added `Ver detalles` only when no safe external URL exists.
|
||||
- Added `frontend/historico-partida.html` and `frontend/assets/js/historico-partida.js` as a direct-browser-compatible internal detail page.
|
||||
- Added `/api/historical/matches/detail?server={serverSlug}&match={matchId}`.
|
||||
- Added persisted public-scoreboard detail lookup and exact RCON competitive-window detail lookup.
|
||||
- Kept synthetic RCON match IDs internal and did not fabricate external scoreboard URLs.
|
||||
- Did not reintroduce paused MVP/Elo UI or Comunidad Hispana #03 in the frontend selector.
|
||||
|
||||
Scope note:
|
||||
|
||||
- The task exceeded the preferred 5-file/200-line budget because it required both a new internal frontend page and a backend detail endpoint/read path for two historical sources. No migrations, persisted data, Docker config, `.env`, Elo/MMR implementation files or unrelated frontend pages were changed.
|
||||
|
||||
Follow-up:
|
||||
|
||||
- No follow-up task is required from this implementation. A future task could add richer player-level detail if the RCON historical model later exposes player stats.
|
||||
|
||||
## Change Budget
|
||||
|
||||
- Prefer fewer than 5 modified files.
|
||||
- Prefer changes under 200 lines when feasible.
|
||||
- Split the work into follow-up tasks if limits are exceeded.
|
||||
Reference in New Issue
Block a user