high priority medium complexity backend pending backend specialist Tier 0

Acceptance Criteria

ContactDetailService exposes a `Stream<ActivityHistoryState>` (or equivalent Riverpod provider) that emits paginated ActivityHistoryPage objects for a given contactId
First page fetch emits ActivityHistoryLoading then ActivityHistoryLoaded with correct page 1 items, totalCount, and hasNextPage flag
Each ActivityHistoryItem contains: typeLabel (String), date (DateTime), durationMinutes (int), chapterAttribution (String, nullable), proxyFlag (bool)
fetchNextPage() appends next page items to the existing list and emits an updated state; duplicate items are not added if fetchNextPage is called twice rapidly
When the last page is reached, hasNextPage is false and subsequent fetchNextPage() calls are no-ops that do not trigger additional Supabase queries
Page cache is keyed by contactId + pageNumber; switching to a different contact clears the cache for the previous contact
Supabase query uses range-based pagination (offset/limit or cursor) matching the agreed API contract
Network error on any page emits ActivityHistoryError with user-readable message; previously loaded pages remain accessible in state
Service correctly maps Supabase snake_case column names to Dart camelCase fields in ActivityHistoryItem
All public methods and stream exposed by the service are documented with dartdoc comments

Technical Requirements

frameworks
Flutter
Riverpod
BLoC
apis
Supabase REST API — activities table, filtered by contact_id, ordered by date desc, paginated with range header or limit/offset
data models
ActivityHistoryItem
ActivityHistoryPage
ActivityHistoryState (Loading / Loaded / Error)
performance requirements
First page (20 items) must load within 1.5 seconds on a 4G connection
Cached pages must be served from memory with no Supabase roundtrip
Supabase query must include only necessary columns — no SELECT *
security requirements
Supabase RLS policies must restrict activity rows to contacts visible to the authenticated user's organisation
Proxy flag must be fetched from database and not inferred client-side to prevent tampering
Contact ID parameter must be validated as a non-empty UUID before constructing the Supabase query

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Model the service state as a single immutable class holding `List items`, `bool isLoading`, `bool hasNextPage`, `int currentPage`, and `String? errorMessage` — this makes UI consumption straightforward. Use Riverpod's `StateNotifier` or `AsyncNotifier` rather than raw `StreamController` so the UI can use `ref.watch()` for reactive updates. For pagination, use Supabase's `.range(start, end)` method: page size of 20 is recommended based on the HLF use case (380 registrations/year → manageable pages).

Cache implementation: store pages in a `Map>` inside the notifier; on contactId change, call `state = ActivityHistoryState.initial()` to reset. Guard fetchNextPage with an `_isFetching` boolean flag to prevent duplicate concurrent requests from rapid scroll events. The proxy flag maps to `is_proxy` in the database — confirm column name with the backend schema before implementing.

Testing Requirements

Unit tests for ActivityHistoryItem.fromJson() covering all field types including null chapterAttribution and proxyFlag=true/false. Integration tests for the service: happy-path first page, happy-path fetchNextPage appending correctly, error on page 2 (page 1 data preserved), last-page no-op, and cache-clear on contactId change. Use a Supabase fake that returns fixture JSON arrays. Aim for ≥85% coverage on the service and model files.

Component
Activity History List
ui low
Epic Risks (3)
medium impact medium prob scope

The encrypted-field-display confirmation dialog adds interaction steps that may frustrate coordinators who access sensitive fields frequently, leading to requests to bypass the flow or skip read-receipt logging, which would violate Blindeforbundet's compliance requirements.

Mitigation & Contingency

Mitigation: Design the confirmation dialog to be as minimal as possible (one clear sentence, single confirm action) and ensure it does not reappear for the same field within a single screen session. Validate the UX with Blindeforbundet coordinators during the TestFlight pilot before finalising.

Contingency: If coordinators raise strong objections, escalate to Blindeforbundet's data protection officer to determine whether a lighter confirmation pattern (e.g., biometric confirmation instead of dialog) satisfies their compliance obligation.

medium impact medium prob technical

The activity-history-list infinite scroll requires paginated Supabase queries. Contacts with hundreds of activities (e.g., an HLF peer mentor with 380 annual registrations) could cause slow page loads or memory pressure on older devices if pagination boundaries are set too large.

Mitigation & Contingency

Mitigation: Use a page size of 20 records with cursor-based pagination. Implement list item recycling using Flutter's ListView.builder. Benchmark memory usage with 400+ item simulation on a low-end test device before TestFlight release.

Contingency: If performance degrades on older devices, reduce page size to 10 and add a time-window filter (last 30 days, last 6 months, all) so the default view loads a manageable record count for most coordinators.

low impact high prob scope

The cognitive load rule engine (from the Cognitive Accessibility feature) mandates no more than 7 fields per screen section. If a contact model has more than 7 editable fields, the edit-contact-screen layout must be split into sections, adding complexity not accounted for in the initial scope.

Mitigation & Contingency

Mitigation: Audit the full contact field list from all four organisations before implementation. Group fields into logical sections (personal info, contact details, affiliation) so no single section exceeds 7 fields. Use the cognitive-load-rule-engine component if it is already delivered by the Cognitive Accessibility feature.

Contingency: If the rule-engine component is not yet available, implement a simple manual section layout with accordion-style expansion for less-frequently edited fields to stay within the 7-field guideline without blocking delivery.