medium priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

Each flag row in the admin list shows its current rollout conditions inline: minimum version (or 'Any version') and activation date (or 'Immediate')
Tapping the conditions inline area or an edit icon expands a configuration panel (inline expansion or bottom sheet) with two fields: minimum version and activation date
The minimum version field accepts only valid semver strings (e.g., '1.2.3'); invalid input prevents save and shows an inline validation error
The activation date field uses Flutter's showDatePicker and enforces that the date cannot be in the past
Both fields are optional; clearing them resets to 'Any version' and 'Immediate' respectively
Tapping 'Save' persists the conditions via FeatureFlagRepository.updateRolloutConditions() and closes the panel
On save success, RolloutEvaluator is notified/invalidated so it re-evaluates active flags with the new conditions
On save failure, the panel remains open with an error message; no partial state is persisted
Tapping 'Cancel' discards unsaved changes and closes the panel
All form inputs are accessible with descriptive labels, error messages linked via aria equivalents (Flutter Semantics), and keyboard-navigable

Technical Requirements

frameworks
Flutter
Riverpod
apis
FeatureFlagRepository.updateRolloutConditions(flagId, RolloutConditions): Future<void>
RolloutEvaluator.invalidate() or equivalent Riverpod provider invalidation
data models
RolloutConditions (minAppVersion: String?, activationDate: DateTime?)
FeatureFlag (id, name, isEnabled, impactDescription, rolloutConditions)
performance requirements
Panel open/close animation must complete within 200ms
Semver validation must be synchronous (regex-based), no async calls
security requirements
Rollout condition updates must require admin role; repository must validate server-side
Activation dates must be validated server-side to prevent backdating via API manipulation
ui components
RolloutConditionsPanel (expansion tile or modal bottom sheet)
SemverTextField (AppTextField with semver regex validator)
DatePickerField (tappable field wrapping showDatePicker)
RolloutConditionsSummary (inline read-only display per flag row)

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Use a local Riverpod StateNotifierProvider scoped to the panel widget to manage form field values and validation state independently of the global flag list. The semver regex should match the canonical pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$. For the date picker, pass DateTime.now() as firstDate to enforce no-past-date constraint. After a successful save, call ref.invalidate(featureFlagListProvider) and ref.invalidate(rolloutEvaluatorProvider) to ensure both the admin list and the client-side evaluator pick up the new conditions.

Prefer an inline ExpansionTile panel over a bottom sheet to keep the admin workflow on one screen and reduce navigation cognitive load—consistent with the WCAG 2.2 AA principle of predictable UI.

Testing Requirements

Widget tests: (1) rollout conditions summary displays correctly for flags with and without conditions; (2) panel opens on edit tap; (3) invalid semver input shows error and disables save; (4) past activation date shows error and disables save; (5) valid inputs enable save button; (6) save calls repository with correct RolloutConditions model; (7) cancel discards changes without repository call; (8) repository failure shows error and keeps panel open; (9) after successful save, the inline summary updates to reflect new conditions. Integration test: full edit flow from list view → panel open → input → save → verify summary updated.

Component
Feature Flag Admin Screen
ui medium
Epic Risks (3)
high impact low prob security

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.

medium impact medium prob scope

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.

medium impact low prob technical

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.