Notion test-run #3 doc item #6 ("To add more filtering controls for Session History").
Adds preset chips (Today / This Week / This Month / Last 3 Months / This Year / All) + Custom date range
+ Shop multi-select to /cafe/pos/sessions. Default preset = "All" preserves the prior
no-date-filter UX. Matches Odoo 17's POS Sessions list filter pattern.
lib/reports/period.ts — PresetKey gains 3 entries (last_3_months, this_year, all); resolveReportPeriod handles each. New isUnfilteredPreset() helper lets callers skip the date constraint server-side when preset = "all".lib/db/cafe_sessions.ts — listSessions DAO gains optional fromUtc + toUtc params applied via gte/lte on opened_at. Tenant scope + existing shop/config filters unchanged.app/(authed)/pos/sessions/page.tsx — reads shop/preset/from/to URL params, scopes shopIds via multi-select (out-of-scope IDs dropped server-side), resolves the period in tenant timezone, skips the date filter when preset = "all".app/(authed)/pos/sessions/sessions-client.tsx — FilterBar with 7 preset chips (6 from spec + Custom), custom from/to date inputs shown only when preset = "custom", Shop multi-select (hidden on single-shop tenants), Register dropdown stays, Reset filters button. New inline ShopMultiSelect with outside-click + Escape close.isUnfilteredPreset() returns true and the page passes undefined to the DAO.buildQs() helper.| ✓ | period.ts: 3 new presets in PresetKey + PRESET_LABELS + PRESET_ORDER; isUnfilteredPreset helper exported |
| ✓ | period.ts runtime: resolveReportPeriod("last_3_months") on 2026-05-27 → 2026-02-27 → 2026-05-27 (calendar-month math via Date arithmetic); "this_year" → 2026-01-01; "all" → 1970-01-01 sentinel; isUnfilteredPreset only true for "all" |
| ✓ | listSessions: signature gains fromUtc + toUtc; applied via gte/lte on cafeSessions.openedAt |
| ✓ | page.tsx: reads searchParams.{shop,preset,from,to}; calls resolveReportPeriod + isUnfilteredPreset; skipDateFilter ternary on DAO call; scopedShopIds derived from URL ∩ accessible shops |
| ✓ | sessions-client.tsx: 11 literal FilterBar testids + 7 preset chip slugs in SESSION_PRESETS + ShopMultiSelect component with outside-click + Escape close |
| ✓ | DAO probe on local lumiere: future-window (2099-01-01 → 2099-12-31) returns 0 sessions; wide-window (1970 → 2099) equals unfiltered count — confirms the filter clause is real, not a no-op |
Typecheck: npx tsc --noEmit on nix-cafe → 0 errors.
karouna-dev → CF auto-deploy.test-u10-prod.mjs on lumiere: SSO → /cafe/pos/sessions → preset chips fire correctly (click each, assert URL param + result subset) → Custom range → Shop dropdown opens + closes outside-click + selections survive reload → Reset clears all.