high priority medium complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

AdminPortalBloc handles LoadActivityLog event by fetching page 1 with default filters and current scope, emitting ActivityLogLoading then ActivityLogLoaded state
AdminPortalBloc handles ActivityLogFilterChanged event by: (1) updating activityLogFilter in state, (2) resetting currentPage to 1 and clearing the existing activity list, (3) fetching page 1 with the new filter, and (4) emitting updated state
AdminPortalBloc handles LoadMoreActivities event by incrementing currentPage and appending the new page's items to the existing activityLog list in state; if the last page has been reached (returned items < pageSize), hasMoreActivities is set to false in state
Concurrent LoadMoreActivities events are handled safely — if a page fetch is already in-flight, the new event is dropped (use droppable transformer)
ActivityLogFilterChanged cancels any in-flight LoadMoreActivities request and restarts from page 1
State model additions: activityLog (List<ActivityLogEntry>), activityLogFilter (ActivityFilter), activityLogStatus (idle/loading/loadingMore/success/error), currentPage (int), hasMoreActivities (bool), activityLogError (nullable String)
AdminStatisticsService is called with the correct scopeId from the current org hierarchy scope state — not a hardcoded value
Unit tests achieve 100% branch coverage on all three event handlers including pagination boundary conditions

Technical Requirements

frameworks
Flutter
flutter_bloc
BLoC
apis
AdminStatisticsService.getActivityLog(scopeId, page, pageSize, filters)
AdminStatisticsService.getActivityLogPage(scopeId, ActivityFilter, int page)
data models
ActivityLogEntry
ActivityFilter
PaginatedResult<ActivityLogEntry>
AdminPortalState
performance requirements
Page size should be 20 items to balance network payload and scroll feel
LoadMoreActivities must use droppable event transformer to prevent duplicate concurrent page fetches
Filter state update and page reset must be atomic — emit a single state change, not two successive ones
security requirements
scopeId for all service calls must originate from authenticated session state in BLoC — never from the ActivityLogFilterChanged event payload
ActivityFilter object must be validated: date range end must not precede start; invalid filters emit ActivityLogFilterError state

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Add activityLog-specific sub-state fields to AdminPortalState (if using a monolithic BLoC state) or extract an ActivityLogSubState and compose it. Use EventTransformer.droppable() from bloc_concurrency package for the LoadMoreActivities handler to prevent duplicate concurrent fetches. ActivityLogFilterChanged should use restartable() to cancel an in-flight LoadActivityLog triggered by a previous filter change. Store activityLogFilter in state so the UI can reflect current active filters; the filter object should be immutable (use copyWith).

When appending pages, create a new list with List.unmodifiable([...existing, ...newPage]) to maintain state immutability. Consider a private _fetchActivityLogPage() helper to avoid duplicating the fetch + error handling logic across LoadActivityLog and LoadMoreActivities handlers.

Testing Requirements

Unit tests with bloc_test: (1) LoadActivityLog → loading → loaded with page 1 items, hasMoreActivities: true, (2) LoadActivityLog returns empty → loaded with empty list, hasMoreActivities: false, (3) ActivityLogFilterChanged → clears list → reloads page 1 with new filter, (4) LoadMoreActivities appends page 2 items to existing list, (5) LoadMoreActivities on last page sets hasMoreActivities: false, (6) LoadMoreActivities while fetch in-flight → dropped (assert service called only once), (7) ActivityLogFilterChanged while page fetch in-flight → cancels previous → fetches with new filter, (8) service throws on LoadActivityLog → emits error with previous list preserved. All tests use mock AdminStatisticsService via Mockito.

Component
Activity Log Viewer
ui medium
Epic Risks (3)
high impact medium prob technical

If org node selection in AdminStateBLoC does not correctly propagate to all dependent data streams (statistics, activity log, user list, certification panel), some panels may show data from the previously selected org scope, creating a confusing and potentially dangerous mixed-scope view.

Mitigation & Contingency

Mitigation: Model org node selection as a single source of truth in AdminStateBLoC. All downstream providers derive their query parameters from this single stream via Riverpod's watch pattern. Write integration tests that verify every data stream emits a reload event when the selected node changes.

Contingency: If scope propagation bugs are detected in QA, add an explicit full-state reset on org node change (clear all cached data and refetch from scratch) as a safe but less efficient fallback until the targeted propagation is fixed.

medium impact medium prob technical

The Admin Dashboard Screen must adapt its layout for Flutter Web (wider viewports, mouse interaction, larger grid) and mobile embedding. Flutter Web responsive layout support has historically required non-trivial workarounds, and the adaptive grid may introduce significant additional development time.

Mitigation & Contingency

Mitigation: Define breakpoints and grid behaviour in the design system before implementation. Use LayoutBuilder with explicit breakpoint constants rather than MediaQuery scattered across widgets. Prototype the web layout with a skeleton screen before implementing live data binding.

Contingency: If web layout proves intractable within sprint, deliver a mobile-first layout for all platforms initially and track a dedicated web-optimisation task for the next sprint.

high impact low prob security

A bug in the Role Assignment Panel's permission scope validation could allow an org_admin to assign roles beyond their authority (e.g., assigning super_admin to a user), representing a serious privilege escalation vulnerability.

Mitigation & Contingency

Mitigation: Enforce role assignment scope on both the client (disable unavailable roles in the panel UI) and the server (UserManagementService validates the target role is within the admin's permitted scope before persisting). Write security-focused tests that attempt out-of-scope role assignments and assert rejection.

Contingency: If an escalation vulnerability is discovered, immediately disable the role assignment panel via feature flag, revoke any incorrectly assigned roles, and deploy a server-side fix before re-enabling.