high priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

invalidateCache(orgId) immediately removes the cached tree for the specified organisation, forcing a fresh fetch on the next getTree() call
invalidateAll() clears all cached trees (used after bulk org structure changes)
Short-TTL policy: cache entries older than the configured TTL are automatically considered stale on next access (lazy expiry — no background timer required)
searchNodes(query, {String? orgId}) returns a List<OrgNodeMatch> sorted by relevance: exact code match first, then name starts-with, then name contains
Search is case-insensitive and diacritic-insensitive (Norwegian ø, æ, å must match their ASCII equivalents)
searchNodes returns a maximum of 20 results to prevent UI overflow
Search operates entirely on the in-memory cache — no Supabase round-trip on each keystroke
If the cache is empty or expired when searchNodes is called, the tree is fetched first and then searched
OrgNodeMatch includes: nodeId, name, code, level, parentName, matchType (exact_code / name_prefix / name_contains)
Unit tests: exact code match, Norwegian character normalisation, empty query returns empty list, query with no matches, results capped at 20

Technical Requirements

frameworks
Flutter
Riverpod
apis
No additional Supabase APIs beyond task-001
data models
OrgNodeMatch (nodeId, name, code, level, parentName, matchType)
CacheEntry (tree, fetchedAt, ttl)
performance requirements
searchNodes across 1400 nodes for a 3-character query: < 20ms
Diacritic normalisation must not introduce perceptible latency
security requirements
Search input must be sanitised to prevent injection if queries are ever forwarded to Supabase (future-proofing)
ui components
OrgNavigatorSearchField (consumes searchNodes via debounced Riverpod AsyncNotifier)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

For diacritic normalisation, implement a simple Dart extension String.normalise() that replaces Norwegian characters (ø→o, æ→ae, å→a, Ø→O, Æ→AE, Å→A) before lowercasing. Do NOT pull in a full Unicode normalisation library — the character set is known and bounded. Search ranking: use a scoring function (3 = exact code, 2 = name prefix, 1 = name contains) and sort descending. For debouncing in the UI layer, use a 300ms debounce in the Riverpod notifier watching the search field — this is a UI concern and should not be implemented inside OrgHierarchyService itself.

Cache invalidation trigger: wire invalidateCache() to Supabase Realtime subscriptions on the organisations table so that admin-side org edits propagate to all connected clients within seconds. This Realtime subscription setup is part of this task.

Testing Requirements

Unit tests (flutter_test): cover all match types and ranking order. Test Norwegian character normalisation with ø→o, æ→ae, å→a equivalences. Test cache invalidation: after invalidateCache(), the next getTree() call must fetch from Supabase (mock the client and assert call count). Test TTL expiry: inject a mock clock, advance past TTL, assert stale entry triggers a re-fetch.

No integration tests required beyond what task-001/002 already cover.

Component
Organisation Hierarchy Service
service high
Epic Risks (4)
medium impact high prob technical

OrgHierarchyNavigator rendering NHF's full 1,400-chapter tree in a single widget may cause Flutter frame-rate drops below 60 fps on mid-range devices, making the navigator unusable for NHF national admins.

Mitigation & Contingency

Mitigation: Implement lazy expansion: only load immediate children on node expand rather than the full tree upfront. Use virtual scrolling for long sibling lists. Test with a synthetic 1,400-node dataset on a low-end Android device during development.

Contingency: If lazy expansion is insufficient, replace the tree widget with a paginated drill-down navigator (select level → select child) that avoids rendering more than 50 nodes at a time.

medium impact medium prob dependency

Bufdir may update their required export column structure or file format during or after development. If the AdminExportService hardcodes the current Bufdir schema, any format change requires a code release rather than a config update.

Mitigation & Contingency

Mitigation: Drive the Bufdir column mapping from a configuration repository rather than hardcoded constants. Abstract column definitions into a named schema config so that format changes require only a config update and re-deployment without service logic changes.

Contingency: If Bufdir format changes post-launch, release a config update within one sprint. If the change is structural (new required sections), scope a targeted service update and communicate timeline to partner organisations.

high impact medium prob integration

Role transition side-effects in UserManagementService (e.g., certification expiry removing mentor from chapter listing, pause triggering coordinator notification) may interact with external services like HLF's website sync. Incomplete side-effect handling could leave the system in an inconsistent state.

Mitigation & Contingency

Mitigation: Model side-effects as explicit domain events published after the primary state change is persisted. Implement event handlers as idempotent operations so re-processing is safe. Write integration tests that assert all side-effects fire correctly for each role transition type.

Contingency: If a side-effect fails after the primary change is persisted, log the failure with full context and trigger a manual reconciliation alert to the on-call team. Provide an admin-accessible re-trigger action for failed side-effects.

medium impact medium prob scope

If AdminStatisticsService cache TTL is set too long, org_admin may see significantly stale KPI values (e.g., a mentor newly paused an hour ago still appears as active), undermining trust in the dashboard.

Mitigation & Contingency

Mitigation: Default cache TTL to 5 minutes with a manual refresh action on the dashboard. Implement cache invalidation triggered by UserManagementService write operations that affect counted entities.

Contingency: If staleness causes org admin complaints post-launch, reduce TTL to 60 seconds and introduce a real-time Supabase subscription for high-impact counters (paused mentors, expiring certifications).