high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

CRUD happy-path tests: createUser, readUser, updateUser, deleteUser each have a passing test verifying correct repository calls, returned entity shape, and no side-effect calls for normal operations
Invalid role transition test: attempting to assign a role that violates the allowed transition matrix (e.g., peer_mentor → national_admin) throws a RoleTransitionException (or returns a typed Failure); test asserts the exception type and message, and that no repository write occurred
Out-of-scope write rejection: calling updateUser or deleteUser for a user outside the authenticated admin's org scope returns a ScopeViolationException; mock OrgHierarchyService to simulate scope boundaries; assert repository write is never called
Certification expiry side-effect test: when certificationExpiryDate is set to a past date during updateUser, the service calls the chapter-listing removal side-effect; mock and verify the side-effect call is made exactly once with the correct user ID
Transactional rollback test: when the chapter-listing removal side-effect throws an exception, the primary user update is rolled back (or the service re-throws and leaves the user record unchanged); test asserts the user record remains in its pre-update state by verifying no commit call on the repository
Notification dispatcher mock: when a user is created or has a role change, the notification dispatcher mock receives exactly one call with the correct notification type; verify(mockNotificationDispatcher.dispatch(...)).called(1)
No notification sent when update contains no role change or status change — verify dispatcher is NOT called in those scenarios
Test suite achieves ≥ 90% branch coverage on UserManagementService
All tests are isolated: each test creates a fresh service instance with fresh mocks; shared state between tests is forbidden

Technical Requirements

frameworks
flutter_test
mocktail for UserRepository, OrgHierarchyService, NotificationDispatcher mocking
apis
UserManagementService public API
UserRepository (mocked)
OrgHierarchyService.getSubtreeIds() (mocked)
NotificationDispatcher.dispatch() (mocked)
ChapterListingService.removeUser() (mocked)
data models
User (id, name, role, certificationExpiryDate, orgId)
RoleTransition (fromRole, toRole)
OrgScopeFilter
UserManagementException hierarchy (RoleTransitionException, ScopeViolationException)
performance requirements
All tests complete in < 8 s; no async timers or real network calls
security requirements
Confirm that out-of-scope write rejection is enforced in the service layer, not merely in the repository, by asserting the repository mock receives zero write calls on scope violation
Verify that role transition validation occurs before any data is written — assert exception is thrown before repository.save() is called

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

This is the most complex service to test due to the interaction of role validation, scope checks, side-effects, and rollback. Structure tests with the Arrange-Act-Assert (AAA) pattern with explicit comments delineating each section. For transactional rollback testing, if the service does not currently have an injectable transaction manager or unit-of-work abstraction, coordinate with the implementation owner to add one before writing rollback tests — testing rollback against real Supabase transactions is not feasible in unit tests. Mock OrgHierarchyService.getSubtreeIds to return a fixed set of org IDs for scope tests; assert via verify that UserRepository.save is called only when the target user's orgId is within that set.

For certification expiry tests, pass a User object with a certificationExpiryDate in the past and verify the side-effect mock is called; for a User with a future expiry date, verify the side-effect is NOT called. Keep each test focused on one behaviour — do not combine CRUD and role transition in a single test case.

Testing Requirements

Pure Dart unit tests (flutter_test) with mocktail mocks for all external dependencies. Organise in test groups: 'CRUD happy paths', 'role transition validation', 'scope enforcement', 'certification expiry side-effects', 'transactional integrity', 'notification dispatch'. Use when().thenReturn() / when().thenThrow() from mocktail to simulate both success and failure paths for each side-effect. For rollback tests, if the service uses a database transaction abstraction, mock the transaction object and verify commit() is not called on failure.

All exception-type assertions should use throwsA(isA()) pattern. Run dart test --coverage and enforce ≥ 90% branch coverage on UserManagementService in CI.

Component
User Management 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).