high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

Widget renders two date fields (start date, end date) using design token colors, typography, and spacing — no hardcoded values
Five preset quick-select options are available: 'Current Month', 'Last Month', 'Current Quarter', 'Last Quarter', 'Custom Range' — each correctly computes the corresponding DateTime boundaries at the moment of selection
Selecting a preset populates both date fields immediately and emits the corresponding DateRange via the onDateRangeChanged callback
When 'Custom Range' is selected, both date fields become editable and a date picker dialog (Flutter showDatePicker) is shown on tap
Validation error is shown inline when end date is earlier than start date; the callback is NOT called while the range is invalid
Callback emits a typed DateRange(DateTime start, DateTime end) value object — never null dates
All interactive elements have a minimum touch target of 48×48 dp per WCAG 2.2 AA
Every date field and quick-select chip has a Semantics label readable by TalkBack and VoiceOver (e.g., 'Start date, currently 1 January 2025')
Widget is fully self-contained — accepts only an optional initial DateRange and an onDateRangeChanged callback; no BLoC or Riverpod provider injected
Widget has a dedicated golden test and unit tests covering: preset selection, custom range validation, invalid range rejection, and accessibility tree

Technical Requirements

frameworks
Flutter
flutter_test
performance requirements
Widget rebuilds only the changed date field on preset/custom change — avoid full widget tree rebuild
Date picker dialog opens within 100ms of tap
security requirements
No date or range data persisted by this widget — all state is ephemeral and passed via callback
Widget does not store PII
ui components
DateRangePresetChips — horizontal scrollable row of quick-select chips
DateFieldTile — reusable date display/edit field built on design tokens
InlineValidationMessage — error text rendered below the end date field

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implement as a StatefulWidget that owns the currently selected preset enum and the two DateTime? values. Use a PresetQuickSelect enum (currentMonth, lastMonth, currentQuarter, lastQuarter, custom) to drive both the chip highlights and date computation. Date boundary computation should be pure functions — extract to a DateRangePresets utility class for easy unit testing.

Use showDatePicker with Flutter's Material date picker; wrap in a helper that enforces firstDate/lastDate bounds (e.g., no future dates beyond today for export ranges). Apply design tokens via the existing AppColors/AppTextStyles/AppSpacing constants — never use literal hex or pixel values. Chip styling: use ChoiceChip Flutter widget. Keep the callback type as typedef void DateRangeChangedCallback(DateRange range) for clarity.

Avoid importing BLoC or Riverpod in this file — the widget must be testable in isolation.

Testing Requirements

Unit tests (flutter_test): verify DateRange emitted for each preset matches expected boundaries for a known reference date; verify invalid range (end < start) suppresses callback; verify custom range emits only after both dates are valid. Widget tests: render widget, tap each preset, verify field values and callback argument. Golden test: snapshot of default state, preset-selected state, and error state. Accessibility test: verify Semantics tree contains correct labels for all interactive elements.

No integration tests required for this self-contained widget.

Component
Export Date Range Picker
ui low
Epic Risks (3)
high impact medium prob technical

Adding exported_at and export_run_id columns to expense_claims requires a live migration on a table shared with the approval workflow. A poorly timed migration could lock the table and block claim submissions or approvals.

Mitigation & Contingency

Mitigation: Use non-blocking ADD COLUMN with a DEFAULT of NULL (no backfill needed) executed during a low-traffic window. Test migration rollback on a staging replica before production deployment.

Contingency: If migration causes table lock contention, roll back and reschedule for a maintenance window. Use a feature flag to gate the export UI until the migration completes successfully.

medium impact high prob scope

Chart of accounts mapping configurations for Xledger and Dynamics may not be fully specified by stakeholders at development time, leaving the mapper with incomplete data and causing validation failures for unmapped expense categories.

Mitigation & Contingency

Mitigation: Implement the mapper to return a structured validation error (not a crash) for any unmapped field, and surface these errors clearly in the export confirmation dialog. Request full mapping tables from Blindeforbundet and HLF stakeholders as a pre-condition for this epic.

Contingency: If mappings arrive incomplete, ship the mapper with the available subset and mark unmapped categories as excluded (skipped with reason). Coordinators see which categories are skipped and can manually submit those records.

medium impact medium prob dependency

Supabase Vault configuration for storing per-org accounting credentials may require infra permissions or environment secrets not yet provisioned in staging or production, blocking development and testing of credential retrieval.

Mitigation & Contingency

Mitigation: Provision Vault secrets and environment configuration in staging as the first task of this epic. Document the exact secret naming convention and rotation procedure before implementation begins.

Contingency: If Vault is unavailable, use environment variables scoped to the Edge Function as a temporary fallback for development. Block production deployment until Vault-based storage is confirmed operational.