05 — Screen Inventory (Feature Flags Module)
- 1. Flags List (
/settings/feature-flags) - 2. Flag Detail (
/settings/feature-flags/:key) - 3. Flag Editor (
/settings/feature-flags/:key/edit) — create + edit modes - 4. Bulk Update (bottom sheet over list)
- 5. Affected-Features Map (detail companion) —
(proposed)client composition - Shared components used
- Analytics events (proposed)
- Keyboard, landscape, tablet, desktop
Every screen of the module: intent, route, composition, states, permissions, platform behavior. Authoritative components in 00-shared/03; module-specific widgets in 07_Component_Library.md.
Legend — States: idle / loading / success / empty / error(offline, 401) / disabled / permission. Analytics events follow
{module}.{screen}.{action}(proposed; SDK open — 00-shared/10 §8).
1. Flags List (/settings/feature-flags)
| Field | Detail |
|---|---|
| Purpose | Browse tenant toggle catalog; grouped by module; quick-toggle; entry to detail/bulk |
| Entry | Settings hub; deep link with ?module= prefilter |
| Exit | row → detail; bulk sheet; back → settings |
| Source | GET /feature-flags (all, sorted key asc — feature-flags.service.ts:11); GET /feature-flags?module= (feature-flags.controller.ts:25-27); tab → GET /feature-flags/enabled (feature-flags.controller.ts:30-34) |
| Composition | AppSearchBar(optional, client-side), module FilterChips (distinct module values), "Enabled only" toggle tab, grouped list (AppSectionHeader per module), row = AppFlagRow |
| States | loading (AppSkeleton(list)); empty (AppEmptyState — fresh tenant); error (AppErrorState); offline (cached + banner); permission (no feature-flags.read → route guarded, 403 screen) |
| Row actions | switch (optimistic toggle, PUT /feature-flags), AppMenu: Edit, Delete |
| Bulk CTA | AppButton "Bulk update" (enabled when ≥ 1 selection; selection mode via long-press or checkbox toggle) |
| Analytics | featureflags.list.view, featureflags.list.filter{module}, featureflags.toggle{key,value} (proposed) |
| Adaptive | phone: list full width, selection via long-press; tablet/desktop: master-detail at ≥ 840 px, hover row highlight |
| a11y | each row Semantics(button, toggled:); module headers announced; filter chips with selected state |
| Motion | m-entrance stagger on rows; switch m-fast |
2. Flag Detail (/settings/feature-flags/:key)
| Field | Detail |
|---|---|
| Purpose | Full picture of one flag + primary toggle |
| Entry | list row tap; deep link |
| Exit | edit; delete; back to list |
| Source | GET /feature-flags/:key → doc; 404 if key missing (feature-flags.service.ts:27-31) |
| Composition | header (key mono, module AppBadge, enabled AppSwitch), AppInfoRows: label, description (or "—"), timestamps createdAt/updatedAt (BaseSchema timestamps:true, base.schema.ts:33-34), tenant scoping note; edit AppButton; delete AppButton (destructive, dialog) |
| States | loading (skeleton); 404 → AppEmptyState "Flag not found" (deleted/renamed); error; offline |
| Permissions | read → view; update → toggle/edit enabled; delete → delete (target contract, OQ-5) |
| Analytics | featureflags.detail.view, featureflags.detail.toggle{key,value} (proposed) |
| a11y | switch semantics; key read as mono code; description in body text |
| Motion | hero from list row (m-slow) — optional; toggle m-fast |
3. Flag Editor (/settings/feature-flags/:key/edit) — create + edit modes
| Field | Detail |
|---|---|
| Purpose | Edit/create one flag: key, enabled, label, description, module |
| Entry | detail "Edit"; FAB "New flag" (create mode — key empty) |
| Exit | Save → detail (refresh); discard → back |
| Source | Save = PUT /feature-flags (upsert — create-or-update, feature-flags.controller.ts:42-46); in create mode a missing key creates a new flag |
| Composition | form fields per 08_Form_Specifications.md; save AppButton (loading) |
| States | edit mode pre-fills from detail doc; create mode empty; saving; validation errors inline; warning banner: description/module are not persisted by the server upsert (feature-flag.repository.ts:40) — see OQ-3 |
| Analytics | featureflags.edit.save{key}, featureflags.create.save{key} (proposed) |
| a11y | labels linked, focus first field, error announce |
| Adaptive | full-screen page (5 fields); tablet centered column ≤ 560 px |
| Motion | m-base push; save success → check + pop |
4. Bulk Update (bottom sheet over list)
| Field | Detail |
|---|---|
| Purpose | Apply a target state to N selected flags |
| Entry | list "Bulk update" (≥ 1 selected) |
| Source | PUT /feature-flags/bulk — body array of UpdateFeatureFlagDto (feature-flags.controller.ts:48-52) |
| Composition | header "Update N flags", mode toggle (enable all / disable all), optional label edit (single field applied to all — (proposed); server only persists enabled+label, feature-flag.repository.ts:40), apply AppButton |
| Result | per-row outcome list (success/fail) — server is sequential, no transaction (feature-flags.service.ts:40-44); failed subset can be retried |
| States | idle (count N), applying (progress), done (per-row results), error (partial) |
| Analytics | featureflags.bulk.apply{n,target}, featureflags.bulk.result{n_ok,n_fail} (proposed) |
| a11y | sheet focus trap; progress announced (live region) |
| Motion | m-base sheet; rows fade-in stagger |
5. Affected-Features Map (detail companion) — (proposed) client composition
| Field | Detail |
|---|---|
| Purpose | Show the end-user surface a flag gates ("turning this off hides: Biometric check-in") |
| Entry | detail screen "Affects" section / tab |
| Source | No backend endpoint — the client composes this from: flag module field, the client's own gated-widget registry (FeatureFlagsCubit keys → screens), and (planned) IMPLEMENTATION_PLAN.md:310-336 matrices. Purely a client-side map; mark results with the module badge. |
| States | empty ("no client screens mapped to this key yet") — key is not in the registry |
| Note | Must not claim server authority; render as informational, (proposed) — hidden when no client registrations exist |
Shared components used
AppSkeleton, AppEmptyState, AppErrorState, AppOfflineBanner, AppSnackbar,
AppBanner, AppSwitch, AppChips (FilterChip), AppListTile, AppCard, AppButton,
AppDialog, AppBottomSheet, AppMenu, AppSectionHeader, AppBadge, AppFAB,
AppInfoRow, AppSearchBar.
Module-specific: AppFlagRow, AppFlagGroupHeader, AppFlagEditorForm, AppBulkUpdateSheet,
AppFlagKeyChip, AppAffectedMapCard — defined in 07_Component_Library.md.
Analytics events (proposed)
featureflags.list.{view,filter,toggle}, featureflags.detail.{view,toggle},
featureflags.edit.{save,fail}, featureflags.create.{save,fail},
featureflags.bulk.{apply,result}, featureflags.delete.{confirm,cancelled},
featureflags.gate.{blocked,shown} (gate events from FeatureFlagsCubit, proposed).
Keyboard, landscape, tablet, desktop
- List: phone long-press → selection; desktop hover + right-click menu;
Nnew. - Editor:
Tabkey→enabled→label→description→module→save;Entersubmits;Escdiscards. - Bulk sheet: arrow keys navigate rows;
Entertoggles selection. - All lists
ListView.builder; keyboards avoid insets on phone.