spec: fix upcoming events date filter default and picker bounds (WealthLedger/frontend#63)
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: wealth-ledger-sdd-v2
|
||||
created: 2026-10-14
|
||||
@@ -0,0 +1,63 @@
|
||||
# Design: Upcoming events date filter
|
||||
|
||||
## Context and Constraints
|
||||
|
||||
The account-events page already has a URL-backed filter with draft, Apply,
|
||||
Reset, and date validation. Its view model currently exposes a `maxDate` set to
|
||||
today, which blocks forecast dates; the date picker has no lower bound. The
|
||||
shared `defaultPeriod()` currently subtracts six elapsed 24-hour intervals and
|
||||
formats both instants as Moscow calendar dates, which can collapse to fewer
|
||||
than seven dates around local midnight.
|
||||
|
||||
The `useUrlPeriod()` hook already supplies a default when the URL has no range,
|
||||
preserves valid URL dates (including past dates), and strips invalid or reversed
|
||||
range parameters. Preserve these semantics. The API already supports requested
|
||||
date windows; no API or persistence changes are needed.
|
||||
|
||||
## Technical Goals / Non-Goals
|
||||
|
||||
### Goals
|
||||
|
||||
- Compute the exact seven-date default using Moscow calendar-date boundaries.
|
||||
- Let the date picker select today and future dates only.
|
||||
- Preserve valid past URL periods and existing Apply/Reset behavior.
|
||||
- Keep malformed, impossible, and reversed URL periods on the default path.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
- Change backend event filtering, UTC inclusivity, or saved forecast window
|
||||
intersection behavior.
|
||||
- Remove the page filter or turn the page into a read-only forecast list.
|
||||
- Reject valid past dates at the URL/API boundary.
|
||||
|
||||
## Design
|
||||
|
||||
Use the shared calendar utility as the owner of the default range. Derive the
|
||||
current Moscow calendar date, then calculate the inclusive end as six calendar
|
||||
days later using calendar arithmetic rather than elapsed milliseconds. Keep
|
||||
the output as `YYYY-MM-DD`, matching existing URL and API parameter formats.
|
||||
|
||||
In the account-events page view model, expose today's date as the picker's
|
||||
minimum selectable date and remove the upper date bound. The picker constraint
|
||||
is presentation-only: do not add a future/past check to `isValidPeriod()` or
|
||||
`useUrlPeriod()`. That keeps valid direct URLs independent of what can be newly
|
||||
selected from the UI.
|
||||
|
||||
Keep URL normalization and Apply/Reset ownership where they are. Invalid URL
|
||||
periods continue to be removed with replacement navigation and resolve to the
|
||||
same default range; valid one-sided periods retain current behavior.
|
||||
|
||||
## Data and State
|
||||
|
||||
No new state or API fields are needed. Existing URL parameters remain the
|
||||
applied state; the view model retains draft state until Apply. Today's picker
|
||||
minimum is refreshed when opening the calendar, consistent with the existing
|
||||
today-bound refresh behavior.
|
||||
|
||||
## Verification
|
||||
|
||||
Verify the default range spans seven distinct dates at ordinary times and
|
||||
around Moscow midnight, picker bounds allow future dates and block past dates,
|
||||
valid past URL periods are preserved, and malformed/impossible/reversed ranges
|
||||
fall back to the default. Existing history, Apply, and Reset behavior must
|
||||
remain intact. Use the frontend repository's local verification commands.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Docs Impact: Upcoming events date filter
|
||||
|
||||
## Decision
|
||||
|
||||
Update the existing canonical page `docs/domains/income/upcoming-events.md`
|
||||
after implementation. It already documents the date filter and URL behavior,
|
||||
so no new documentation page is needed.
|
||||
|
||||
## Durable Information to Promote
|
||||
|
||||
Clarify the user-visible default as seven calendar dates inclusive of today,
|
||||
and explain that the date picker permits today and future dates while valid
|
||||
past ranges remain usable when supplied through a direct URL. Invalid date
|
||||
ranges continue to fall back to the default.
|
||||
|
||||
## Not Required
|
||||
|
||||
No API reference, architecture page, glossary, or ADR change is expected: the
|
||||
API contract and forecast-window semantics do not change.
|
||||
|
||||
## Verification
|
||||
|
||||
After implementation, confirm the existing upcoming-events domain page matches
|
||||
the shipped default range, picker bounds, and URL compatibility behavior.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Fix upcoming events date filter
|
||||
|
||||
## Why
|
||||
|
||||
Страница «Будущие события» предназначена для просмотра прогноза, но календарь
|
||||
сейчас запрещает выбрать будущие даты и разрешает выбирать прошедшие. Значение
|
||||
периода по умолчанию также должно соответствовать прогнозному горизонту:
|
||||
семь календарных дат, начиная с сегодняшней.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Оставить URL-backed фильтр периода и действия Apply/Reset.
|
||||
- По умолчанию показывать семь календарных дат включительно: от сегодняшней даты
|
||||
до шестого следующего календарного дня.
|
||||
- В календаре разрешить даты начиная с сегодняшней; не ограничивать доступные
|
||||
даты сверху.
|
||||
- Сохранять валидные периоды из URL, включая прошедшие даты. Некорректный формат,
|
||||
невозможную календарную дату или обратный диапазон нормализовать к периоду по
|
||||
умолчанию.
|
||||
|
||||
## Capabilities
|
||||
|
||||
- `brokerage-account-upcoming-events`
|
||||
|
||||
## Impact
|
||||
|
||||
- `frontend/`: фильтр и URL-период страницы будущих событий.
|
||||
- `specs/`: уточнение пользовательского поведения периода по умолчанию и
|
||||
календарных ограничений существующей capability.
|
||||
|
||||
Изменение сохраняет выбор владельца из frontend Issue #63: фильтр остаётся.
|
||||
Оно не переводит страницу в режим read-only списка исходного прогноза.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- При первом открытии без параметров период включает сегодня и следующие шесть
|
||||
календарных дат.
|
||||
- Пользователь может выбирать будущие даты и не может выбрать даты до сегодня.
|
||||
- Прямой URL с валидными прошедшими датами сохраняет указанный период.
|
||||
- Некорректный URL-период заменяется периодом по умолчанию.
|
||||
@@ -0,0 +1,37 @@
|
||||
# QA Analysis: Upcoming events date filter
|
||||
|
||||
## Verification Scope
|
||||
|
||||
In scope: `brokerage-account-upcoming-events` — **User can filter upcoming
|
||||
events by a forecast date range** and its four scenarios in the delta spec.
|
||||
|
||||
Out of scope: backend date-window behavior, event calculations, forecast
|
||||
freshness, and API error mapping; these are unchanged by this frontend date
|
||||
filter adjustment.
|
||||
|
||||
## Coverage Matrix
|
||||
|
||||
| Requirement / Scenario | Risk | Verification |
|
||||
| --- | --- | --- |
|
||||
| Default range starts today and spans seven calendar dates | Off-by-one or local-midnight error yields the wrong period | Check that the inclusive range contains today and the next six distinct Moscow calendar dates, including when opened around Moscow midnight. |
|
||||
| Future dates can be selected and past dates cannot | Incorrect picker bounds preserve the reported defect or block forecast dates | Open the date picker; confirm yesterday is unavailable and today plus later dates are selectable. Apply a future range and confirm the displayed period reflects it. |
|
||||
| Valid past URL range is preserved | UI restriction is accidentally enforced on deep links | Open a valid past range directly and confirm the same dates remain applied and in the URL. |
|
||||
| Invalid URL range falls back to the default | Malformed or impossible dates leak into requests or remain in navigation state | Open malformed, impossible, and reversed ranges; confirm the default range is applied and invalid range parameters are removed. |
|
||||
|
||||
## Test Data and Boundaries
|
||||
|
||||
- Use a controlled current date and include a case near the Europe/Moscow
|
||||
calendar-date boundary.
|
||||
- Cover exactly today, the sixth following calendar date, and a later future
|
||||
date in the picker.
|
||||
- For URL normalization, include invalid syntax, an impossible date such as
|
||||
February 30, and `from` later than `to`.
|
||||
- Include a valid past range to distinguish URL compatibility from picker
|
||||
restrictions.
|
||||
|
||||
## Risks and Limitations
|
||||
|
||||
The calendar is a visual interaction, so system-level verification should use
|
||||
the existing browser-capable UI validation available to the frontend project.
|
||||
If only component-level verification is available, it can establish URL and
|
||||
range state but cannot fully prove the rendered calendar's disabled dates.
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Delta for Brokerage Account Upcoming Events
|
||||
|
||||
## Requirement: User can filter upcoming events by a forecast date range
|
||||
|
||||
The events page MUST retain its URL-backed date-range filter. When the URL has
|
||||
no `from` or `to` parameters, the applied range MUST include the current date
|
||||
and the following six calendar dates. The page MUST allow selecting today and
|
||||
future dates in its date picker and MUST prevent selecting dates before today.
|
||||
|
||||
The date-picker restriction MUST NOT invalidate or rewrite a valid past date
|
||||
range supplied directly in the URL. A malformed date, impossible calendar date,
|
||||
or reversed range MUST be normalized to the default range, removing invalid
|
||||
`from` and `to` parameters from the URL. Applying and resetting the filter MUST
|
||||
continue to use the existing URL-backed period behavior.
|
||||
|
||||
#### Scenario: Default range starts today and spans seven calendar dates
|
||||
|
||||
- **WHEN** the user opens the events page without `from` or `to` parameters
|
||||
- **THEN** the applied range starts on the current calendar date
|
||||
- **AND** the inclusive end date is six calendar dates after the start date
|
||||
|
||||
#### Scenario: Future dates can be selected and past dates cannot
|
||||
|
||||
- **WHEN** the user opens the date picker
|
||||
- **THEN** today and later dates are selectable
|
||||
- **AND** dates before today are not selectable
|
||||
|
||||
#### Scenario: Valid past URL range is preserved
|
||||
|
||||
- **WHEN** the user opens the events page with valid `from` and `to` dates in
|
||||
the past and `from` is not after `to`
|
||||
- **THEN** the page applies that URL range without clamping or replacing it
|
||||
|
||||
#### Scenario: Invalid URL range falls back to the default
|
||||
|
||||
- **WHEN** the URL contains a malformed date, an impossible calendar date, or
|
||||
a range whose `from` date is after its `to` date
|
||||
- **THEN** the page applies the default seven-calendar-date range
|
||||
- **AND** invalid `from` and `to` parameters are removed from the URL
|
||||
@@ -0,0 +1,61 @@
|
||||
# System Analysis: Upcoming events date filter
|
||||
|
||||
## Scope and ownership
|
||||
|
||||
This change affects the frontend events page and its existing date-range
|
||||
contract. The backend API already accepts optional `from` and `to` dates and
|
||||
returns events for the requested range; the canonical
|
||||
`brokerage-account-upcoming-events` capability defines inclusive UTC date
|
||||
bounds and behavior for invalid request ranges. No backend/API contract change
|
||||
is needed.
|
||||
|
||||
The frontend owns picker availability, URL normalization, and the default
|
||||
range. The user-approved product decision is to retain the filter (rather than
|
||||
replace it with an unfiltered saved-forecast list, as considered by frontend
|
||||
Issue #63).
|
||||
|
||||
## Observable flow
|
||||
|
||||
```text
|
||||
URL query parameters
|
||||
|
|
||||
v
|
||||
validate calendar dates and ordering
|
||||
| valid | invalid
|
||||
v v
|
||||
preserve supplied range remove invalid range
|
||||
| |
|
||||
+------------+--------------+
|
||||
v
|
||||
no range -> seven dates from today
|
||||
|
|
||||
v
|
||||
GET events with inclusive range
|
||||
```
|
||||
|
||||
The date picker prevents new selection of dates before today, but this UI
|
||||
constraint is intentionally not a validation rule for a valid URL-provided
|
||||
past range. API date serialization and existing inclusive-boundary semantics
|
||||
remain unchanged.
|
||||
|
||||
## Time-zone and calendar semantics
|
||||
|
||||
The existing frontend date utilities represent calendar dates in the
|
||||
`Europe/Moscow` zone. The default must be computed as calendar-date arithmetic
|
||||
in that same zone, not by subtracting elapsed 24-hour durations from the
|
||||
current instant; elapsed-time arithmetic can yield the wrong number of distinct
|
||||
dates around a local midnight or daylight offset change. The current-date
|
||||
boundary used by the picker and default must be consistent with this existing
|
||||
frontend calendar convention.
|
||||
|
||||
## Failure and compatibility behavior
|
||||
|
||||
- Valid past query ranges remain accepted even though the picker will not
|
||||
create them.
|
||||
- Malformed, impossible, or reversed ranges follow the existing URL
|
||||
normalization path and resolve to the default period.
|
||||
- One-sided valid ranges keep their existing supported behavior; this change
|
||||
does not require both query parameters to be present.
|
||||
- Apply and Reset retain their existing URL/history semantics.
|
||||
- Backend `INVALID_EVENTS_PERIOD`, request parameters, and saved forecast window
|
||||
intersection behavior are outside this change.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Tasks: Upcoming events date filter
|
||||
|
||||
- [x] 1.1 [frontend] Implement the seven-calendar-date default and date-picker bounds while preserving URL period normalization and Apply/Reset behavior.
|
||||
- **Covers:** `brokerage-account-upcoming-events` — `User can filter upcoming events by a forecast date range`.
|
||||
- **Source:** Proposal **What Changes**; Specs scenarios **Default range starts today and spans seven calendar dates**, **Future dates can be selected and past dates cannot**, **Valid past URL range is preserved**, and **Invalid URL range falls back to the default**; Design **Design**.
|
||||
- **Verification:** Frontend owner runs relevant existing page/calendar tests and confirms Moscow-midnight default, future/past picker bounds, valid past URL preservation, and invalid URL fallback.
|
||||
|
||||
- [x] 1.2 [docs] Update the canonical upcoming-events page to document the shipped default range and picker/URL behavior.
|
||||
- **Covers:** `brokerage-account-upcoming-events` — `User can filter upcoming events by a forecast date range`.
|
||||
- **Source:** Docs Impact **Durable Information to Promote**.
|
||||
- **Verification:** Confirm `docs/domains/income/upcoming-events.md` describes seven inclusive calendar dates from today, picker restrictions, valid past URL behavior, and invalid-range fallback.
|
||||
Reference in New Issue
Block a user