high priority medium complexity backend pending backend specialist Tier 0

Acceptance Criteria

Given a fee amount strictly below the org-configured threshold, validateAssignmentFee() returns FeeValidationResult.belowThreshold and the caller can proceed directly to assignment confirmation
Given a fee amount exactly equal to the org-configured threshold, validateAssignmentFee() returns FeeValidationResult.requiresApproval, triggering the expense approval path
Given a fee amount above the org-configured threshold, validateAssignmentFee() returns FeeValidationResult.requiresApproval
Given a zero fee amount, validation passes as belowThreshold without querying the threshold configuration
Given a null or negative fee amount, the method throws a FeeValidationException with a descriptive message before any database access
The threshold value is fetched from org_settings (Supabase) keyed by org_id β€” no hardcoded constants
If the org_settings record for the calling org does not exist, the method throws OrgConfigNotFoundException and does not fall back to a default value
The validation result is a sealed class / enum with exactly two variants: belowThreshold and requiresApproval β€” no ambiguous states
All fee comparisons use Decimal / int arithmetic in minor currency units (ΓΈre) to avoid floating-point rounding errors
Unit tests cover: below threshold, at threshold, above threshold, zero fee, missing org config, negative fee

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
flutter_test
apis
Supabase PostgREST REST API (org_settings table read)
data models
DriverAssignment
OrgSettings (honorarium_threshold_ore field)
FeeValidationResult (sealed class)
performance requirements
Threshold lookup must complete within 200 ms under normal network conditions β€” cache the value per org_id within the service instance lifetime
No N+1 queries β€” org threshold is fetched once per assignment validation call
security requirements
Supabase RLS must restrict org_settings reads to rows matching the authenticated user's org_id β€” service must not pass org_id as an unverified client parameter
Fee amount must never be logged in plaintext in production log levels β€” use verbose/debug guard

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Represent all monetary values as int (ΓΈre / minor units) throughout the service layer to eliminate floating-point precision bugs. Define a sealed class FeeValidationResult with two subclasses: BelowThreshold and RequiresApproval. Store the org threshold in OrgSettings as honorarium_threshold_ore (integer). Implement OrgSettingsRepository as an abstract class with a SupabaseOrgSettingsRepository concrete implementation, injected via Riverpod provider β€” this enables easy mocking in tests.

Cache the threshold per org_id using a simple in-memory map on the service; invalidate on org settings update events. Avoid business logic in the Supabase RPC layer β€” keep validation in Dart for testability. The FeeValidationResult should carry the resolved threshold value so callers can display it in UI without a second fetch.

Testing Requirements

Unit tests (flutter_test) are mandatory and must achieve 100% branch coverage of the validation logic. Test the FeeValidationService in isolation using a mock OrgSettingsRepository. Parameterized tests for boundary values: threshold - 1, threshold, threshold + 1, 0, negative. Integration test: verify the Supabase RLS policy actually blocks cross-org threshold reads by running the query under a JWT from a different org β€” this test runs against the Supabase test project.

No UI tests required for this task.

Component
Driver Assignment Service
service medium
Epic Risks (4)
high impact medium prob security

Org-scoped encryption key management is complex. If keys are not correctly isolated per organization, a breach in one org's key could expose another org's declarations. Additionally, key rotation is not specified but may be needed for compliance, and the current implementation may not support it.

Mitigation & Contingency

Mitigation: Use Supabase Vault or a dedicated secrets management approach for org-scoped key storage. Define the key derivation strategy (per-org master key) in a security design document reviewed before implementation begins. Include key isolation tests in the test suite.

Contingency: If a full per-org key management system cannot be safely implemented within the sprint, fall back to a single platform-level encryption key with strict RLS isolation as a temporary measure, flagging the key rotation gap as a security debt item with a defined resolution milestone.

medium impact medium prob integration

Push notification delivery to drivers depends on FCM token availability and device connectivity. If a driver has not granted notification permissions or has an expired FCM token, the declaration delivery notification will silently fail, leaving the coordinator unaware and the declaration unacknowledged.

Mitigation & Contingency

Mitigation: Implement delivery status tracking in declaration-notification-service. Fall back to in-app notification and SMS (if configured) when push delivery fails. Expose delivery failure status in the declaration status badge so coordinators can identify and manually follow up.

Contingency: If push delivery proves unreliable, implement a polling-based in-app notification fallback where drivers see pending declarations on next app open, ensuring the workflow can complete even without push notifications.

medium impact medium prob technical

The acknowledgement service is meant to validate that the driver has fully scrolled through the declaration before confirming. Implementing reliable scroll completion detection in Flutter across different screen sizes and font sizes is technically non-trivial and could be bypassed.

Mitigation & Contingency

Mitigation: Implement scroll position tracking using ScrollController with a threshold (e.g., 95% of content height reached) and record the validated state server-side before allowing acknowledgement submission. Document the approach in the legal sign-off checkpoint noted in the feature documentation.

Contingency: If reliable scroll detection cannot be implemented within the sprint, add a mandatory reading delay timer (e.g., estimated reading time based on word count) as an alternative validation mechanism, pending legal review of the approach.

medium impact low prob dependency

The driver assignment service must coordinate with the threshold-based expense approval workflow for fees above configured thresholds. If the expense approval workflow interface changes or is not yet stable, the integration point could break or produce incorrect routing behavior.

Mitigation & Contingency

Mitigation: Define a clear interface contract between driver-assignment-service and the expense approval workflow before implementation. Use dependency injection so the expense workflow client can be mocked in tests. Monitor the expense approval feature for interface changes.

Contingency: If the expense approval workflow interface is not stable, implement a direct database insert to the expense records table as a temporary bypass, with a flag indicating manual review is needed, until the stable interface is available.