Driver honorarium service: DB schema and core persistence
epic-travel-expense-registration-org-extensions-task-001 — Create the database schema for honorarium records, including the honorarium_records table with fields for amount, org-specific rate band, declaration_acknowledged_at timestamp, parent expense ID foreign key, and activity ID. Implement the DriverHonorariumService repository layer with create, read, and update operations. Ensure row-level security policies restrict access by organisation and coordinator role.
Acceptance Criteria
Technical Requirements
Implementation Notes
Place migration in `supabase/migrations/` with a timestamp prefix. Place the Dart repository in `lib/features/expense/data/honorarium_repository.dart` and the domain model in `lib/features/expense/domain/models/honorarium_record.dart`. The `rate_band` field maps to Blindeforbundet's tiered honorarium system (standard rate vs. elevated rate at 3 and 15 assignments) — define the allowed band values as constants in a `HonorariumRateBand` enum in Dart and as a CHECK constraint in SQL to keep them in sync.
Use `Equatable` on `HonorariumRecord` for value equality in tests. The feature flag check (Blindeforbundet-only) is implemented in task-002, not here — the schema and repository are generic. Do not add any org-specific business logic in this task; keep the persistence layer clean.
Testing Requirements
Unit tests (flutter_test): HonorariumRecord.fromJson() with all fields present; fromJson() with nullable fields null; toJson() round-trip. Integration tests (against local emulator): createHonorarium inserts a row and returns it; getHonorariumByExpenseId returns null when no row exists; update changes the correct fields; RLS test — a user from a different org cannot SELECT the row (expect RLS-denied response); a non-coordinator role cannot INSERT (expect 403/RLS denied). Migration test: run `supabase db reset` and verify the table and indexes exist via information_schema queries.
The Dynamics portal (HLF) and Xledger (Blindeforbundet) APIs have organisation-managed API contracts that may change without notice. Field mapping requirements, authentication flows, and export formats are not fully documented and may only be clarified during integration testing.
Mitigation & Contingency
Mitigation: Engage HLF and Blindeforbundet technical contacts early to obtain API documentation, sandbox credentials, and example payloads before implementation starts. Design the accounting integration client as a thin adapter layer with organisation-specific mappers so that field mapping changes require only mapper updates, not core client changes.
Contingency: If API documentation is unavailable or the API is unstable during Phase 3, implement a CSV/JSON file export as an interim deliverable. Coordinators can manually upload the file to their respective accounting systems until the live API integration is completed.
The confidentiality declaration for Blindeforbundet drivers may have specific legal requirements around content, format, wording, and record-keeping that are not yet specified. Implementing the wrong declaration flow could expose Blindeforbundet to compliance risk.
Mitigation & Contingency
Mitigation: Treat the declaration content and acknowledgement flow as a Blindeforbundet-controlled configuration, not hardcoded text. Implement the declaration as a templated document fetched from Supabase and reviewed by Blindeforbundet before any production deployment. Obtain written sign-off on the declaration text and acknowledgement mechanism before the epic is considered complete.
Contingency: If legal requirements cannot be confirmed in time for the sprint, deliver the driver honorarium form without the confidentiality declaration and gate the entire driver feature behind its feature flag. The declaration can be added in a follow-up sprint once requirements are confirmed, without blocking other feature delivery.
If the accounting export can be triggered multiple times for the same approved claims batch, duplicate records may be created in Dynamics or Xledger, causing accounting reconciliation problems that are difficult to reverse.
Mitigation & Contingency
Mitigation: Implement idempotent export runs: each export batch is assigned a unique run ID stored in the database. The accounting integration client checks for an existing successful export run for the same claim IDs before submitting. Approved claims that have been exported are marked with exported_at timestamp to prevent re-export.
Contingency: If duplicate exports occur despite idempotency checks (e.g. network failure after API success but before local confirmation), provide coordinators with an export history panel showing run IDs and timestamps. Implement a reconciliation endpoint that can query the accounting system for existing records before re-submitting flagged claims.