From b4c0589745e0d1fb6b482addbea82d06c4924dad Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 14 Oct 2026 21:24:13 +0300 Subject: [PATCH] spec: fix upcoming events date filter default and picker bounds (WealthLedger/frontend#63) --- .../.openspec.yaml | 2 + .../fix-upcoming-events-date-filter/design.md | 63 +++++++++++++++++++ .../docs-impact.md | 24 +++++++ .../proposal.md | 40 ++++++++++++ .../qa-analysis.md | 37 +++++++++++ .../brokerage-account-upcoming-events/spec.md | 39 ++++++++++++ .../system-analysis/analysis.md | 61 ++++++++++++++++++ .../fix-upcoming-events-date-filter/tasks.md | 11 ++++ 8 files changed, 277 insertions(+) create mode 100644 openspec/changes/fix-upcoming-events-date-filter/.openspec.yaml create mode 100644 openspec/changes/fix-upcoming-events-date-filter/design.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/docs-impact.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/proposal.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/qa-analysis.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/specs/brokerage-account-upcoming-events/spec.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/system-analysis/analysis.md create mode 100644 openspec/changes/fix-upcoming-events-date-filter/tasks.md diff --git a/openspec/changes/fix-upcoming-events-date-filter/.openspec.yaml b/openspec/changes/fix-upcoming-events-date-filter/.openspec.yaml new file mode 100644 index 0000000..0c163c7 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/.openspec.yaml @@ -0,0 +1,2 @@ +schema: wealth-ledger-sdd-v2 +created: 2026-10-14 diff --git a/openspec/changes/fix-upcoming-events-date-filter/design.md b/openspec/changes/fix-upcoming-events-date-filter/design.md new file mode 100644 index 0000000..44ee2ab --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/design.md @@ -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. diff --git a/openspec/changes/fix-upcoming-events-date-filter/docs-impact.md b/openspec/changes/fix-upcoming-events-date-filter/docs-impact.md new file mode 100644 index 0000000..18cda57 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/docs-impact.md @@ -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. diff --git a/openspec/changes/fix-upcoming-events-date-filter/proposal.md b/openspec/changes/fix-upcoming-events-date-filter/proposal.md new file mode 100644 index 0000000..252e31d --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/proposal.md @@ -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-период заменяется периодом по умолчанию. diff --git a/openspec/changes/fix-upcoming-events-date-filter/qa-analysis.md b/openspec/changes/fix-upcoming-events-date-filter/qa-analysis.md new file mode 100644 index 0000000..bb55835 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/qa-analysis.md @@ -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. diff --git a/openspec/changes/fix-upcoming-events-date-filter/specs/brokerage-account-upcoming-events/spec.md b/openspec/changes/fix-upcoming-events-date-filter/specs/brokerage-account-upcoming-events/spec.md new file mode 100644 index 0000000..16fcab3 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/specs/brokerage-account-upcoming-events/spec.md @@ -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 diff --git a/openspec/changes/fix-upcoming-events-date-filter/system-analysis/analysis.md b/openspec/changes/fix-upcoming-events-date-filter/system-analysis/analysis.md new file mode 100644 index 0000000..be68f68 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/system-analysis/analysis.md @@ -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. diff --git a/openspec/changes/fix-upcoming-events-date-filter/tasks.md b/openspec/changes/fix-upcoming-events-date-filter/tasks.md new file mode 100644 index 0000000..c948e95 --- /dev/null +++ b/openspec/changes/fix-upcoming-events-date-filter/tasks.md @@ -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. -- 2.54.0