Build read-only expense summary card widget
epic-travel-expense-registration-foundation-task-010 — Implement the ExpenseSummaryCard Flutter widget that displays a compact, read-only summary of an expense claim: type badge, amount, date, status chip (pending/auto-approved/rejected), and receipt thumbnail indicator. The widget must be reusable across the attestation queue screen, home dashboard, and profile views. Apply design token colours and WCAG 2.2 AA contrast requirements.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Place widget at `lib/features/expense/widgets/expense_summary_card.dart`. Import `ExpenseClaim` from the data layer defined in task-004; do not duplicate the model. For status chip colours use design tokens (e.g. `AppColors.statusPending`, `AppColors.statusApproved`, `AppColors.statusRejected`) — add tokens if missing rather than hardcoding hex values.
Use `Semantics(label: ..., child: ...)` wrapping the entire card, with `excludeSemantics: true` on child elements, so screen readers read one clean string. For the receipt indicator, use a camera icon with `Visibility` widget controlled by `claim.receiptUrl != null` — avoid `Opacity(opacity: 0)` which keeps the widget in the tree invisibly. Apply `Flexible` or `Expanded` within the row layout to prevent overflow at large text scales. The type badge should use the organisation's label system (dynamic terminology per org) — pass the label string in, do not resolve it inside the widget.
Testing Requirements
Widget tests (flutter_test): render each status state, verify chip colour token, verify VoiceOver semantics label, verify onTap callback fires, verify null onTap disables interaction. Golden tests: capture PNG for pending/auto_approved/rejected states at 1.0 and 2.0 text scale. Accessibility audit: run Flutter's SemanticsController in tests to assert the merged semantics node. No integration test required for this isolated widget, but include it in the attestation queue screen integration test in task-011.
Row-level security policies for expense claims must correctly scope data to organisation, role (peer mentor sees own claims only, coordinator sees org-wide queue), and claim status. Incorrect RLS can expose claims cross-organisation or prevent coordinators from accessing the attestation queue.
Mitigation & Contingency
Mitigation: Define RLS policies in code-reviewed migration files. Write integration tests that attempt cross-org reads with different JWT roles and assert access denial. Review with a second engineer before merging migrations.
Contingency: If RLS is misconfigured post-deployment, disable the affected policy temporarily and apply a hotfix migration within the same release window. No claim data is exposed publicly due to Supabase project-level auth requirement.
The auto-approval Edge Function is triggered server-side on expense insert. Cold-start latency or Edge Function failures can block the submission response and degrade UX, especially on mobile networks.
Mitigation & Contingency
Mitigation: Implement the auto-approval Edge Function client with a timeout and graceful fallback: if no result is received within 5 seconds, treat the claim as 'pending' and poll for the status update via Supabase Realtime. Keep the Edge Function warm with a periodic ping.
Contingency: If Edge Function reliability is unacceptable, move auto-approval evaluation to a database trigger or Postgres function as an interim measure, accepting that threshold configuration changes require a migration rather than a settings update.
The expense type catalogue and threshold configuration are cached locally for offline use. If an organisation updates their catalogue exclusion rules or thresholds while a peer mentor is offline, the local cache may allow submissions that violate the new policy.
Mitigation & Contingency
Mitigation: Cache entries include a TTL (24 hours). On connectivity restore, refresh cache before allowing new submissions. Server-side validation in the Edge Function and save functions provides a second enforcement layer.
Contingency: If a stale-cache submission passes client validation but fails server validation, surface a clear error message explaining that the expense type rules have been updated and prompt the user to review their selection with the refreshed catalogue.