high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

TerminologyAdminPreviewScreen is a Riverpod ConsumerWidget and renders without errors on both iOS and Android
Screen is only accessible to users with coordinator or administrator roles; all other roles receive a 403/no-access redirect
App bar displays the active organization's name as the title
Loading state renders a centered CircularProgressIndicator while OrganizationLabelsNotifier is in loading state
Error state renders a user-friendly error message with a retry button when TerminologyRepository throws
Empty state renders a placeholder message when the label map returns an empty collection
Screen is wired to OrganizationLabelsNotifier and TerminologyRepository via Riverpod providers — no direct instantiation
Switching active organization triggers a provider refresh and the screen re-renders with the new org's data
Screen passes flutter_test widget tests for loading, error, and empty states using mocked providers

Technical Requirements

frameworks
Flutter
Riverpod
apis
TerminologyRepository (read)
OrganizationLabelsNotifier (watch)
data models
OrganizationLabelMap
LabelKeyRegistry
Organization
performance requirements
Initial render must complete within 300ms on mid-range device
Provider watch must not cause unnecessary rebuilds outside loading/error/data state transitions
security requirements
Role guard must be enforced at the widget level AND at the route guard level — defense in depth
No label values containing PII must be logged or exposed in error messages
ui components
Scaffold with AppBar
CircularProgressIndicator (loading state)
ErrorWidget with retry button (error state)
EmptyStateWidget (empty state)
Page header using design token typography

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use AsyncValue pattern from Riverpod for state handling — switch on AsyncValue with .when(data, loading, error). Apply the existing role-guard HOC/mixin already used on other admin screens rather than reimplementing RBAC locally. The app bar subtitle slot should be reserved for the last-updated timestamp added in task-011 — leave it as an empty subtitle or null for now to avoid layout shift later. Use HtmlGenerationUtils-equivalent Flutter equivalents (shared page scaffold widget) if one exists in the project's shared widgets layer.

Avoid StatefulWidget; use ConsumerWidget only.

Testing Requirements

Write flutter_test widget tests covering: (1) loading state renders CircularProgressIndicator, (2) error state renders error message and retry CTA, (3) empty state renders placeholder, (4) data state renders scaffold without throwing. Mock OrganizationLabelsNotifier and TerminologyRepository using Riverpod overrides. Verify role guard redirects non-coordinator/admin users. Target 100% branch coverage on state handling logic.

Epic Risks (3)
high impact medium prob integration

WcagSemanticsLabelResolver's Semantics wrappers may conflict with Semantics nodes already defined by existing accessible widgets (e.g., accessible-bottom-navigation, activity-wizard-semantics), causing duplicate or contradictory screen reader announcements that fail WCAG 2.2 AA criteria.

Mitigation & Contingency

Mitigation: Audit all existing Semantics-annotated widgets in the accessibility feature before implementing WcagSemanticsLabelResolver. Define a clear hierarchy rule: WcagSemanticsLabelResolver always merges with, never replaces, existing Semantics nodes. Use Flutter's debugSemantics output in CI to detect conflicts automatically.

Contingency: If conflicts are discovered in testing, introduce a resolverMode parameter to WcagSemanticsLabelResolver allowing it to operate in 'override' or 'merge' mode per call site; coordinate with the Screen Reader Support feature team to align Semantics strategies.

medium impact medium prob technical

If TerminologyAwareTextWidget subscribes to the full terminology map provider rather than the per-key labelProvider family, a single label update will trigger a full widget-tree rebuild across all screens simultaneously, causing jank on devices used by older peer mentors.

Mitigation & Contingency

Mitigation: Implement TerminologyAwareTextWidget using ref.watch(labelProvider(key)) on the per-key family provider from TerminologyRiverpodProviders so that only widgets bound to the changed key rebuild. Verify with Flutter DevTools 'rebuild tracking' in widget tests.

Contingency: If full-map subscriptions slip through code review, add a Riverpod lint rule that flags direct organizationLabelsNotifierProvider subscriptions inside widget build methods and enforces the per-key family pattern.

medium impact low prob security

The TerminologyAdminPreviewScreen requires coordinator-level access, but if role checks rely solely on client-side guard logic without matching Supabase RLS policies, a peer mentor could potentially access the admin preview by manipulating navigation state.

Mitigation & Contingency

Mitigation: Protect the admin preview route with a server-validated role guard that re-fetches the user's role from Supabase on screen initialization, not just from local state. Add a Supabase RLS policy that restricts label map read access for the admin preview endpoint to coordinator and admin roles only.

Contingency: If unauthorized access is discovered in testing, immediately add a middleware role assertion that redirects non-coordinators to the no-access screen and logs the unauthorized navigation attempt for audit.