critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

fetchAssignmentHistory returns an empty list (not null, no exception) when organizationId corresponds to NHF
fetchAssignmentHistory returns an empty list (not null, no exception) when organizationId corresponds to HLF
fetchAssignmentHistory returns List<AssignedContact> from the assignment_records table when organizationId corresponds to Blindeforbundet
The organization branching logic uses a named constant or enum (e.g., OrgIds.blindeforbundet) — no magic strings inline
Each AssignedContact in the result includes: id, mentor_id, contact_id, contact_name, status (open/closed), assigned_date, deadline (nullable), and days_remaining (computed, nullable)
days_remaining is computed as deadline.difference(DateTime.now()).inDays; negative values indicate overdue (overdue_flag = true)
Results are ordered by assigned_date descending
Supabase query filters by mentor_id and org_id (or scoped via RLS) on assignment_records
Any Supabase exception is caught and rethrown as AssignmentFetchException
Method is implemented behind an abstract interface IAssignmentHistoryRepository for testability

Technical Requirements

frameworks
Flutter
Dart
supabase_flutter
apis
Supabase PostgREST — assignment_records table
Supabase RLS policies scoped to Blindeforbundet org
data models
AssignedContact
AssignmentStatus enum (open, closed)
OrgIds constants
performance requirements
For Blindeforbundet, query must complete within 500 ms for up to 200 assignment records
For NHF/HLF, the method must short-circuit before any network call — return const [] immediately
security requirements
NHF/HLF short-circuit must happen in Dart code before any Supabase query is constructed, ensuring zero data leakage across org boundaries
Supabase RLS is the authoritative access control layer for Blindeforbundet data; repository logic is a defense-in-depth layer only
organizationId must be validated as non-empty string before branching

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

The org-branching is architecturally significant: it represents a deliberate multi-tenant data isolation contract. Document this with a /// doc comment on the method explaining why NHF/HLF return empty. Use a centralized OrgIds constant class (e.g., in constants.dart) so the branching condition is maintainable — if a new org is added, the constant class is the single change point. Compute days_remaining and the overdue flag inside the AssignedContact.fromJson factory or a dedicated mapper function, not inside the repository method, to keep the repository thin.

The AssignedContact model should be immutable (all final fields, const constructor where possible).

Testing Requirements

Unit tests with flutter_test and mockito. Test cases: (1) NHF organizationId → returns empty list, Supabase client never called; (2) HLF organizationId → returns empty list, Supabase client never called; (3) Blindeforbundet organizationId → Supabase is queried and results mapped to List; (4) Blindeforbundet result includes correctly computed days_remaining and overdue_flag; (5) empty assignment_records for a mentor under Blindeforbundet → returns empty list; (6) PostgrestException → rethrown as AssignmentFetchException; (7) null/empty organizationId → ArgumentError before any branching. Verify the NHF/HLF short-circuit does NOT invoke the mocked Supabase client using Mockito's verifyNever.

Component
Assignment History Repository
data low
Epic Risks (3)
high impact medium prob security

Supabase RLS policies for peer mentor data may block coordinator queries if the RLS rules are written for peer-mentor-self access only, requiring policy updates that affect other features sharing the same tables.

Mitigation & Contingency

Mitigation: Review existing RLS policies on peer_mentors, certification_records, and activity_log tables before writing repository queries. Coordinate with the database team to add coordinator-role predicates without weakening existing mentor-self policies.

Contingency: If policy changes are blocked, implement a Supabase Edge Function as a secure query proxy that enforces authorization server-side, avoiding direct RLS policy modification.

medium impact medium prob technical

The activity log table schema may not have a mentor_id foreign key column or may require a JOIN through an intermediate table, making the aggregation query significantly more complex than anticipated.

Mitigation & Contingency

Mitigation: Inspect the actual Supabase activity_log table schema before starting the MentorActivityLogRepository implementation. Document the exact JOIN path needed and validate it returns correct results for a known mentor.

Contingency: If schema requires complex multi-table aggregation, implement a Supabase database function (RPC) and expose it via the repository's fetchSummary method to keep Dart code clean.

high impact low prob dependency

The Blindeforbundet assignment table may not yet exist in the shared Supabase schema or may have a different structure than assumed, blocking the AssignmentHistoryRepository implementation.

Mitigation & Contingency

Mitigation: Verify the assignments table exists and confirm its column structure with the Contact Detail & Edit Screen team which also depends on assignment data (assignment-repository in that feature).

Contingency: If the assignments table is not yet available, implement the AssignmentHistoryRepository with a stub returning empty list and a TODO marker, unblocking the aggregation service while the schema is finalized.