feat: add current match page and live kill feed
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
---
|
||||
id: TASK-150
|
||||
title: Server card history and current match entrypoints
|
||||
status: done
|
||||
type: frontend
|
||||
team: Frontend Senior
|
||||
supporting_teams: []
|
||||
roadmap_item: rcon-full-data
|
||||
priority: high
|
||||
---
|
||||
|
||||
# TASK-150 - Server card history and current match entrypoints
|
||||
|
||||
## Goal
|
||||
|
||||
Add server-specific navigation buttons to the home page and make the internal
|
||||
historical page accept an initial server filter through the URL.
|
||||
|
||||
## Background
|
||||
|
||||
The home page currently renders live server cards in
|
||||
`frontend/assets/js/main.js`. Each server card currently has a single
|
||||
"Historico" action built through `renderServerAction(server)`.
|
||||
|
||||
We need clearer per-server actions for the active Comunidad Hispana servers:
|
||||
|
||||
- Open the public current scoreboard.
|
||||
- Open our internal historical page already filtered by that server.
|
||||
- Open our future internal live/current match page already filtered by that
|
||||
server.
|
||||
|
||||
Important URL correction:
|
||||
|
||||
The current public scoreboard URLs are the base scoreboard URLs, without
|
||||
`/games`:
|
||||
|
||||
- `comunidad-hispana-01` -> `https://scoreboard.comunidadhll.es`
|
||||
- `comunidad-hispana-02` -> `https://scoreboard.comunidadhll.es:5443`
|
||||
|
||||
The `/games` URLs are only for the external public historical scoreboard, if
|
||||
needed later:
|
||||
|
||||
- `comunidad-hispana-01` -> `https://scoreboard.comunidadhll.es/games`
|
||||
- `comunidad-hispana-02` -> `https://scoreboard.comunidadhll.es:5443/games`
|
||||
|
||||
## Constraints / DO NOT BREAK
|
||||
|
||||
- Do not change backend storage.
|
||||
- Do not change RCON ingestion.
|
||||
- Do not change scoreboard correlation logic.
|
||||
- Do not depend on server #03.
|
||||
- Do not expose arbitrary URLs received from API payloads.
|
||||
- Do not remove existing server card live status rendering.
|
||||
- Do not implement the full live match page in this task.
|
||||
- Keep the change frontend-focused and minimal.
|
||||
- Preserve existing responsive layout.
|
||||
|
||||
## Allowed Changes
|
||||
|
||||
- `frontend/assets/js/main.js`
|
||||
- `frontend/assets/css/main.css` or equivalent home CSS file
|
||||
- historical page JS/CSS/HTML files needed to support `?server=`
|
||||
- optionally add a minimal placeholder `partida-actual.html` if needed to
|
||||
avoid a broken link
|
||||
- docs only if needed
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
1. Replace the current single "Historico" server-card action with a small
|
||||
action group.
|
||||
2. For each active supported server, render these actions:
|
||||
- "Scoreboard público"
|
||||
- "Nuestro histórico"
|
||||
- "Partida actual"
|
||||
3. "Scoreboard público" must open the current public scoreboard base URL:
|
||||
- `comunidad-hispana-01` -> `https://scoreboard.comunidadhll.es`
|
||||
- `comunidad-hispana-02` -> `https://scoreboard.comunidadhll.es:5443`
|
||||
It must NOT append `/games`.
|
||||
4. "Nuestro histórico" must open the internal historical page with a server
|
||||
query parameter:
|
||||
- `historico.html?server=comunidad-hispana-01`
|
||||
- `historico.html?server=comunidad-hispana-02`
|
||||
5. "Partida actual" must open:
|
||||
- `partida-actual.html?server=comunidad-hispana-01`
|
||||
- `partida-actual.html?server=comunidad-hispana-02`
|
||||
6. Add trusted frontend mappings for supported active servers only:
|
||||
- `comunidad-hispana-01`
|
||||
- `comunidad-hispana-02`
|
||||
Do not add server #03.
|
||||
7. The server identifier should be resolved from the server payload using
|
||||
`external_server_id` or another already existing stable server slug. If the
|
||||
server cannot be resolved to a trusted known server, do not render
|
||||
public/current-match actions for it.
|
||||
8. Update the historical page initialization so that:
|
||||
- `?server=comunidad-hispana-01` selects Comunidad Hispana #01 instead of
|
||||
defaulting to all servers.
|
||||
- `?server=comunidad-hispana-02` selects Comunidad Hispana #02 instead of
|
||||
defaulting to all servers.
|
||||
- unknown or missing server query values fall back to the current default
|
||||
behavior.
|
||||
9. If `partida-actual.html` does not exist yet, create a minimal placeholder
|
||||
page that:
|
||||
- reads `?server=`
|
||||
- displays "Partida actual"
|
||||
- displays the selected server slug/name
|
||||
- explains that the live detail view will be implemented in the next task
|
||||
- includes a safe link back to the home page and historical page
|
||||
Do not implement live data polling yet.
|
||||
10. Ensure all generated URLs are built from trusted constants, not directly
|
||||
from API-provided arbitrary values.
|
||||
|
||||
## Files to Read First
|
||||
|
||||
- `AGENTS.md`
|
||||
- `ai/architecture-index.md`
|
||||
- `ai/repo-context.md`
|
||||
- `ai/orchestrator/frontend-senior.md`
|
||||
- `frontend/assets/js/main.js`
|
||||
- historical page files used for the existing server filter flow
|
||||
|
||||
## Expected Files to Modify
|
||||
|
||||
- `frontend/assets/js/main.js`
|
||||
- home CSS only if the new action group needs layout styling
|
||||
- historical page files needed for `?server=` initialization
|
||||
- `partida-actual.html` only if a placeholder is needed
|
||||
|
||||
## Validation
|
||||
|
||||
- Run `node --check` on every modified frontend JS file.
|
||||
- Review `git diff --name-only` and confirm the changed files match this task.
|
||||
|
||||
## Manual Verification
|
||||
|
||||
1. Open the home page.
|
||||
2. Verify Comunidad Hispana #01 card shows:
|
||||
- Scoreboard público
|
||||
- Nuestro histórico
|
||||
- Partida actual
|
||||
3. Verify Comunidad Hispana #02 card shows:
|
||||
- Scoreboard público
|
||||
- Nuestro histórico
|
||||
- Partida actual
|
||||
4. Click "Scoreboard público" for Comunidad Hispana #01 and verify it opens:
|
||||
`https://scoreboard.comunidadhll.es`
|
||||
5. Click "Scoreboard público" for Comunidad Hispana #02 and verify it opens:
|
||||
`https://scoreboard.comunidadhll.es:5443`
|
||||
6. Click "Nuestro histórico" for Comunidad Hispana #01 and verify the
|
||||
historical page loads with Comunidad Hispana #01 selected.
|
||||
7. Click "Nuestro histórico" for Comunidad Hispana #02 and verify the
|
||||
historical page loads with Comunidad Hispana #02 selected.
|
||||
8. Click "Partida actual" for both servers and verify the page opens with the
|
||||
correct server query parameter.
|
||||
9. Verify no server #03 action is introduced.
|
||||
|
||||
## Commit Message
|
||||
|
||||
`feat: add current match server entrypoints`
|
||||
|
||||
## Expected Outcome
|
||||
|
||||
The home page exposes clear per-server navigation actions, and the internal
|
||||
historical page can open directly filtered by server.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Replaced the home server-card history URL path with a trusted frontend action
|
||||
catalog for active servers `comunidad-hispana-01` and
|
||||
`comunidad-hispana-02` only. Payload-provided `community_history_url`
|
||||
values and the previous server #03 fallback are no longer used for those
|
||||
card actions.
|
||||
- Added the three per-server entrypoints from trusted constants: public
|
||||
scoreboard base URL, internal historical filter URL and internal current
|
||||
match URL.
|
||||
- Confirmed `frontend/assets/js/historico.js` already normalizes the supported
|
||||
`?server=` values into the active selector and falls back to `all-servers`
|
||||
for unknown or missing values, so no historical page code change was needed.
|
||||
- Added a minimal `partida-actual.html` placeholder with a trusted server label
|
||||
map and safe internal links for TASK-151 to upgrade.
|
||||
- Validation: `node --check frontend/assets/js/main.js`.
|
||||
- Scope review: `git diff --name-only` and `git status --short` were reviewed
|
||||
for the task move plus frontend files. Browser click verification was not
|
||||
completed because the in-app browser JavaScript control tool was not
|
||||
available after tool discovery in this session.
|
||||
|
||||
## Change Budget
|
||||
|
||||
- Prefer fewer than 5 modified files.
|
||||
- Prefer changes under 200 lines when feasible.
|
||||
- Split the work into follow-up tasks if the scope grows.
|
||||
190
ai/tasks/done/TASK-151-current-match-page-base.md
Normal file
190
ai/tasks/done/TASK-151-current-match-page-base.md
Normal file
@@ -0,0 +1,190 @@
|
||||
---
|
||||
id: TASK-151
|
||||
title: Current match page base
|
||||
status: done
|
||||
type: frontend
|
||||
team: Frontend Senior
|
||||
supporting_teams:
|
||||
- Backend Senior
|
||||
roadmap_item: rcon-full-data
|
||||
priority: high
|
||||
---
|
||||
|
||||
# TASK-151 - Current match page base
|
||||
|
||||
## Goal
|
||||
|
||||
Create the first functional internal "Partida actual" page for active
|
||||
Comunidad Hispana servers.
|
||||
|
||||
## Background
|
||||
|
||||
The home page will link to
|
||||
`partida-actual.html?server=<server_slug>`. We need the first real version of
|
||||
our internal current-match page.
|
||||
|
||||
This page should be visually aligned with the existing historical match detail
|
||||
page, but it represents a live match instead of a closed historical match.
|
||||
|
||||
Important public scoreboard URLs:
|
||||
|
||||
- `comunidad-hispana-01` -> `https://scoreboard.comunidadhll.es`
|
||||
- `comunidad-hispana-02` -> `https://scoreboard.comunidadhll.es:5443`
|
||||
|
||||
These are base URLs for the current public scoreboard and must not include
|
||||
`/games`.
|
||||
|
||||
## Constraints / DO NOT BREAK
|
||||
|
||||
- Do not break the existing historical page.
|
||||
- Do not break the existing match detail page.
|
||||
- Do not change scoreboard correlation logic.
|
||||
- Do not implement the live kill feed in this task unless there is already a
|
||||
safe endpoint that can be reused trivially.
|
||||
- Do not fabricate closed-match data.
|
||||
- Do not show final winner/duration/closed_at for a live match.
|
||||
- Do not depend on server #03.
|
||||
- Do not expose untrusted public scoreboard URLs.
|
||||
- Keep polling moderate and safe.
|
||||
|
||||
## Allowed Changes
|
||||
|
||||
- `partida-actual.html`
|
||||
- new frontend JS/CSS for current match page
|
||||
- backend API endpoint only if needed
|
||||
- backend read-model code only if needed for current live state
|
||||
- tests where practical
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
1. Create or upgrade `partida-actual.html` as a real live-current-match page.
|
||||
2. The page must read `?server=` from the URL.
|
||||
3. Supported server values:
|
||||
- `comunidad-hispana-01`
|
||||
- `comunidad-hispana-02`
|
||||
4. Unknown server values must show a safe error/empty state and must not build
|
||||
external URLs from the unknown value.
|
||||
5. Add trusted current public scoreboard links:
|
||||
- `comunidad-hispana-01` -> `https://scoreboard.comunidadhll.es`
|
||||
- `comunidad-hispana-02` -> `https://scoreboard.comunidadhll.es:5443`
|
||||
6. Add a "Ver scoreboard público" button using the trusted base URL for that
|
||||
server.
|
||||
7. The page should display a live-match header with:
|
||||
- server name
|
||||
- live/online status
|
||||
- current map
|
||||
- game mode if available
|
||||
- `started_at` if available
|
||||
- current players / max players if available
|
||||
- last updated/captured timestamp
|
||||
8. The page should display a scoreboard panel:
|
||||
- allied score if available
|
||||
- axis score if available
|
||||
- neutral state if scores are unavailable
|
||||
9. Do not display:
|
||||
- final duration
|
||||
- final winner
|
||||
- `closed_at`
|
||||
- any copy implying that the match has finished
|
||||
10. Add a placeholder section for future live kill feed:
|
||||
- title: "Feed de combate"
|
||||
- text explaining that live kill events will appear here when enabled
|
||||
- no fake kill rows
|
||||
11. Add a player table section if current player stats are already available
|
||||
from existing APIs. If they are not available, show a clean placeholder:
|
||||
- "Las estadísticas en vivo aparecerán cuando haya datos suficientes."
|
||||
12. Add frontend polling with safe in-flight protection:
|
||||
- default interval: 30 seconds
|
||||
- avoid overlapping requests
|
||||
- show stale/error states clearly
|
||||
13. If no backend endpoint exists for current match state, add a minimal
|
||||
endpoint that derives the current server state from existing live/RCON
|
||||
snapshot data. Keep it read-only.
|
||||
14. The endpoint response should be stable and minimal:
|
||||
- server slug/name
|
||||
- status
|
||||
- map
|
||||
- `game_mode`
|
||||
- `started_at`
|
||||
- `allied_score`
|
||||
- `axis_score`
|
||||
- players
|
||||
- `max_players`
|
||||
- `captured_at`/`updated_at`
|
||||
- `public_scoreboard_url` from trusted mapping
|
||||
|
||||
## Files to Read First
|
||||
|
||||
- `AGENTS.md`
|
||||
- `ai/architecture-index.md`
|
||||
- `ai/repo-context.md`
|
||||
- `ai/orchestrator/frontend-senior.md`
|
||||
- current historical match detail frontend files
|
||||
- live server backend/read-model files used by the existing server cards
|
||||
|
||||
## Expected Files to Modify
|
||||
|
||||
- `partida-actual.html`
|
||||
- new current-match frontend JS/CSS files as needed
|
||||
- minimal live-state backend endpoint/read-model files only if existing APIs
|
||||
cannot supply the page state
|
||||
- focused tests where practical
|
||||
|
||||
## Validation
|
||||
|
||||
- `python -m compileall backend/app`
|
||||
- Run backend tests relevant to live server/read model if available.
|
||||
- Run `node --check` on modified/new frontend JS files.
|
||||
- Review `git diff --name-only` and confirm the changed files match this task.
|
||||
|
||||
## Manual Verification
|
||||
|
||||
1. Open `partida-actual.html?server=comunidad-hispana-01`.
|
||||
2. Open `partida-actual.html?server=comunidad-hispana-02`.
|
||||
3. Verify the public scoreboard button opens:
|
||||
- `https://scoreboard.comunidadhll.es`
|
||||
- `https://scoreboard.comunidadhll.es:5443`
|
||||
4. Verify `/games` is not used for the current public scoreboard button.
|
||||
5. Verify no final/closed-match fields are shown.
|
||||
6. Verify unknown server query values do not create unsafe links.
|
||||
|
||||
## Commit Message
|
||||
|
||||
`feat: add current match page base`
|
||||
|
||||
## Expected Outcome
|
||||
|
||||
A safe first version of the internal current-match page exists and can display
|
||||
live server/match state without pretending the match is closed.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Upgraded `partida-actual.html` into the first internal live match page and
|
||||
kept it aligned with the existing historical shell/styles.
|
||||
- Added frontend polling every 30 seconds with an in-flight guard. The page
|
||||
rejects unknown `?server=` values before building any external link, and the
|
||||
public scoreboard button is populated only from the trusted backend
|
||||
projection.
|
||||
- Added read-only `GET /api/current-match?server=`. It supports only active
|
||||
trusted scoreboard origins and projects the existing live server snapshot
|
||||
fields into the current-match shape. The current live snapshot persistence
|
||||
exposes status, map, population and capture time; score, game mode and match
|
||||
start fields remain `null`/unavailable when the snapshot source does not
|
||||
provide them.
|
||||
- Kept the combat feed and live player statistics as honest empty placeholders
|
||||
for the follow-up tasks rather than fabricating closed-match or kill data.
|
||||
- Validation: `python -m compileall backend/app`;
|
||||
`node --check frontend/assets/js/partida-actual.js`;
|
||||
`powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`;
|
||||
narrow inline route guard check for missing/unknown current-match server
|
||||
values; narrow inline payload projection check using a controlled live
|
||||
snapshot document.
|
||||
- Scope review: `git diff --name-only` and `git status --short` were reviewed.
|
||||
No focused product route test file exists in `backend/tests` for this API
|
||||
bootstrap layer yet.
|
||||
|
||||
## Change Budget
|
||||
|
||||
- Prefer fewer than 5 modified files.
|
||||
- Prefer changes under 200 lines when feasible.
|
||||
- Split the work into follow-up tasks if the scope grows.
|
||||
174
ai/tasks/done/TASK-152-current-match-live-kill-feed.md
Normal file
174
ai/tasks/done/TASK-152-current-match-live-kill-feed.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
id: TASK-152
|
||||
title: Current match live kill feed
|
||||
status: done
|
||||
type: backend
|
||||
team: Backend Senior
|
||||
supporting_teams:
|
||||
- Frontend Senior
|
||||
roadmap_item: rcon-full-data
|
||||
priority: high
|
||||
---
|
||||
|
||||
# TASK-152 - Current match live kill feed
|
||||
|
||||
## Goal
|
||||
|
||||
Expose recent current-match kill events and render them as a live visual feed
|
||||
on `partida-actual.html`.
|
||||
|
||||
## Background
|
||||
|
||||
The current-match page will exist at
|
||||
`partida-actual.html?server=<server_slug>`. The backend already stores/parses
|
||||
RCON AdminLog data and materializes kill/player stats for historical matches.
|
||||
|
||||
Existing materialization logic uses AdminLog kill payload fields such as:
|
||||
|
||||
- `killer_id`
|
||||
- `killer_name`
|
||||
- `killer_team`
|
||||
- `victim_id`
|
||||
- `victim_name`
|
||||
- `victim_team`
|
||||
- `weapon`
|
||||
|
||||
We now want a live/current-match kill feed similar to a FPS kill feed: killer,
|
||||
weapon, victim, teamkill distinction, timestamp.
|
||||
|
||||
## Constraints / DO NOT BREAK
|
||||
|
||||
- Do not query RCON directly from the frontend.
|
||||
- Do not expose raw AdminLog lines.
|
||||
- Do not expose admin-only/sensitive fields.
|
||||
- Do not break existing historical materialization.
|
||||
- Do not break existing match detail player stats.
|
||||
- Do not depend on server #03.
|
||||
- Do not fabricate kill events.
|
||||
- Do not duplicate kill rows on repeated polling.
|
||||
- Keep polling safe.
|
||||
|
||||
## Allowed Changes
|
||||
|
||||
- backend endpoint for current match kill feed
|
||||
- backend read-model/helper for current/open match event window
|
||||
- frontend current-match JS/CSS
|
||||
- tests for event normalization/filtering where practical
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
1. Add a backend endpoint for recent current-match kill events by server.
|
||||
2. Supported servers:
|
||||
- `comunidad-hispana-01`
|
||||
- `comunidad-hispana-02`
|
||||
3. Unknown server values must return a safe 400/404 style response and must
|
||||
not query arbitrary targets.
|
||||
4. The endpoint should return normalized event rows:
|
||||
- `event_id`
|
||||
- `event_timestamp` or `server_time`
|
||||
- `killer_name`
|
||||
- `killer_team`
|
||||
- `victim_name`
|
||||
- `victim_team`
|
||||
- `weapon`
|
||||
- `is_teamkill`
|
||||
- confidence/source if needed
|
||||
5. The endpoint should only return events belonging to the current/open match
|
||||
if that can be determined.
|
||||
6. If the current/open match window cannot be determined reliably, return a
|
||||
safe recent window and include a clear confidence marker, for example:
|
||||
- scope: `"recent-admin-log-window"`
|
||||
- confidence: `"partial"`
|
||||
7. Do not return raw AdminLog text.
|
||||
8. Add frontend rendering for a kill feed:
|
||||
- newest events visible at top or bottom consistently
|
||||
- killer name
|
||||
- weapon label/icon placeholder
|
||||
- victim name
|
||||
- timestamp
|
||||
- teamkill visual distinction
|
||||
9. Prevent duplicate rendering:
|
||||
- track `event_id` values already rendered
|
||||
- update existing rows only if needed
|
||||
10. Poll every 15-30 seconds.
|
||||
11. Add an empty state:
|
||||
- "Todavía no se han detectado bajas en esta partida."
|
||||
12. Add an error/stale state:
|
||||
- "No se pudo actualizar el feed de combate."
|
||||
13. Do not show fake/sample kill events in production UI.
|
||||
|
||||
## Files to Read First
|
||||
|
||||
- `AGENTS.md`
|
||||
- `ai/architecture-index.md`
|
||||
- `ai/repo-context.md`
|
||||
- `ai/orchestrator/backend-senior.md`
|
||||
- current-match page files created by TASK-151
|
||||
- AdminLog materialization/read-model files that already normalize kill data
|
||||
|
||||
## Expected Files to Modify
|
||||
|
||||
- backend current-match kill feed endpoint/read-model files
|
||||
- current-match frontend JS/CSS files
|
||||
- focused tests for event normalization/filtering where practical
|
||||
|
||||
## Validation
|
||||
|
||||
- `python -m compileall backend/app`
|
||||
- Run backend tests related to AdminLog/materialization/current-match feed.
|
||||
- Run `node --check` on current-match frontend JS.
|
||||
- Review `git diff --name-only` and confirm the changed files match this task.
|
||||
|
||||
## Manual Verification
|
||||
|
||||
1. Open `partida-actual.html?server=comunidad-hispana-01`.
|
||||
2. Open `partida-actual.html?server=comunidad-hispana-02`.
|
||||
3. Verify kill feed renders only normalized events.
|
||||
4. Verify repeated polling does not duplicate rows.
|
||||
5. Verify teamkills are visually distinguishable.
|
||||
6. Verify raw AdminLog lines are never displayed.
|
||||
|
||||
## Commit Message
|
||||
|
||||
`feat: add current match live kill feed`
|
||||
|
||||
## Expected Outcome
|
||||
|
||||
The current-match page can show a safe, normalized, non-duplicated live kill
|
||||
feed based on RCON/AdminLog data.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Added read-only `GET /api/current-match/kills?server=&limit=` for the active
|
||||
trusted Comunidad Hispana servers. Unsupported servers fail before any
|
||||
AdminLog query is built.
|
||||
- Added a safe AdminLog kill feed read that emits normalized fields only:
|
||||
generated `event_id`, event time/server time, killer/victim names and teams,
|
||||
weapon, and computed `is_teamkill`. It does not return raw AdminLog text,
|
||||
player ids or admin-only payload fields.
|
||||
- Feed scope prefers `open-admin-log-match-window` with
|
||||
`confidence: "admin-log-boundary"` when the latest AdminLog boundary for the
|
||||
server is an unmatched `match_start`. Otherwise it returns
|
||||
`recent-admin-log-window` with `confidence: "partial"` as the explicit
|
||||
fallback.
|
||||
- Extended `partida-actual.js` to poll the feed with the existing 30-second
|
||||
in-flight-protected current-match refresh cycle, dedupe rows by `event_id`,
|
||||
keep newest events ordered by server/event time, render a TK badge for
|
||||
teamkills, and show empty/error states without fake rows.
|
||||
- Added a focused AdminLog storage test for open-window filtering and teamkill
|
||||
normalization. The environment does not have `pytest` installed (`pytest`
|
||||
and `python -m pytest` both failed), so the same storage normalization path
|
||||
was verified with a narrow inline Python scenario.
|
||||
- Validation: `python -m compileall backend/app`;
|
||||
`node --check frontend/assets/js/partida-actual.js`;
|
||||
`powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`;
|
||||
narrow inline route guard check for missing, unknown and invalid-limit feed
|
||||
requests; inline storage normalization check excluding pre-window kills and
|
||||
confirming no raw message field leaks.
|
||||
- Scope review: `git diff --name-only` and `git status --short` were reviewed.
|
||||
|
||||
## Change Budget
|
||||
|
||||
- Prefer fewer than 5 modified files.
|
||||
- Prefer changes under 200 lines when feasible.
|
||||
- Split the work into follow-up tasks if the scope grows.
|
||||
Reference in New Issue
Block a user