04 — Information Architecture (Feature Flags Module)
- 1. Placement in the shell
- 2. Route table (module-owned; extends
00-shared/05 §4) - 3. Screen hierarchy
- 4. Modal hierarchy (module)
- 5. Screen relationships
- 6. Nested nav
- 7. Quick actions / FAB / context menus
- 8. Deep links (proposed)
- 9. Accessibility of IA
- 10. Peripheral: what the module owns vs the shell
Where the Feature Flags screens live in the shell (00-shared/05). The module owns a Settings sub-section (
/settings/feature-flags, admin-only) plus the global gating service that influences every role's surface (rendered elsewhere; owned byFeatureFlagsCubit, see 13). Everything is derived fromfeature-flags.controller.ts(routes) and the shared shell.
1. Placement in the shell
App
└─ AppShell (role-aware)
├─ NavigationBar / Rail / Drawer (00-shared/05 §2)
└─ /settings [admin]
└─ Settings hub
└─ /settings/feature-flags Feature Flags (this module)
├─ /settings/feature-flags list (all / by module / enabled)
├─ /settings/feature-flags/:key flag detail
├─ /settings/feature-flags/:key/edit flag editor (full-screen, >3 fields)
└─ (sheet) bulk update
└─ global: FeatureFlagsCubit gates routes & widgets across all modules
(biometric, notifications/channels, payments — (forward-looking) consumers)
Settingsis an existing top-level destination (00-shared/05 §2: "Settings | /settings | admin"), so the flags section is a settings sub-page — same pattern as Auth's Security hub under/settings(auth/04 §1).- The route prefix is module-owned and proposed (no client exists;
00-shared/12 D1/A2):/settings/feature-flags. Alternative(proposed): nest under/settings/integrationsonce theintegrationsmodule lands (blueprint lists it separately,COLLECTIONS.md:805-818).
2. Route table (module-owned; extends 00-shared/05 §4)
| Route | Screen | Auth | Perm (target) | Source API |
|---|---|---|---|---|
/settings/feature-flags | Flags list | JWT | feature-flags.read | GET /feature-flags (+?module=) |
/settings/feature-flags?tab=enabled | Enabled-only list | JWT | feature-flags.read | GET /feature-flags/enabled |
/settings/feature-flags/:key | Flag detail | JWT | feature-flags.read | GET /feature-flags/:key |
/settings/feature-flags/:key/edit | Flag editor | JWT | feature-flags.update | PUT /feature-flags |
/settings/feature-flags/bulk | Bulk update (sheet) | JWT | feature-flags.update | PUT /feature-flags/bulk |
| (menu) delete | — | JWT | feature-flags.delete (target) | DELETE /feature-flags/:key |
Guard note: permissions are not enforced server-side today (
rbac.guard.ts:29,feature-flags.controller.ts:18) — the routes are spec'd as if they will be (OQ-5).
3. Screen hierarchy
- Flags list is the hub: rows → detail; module filter chips + enabled tab; FAB / bulk button; row menu (edit, delete).
- Detail → Edit (full-screen page — 5 fields incl. description;
> 3 fields→ page per00-shared/05 §5); Edit returns → Detail (refresh). - Bulk update is a bottom sheet over the list (selection state lives in the list cubit).
flowchart TD
SET[/settings/] --> FF[/settings/feature-flags/]
FF --> ENABLED[/settings/feature-flags?tab=enabled/]
FF --> DET[/settings/feature-flags/:key/]
FF --> BULK(("bulk sheet"))
DET --> EDT[/settings/feature-flags/:key/edit/]
EDT --> DET
DET --> FF
BULK --> FF
FF -. gates .-> OTHER[every gated module screen via FeatureFlagsCubit]
4. Modal hierarchy (module)
Following 00-shared/05 §5:
- Snackbar/toast — "Feature enabled", "3 of 5 flags updated", "Flag deleted", copy.
- Bottom sheet — bulk update (selection + apply), key quick-copy.
- Dialog — delete confirm (destructive; typed confirm not required — soft delete is reversible at DB level but re-creation is blocked today, OQ-4 → use standard destructive confirm with the re-create caveat in copy).
- Full-screen page — flag editor (5 fields), flags list on phone.
- Loader — button spinners + list skeletons; never full-screen dual column.
5. Screen relationships
- Flags list → detail returns with changed state (toggle flipped) — detail cubit refreshes
on return; list refreshes on detail pop (
RefreshIndicator+ cubitRefresh). - Bulk sheet applies → list refetches → per-row result banner.
- Delete → row removed (server-confirm, no optimistic removal for delete; toggle IS optimistic).
- Global: whenever
FeatureFlagsCubitrefreshes (app.resume, pull-to-refresh, TTL), every gated widget rebuilds viaBlocBuilder/BlocSelector— no route change needed.
6. Nested nav
- Tablet/desktop ≥ 840 dp: master-detail — list left pane, detail right (
00-shared/04 §6). - Phone: push (list → detail → edit).
- The bulk sheet keeps list selection state in
FlagsListCubit(sheet is a view of it).
7. Quick actions / FAB / context menus
- FAB (extended): "New flag" — opens the flag editor in create mode (upsert with a new
key). One FAB per screen (
00-shared/03 D). - Row
AppMenu: Edit, Delete (destructive). - Module filter chips + "Enabled only"
FilterChiprow under the AppBar. - Keyboard (desktop):
Ctrl+Ksearch n/a (list is short);Nnew flag;Esccloses sheet; space toggles focused switch (00-shared/08 §2).
8. Deep links (proposed)
| Pattern | Target | Note |
|---|---|---|
studylyon://settings/feature-flags | Flags list | admin |
studylyon://settings/feature-flags/:key | Flag detail | supports support-links |
studylyon://settings/feature-flags?module=biometric | Filtered list | prefill filter |
9. Accessibility of IA
- One
headlineMediumper screen; list rows ordered: name → module badge → state switch. - Focus begins on first filter chip (desktop); switch rows announce state
(
Semantics(toggled:),09_Accessibility_Baseline.md §5). - Gated screens: hidden content is removed from the semantics tree, never "disabled-but- announced" (screen readers must not read what the tenant can't use).
10. Peripheral: what the module owns vs the shell
- Shell-owned: Settings hub entry, global 403/404 screens, offline banner.
- Module-owned: the four flag screens + the bulk sheet + the global gating contract (FeatureFlagsCubit) that other modules consume — gating widgets live in shared, driven by this module's state (13_State_Management.md).