Define ExpenseType enum with display metadata
epic-expense-type-selection-foundation-task-001 — Create the canonical ExpenseType enum in Dart covering all reimbursable expense types (kilometre, transit, toll, parking, driver-honorarium, etc.). Each variant must carry display metadata: localisation key, icon reference, and formula parameters (rate multiplier, receipt threshold, requires-distance flag). Export a const map of ExpenseTypeConfig objects keyed by ExpenseType for downstream consumers.
Acceptance Criteria
Technical Requirements
Implementation Notes
This is the foundational data file for the entire expense selection epic — get the naming and structure right as all downstream tasks depend on it. Use an enhanced enum pattern in Dart: enum ExpenseType { kilometre, transit, toll, parking, driverHonorarium } with a separate const map rather than adding methods to the enum itself (this keeps the enum serialisable and avoids issues with Hive type adapters). Place the file at lib/features/expenses/domain/expense_type.dart. Define FormulaParameters as a simple immutable class with const constructor in a sibling file (task-002 will extend it).
For the mutual exclusion pairs, use a Set
Testing Requirements
Unit tests verifying: (1) every ExpenseType variant has an entry in kExpenseTypeConfigs, (2) no config entry has a null or empty localisationKey, (3) requiresDistance is true only for kilometre type, (4) receiptThreshold is a positive number for all types where requiresReceipt is true, (5) kMutualExclusionPairs contains at least the kilometre/transit exclusion pair documented in the HLF spec. These are simple assertion-based tests with no mocking needed. Run with flutter test.
The compatibility matrix might be under-specified in source documentation. If a new organisation adds expense types or redefines rules, hardcoded pairwise logic becomes a maintenance liability and can silently allow previously excluded combinations.
Mitigation & Contingency
Mitigation: Model the matrix as a const Map<ExpenseType, Set<ExpenseType>> rather than if-else chains; add a unit test that exhaustively asserts every pair combination so any future matrix change forces explicit test updates.
Contingency: If per-organisation matrix variants are requested before the epic closes, extract matrix loading into expense-type-config with an org-override slot and defer per-org configuration to the repository epic.
VoiceOver (iOS) and TalkBack (Android) handle Semantics widget announcements differently in Flutter. Live-region behaviour for disabled state changes is inconsistent across Flutter versions and may require platform-specific workarounds that are not yet documented.
Mitigation & Contingency
Mitigation: Write accessibility integration tests using Flutter's SemanticsController targeting both iOS and Android simulators from the outset; pin to a Flutter version known to handle Semantics.liveRegion correctly.
Contingency: If platform parity is unachievable before release, ship with a known gap documented in the WCAG audit log and schedule a dedicated accessibility sprint; do not block other epics.