Build paginated audit log view for flag changes
epic-organization-feature-flags-ui-task-005 — Implement the read-only paginated audit log section within the admin screen that displays all flag change events. Each log entry must show: flag name, previous state, new state, timestamp, and the admin who made the change. Use cursor-based pagination via FeatureFlagRepository with a 'Load more' control. Entries must be read-only with no interactive elements.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use a Riverpod AsyncNotifier
Do not use a separate inner ScrollView—this causes nested scroll conflicts on mobile. The StateBadge for 'enabled' should use the design token for success-adjacent color (verify against styles.css token set) and 'disabled' should use muted/secondary color, always paired with text.
Testing Requirements
Widget tests using flutter_test and mocked FeatureFlagRepository: (1) first page renders correct number of entries with all required fields visible; (2) 'Load more' button appears when nextCursor is non-null; (3) 'Load more' button is absent when nextCursor is null; (4) tapping 'Load more' appends entries without replacing existing ones; (5) empty state renders when entry list is empty; (6) error state renders when initial load throws; (7) no tap handler is registered on any log entry tile. Also write a golden test to prevent unintended visual regressions on the AuditLogEntryTile.
The feature flag admin screen allows persisting changes to organization_configs. If the role guard is implemented only client-side (checking role state in Riverpod), a user who manipulates their local role state could toggle flags for their organization without proper server-side authorization, potentially exposing features prematurely.
Mitigation & Contingency
Mitigation: Implement server-side authorization for flag update operations using Supabase RLS UPDATE policies that check the user's role in the memberships table. The client-side guard is UX only; the database enforces the actual restriction.
Contingency: If an unauthorized update is detected, audit the RLS policies and add a Supabase Edge Function as an authorization middleware for flag toggle operations, rejecting requests from non-admin role JWTs.
Developers on other feature teams may use FeatureGate incorrectly — for example, wrapping business logic rather than UI, or using it before flag initialization completes — leading to features that are visible but non-functional or cause runtime errors when flags are queried in a loading state.
Mitigation & Contingency
Mitigation: Add assert statements in FeatureGate's build method that throw in debug mode if the provider is still in a loading state. Write developer documentation with a clear usage contract: FeatureGate is UI-only; logic gating must use the provider's isEnabled method directly. Include lint examples in the codebase.
Contingency: If misuse is found in code reviews, add a custom Dart lint rule via custom_lint that flags FeatureGate usage outside of the widget tree, and conduct a codebase audit to find existing violations.
If the audit log is stored in the same organization_configs table without pagination or archival strategy, high-frequency flag changes during pilot testing could produce an unbounded number of rows, degrading query performance on the admin screen.
Mitigation & Contingency
Mitigation: Store audit log entries in a separate feature_flag_audit_log table with an index on (organization_id, changed_at DESC). Implement cursor-based pagination in the repository and limit the initial load to 50 entries.
Contingency: If table size becomes a performance concern, add a Supabase scheduled function to archive entries older than 90 days to cold storage, and add a database index on changed_at for range queries.