05 — Screen Inventory (Settings Module)
- Legend
- 1. Settings List (hub) —
/settings - 2. Setting Detail —
/settings/:key - 3. Typed Value Editors (per type — embedded in list row + detail)
- 4. New Setting (FAB flow) — sheet
- 5. Delete Confirm (dialog/sheet)
- 6. History — NOT AVAILABLE
- 7. Cross-surface references (not module-owned)
- Shared components used
- Analytics events (proposed)
- Keyboard / landscape / tablet / desktop
Every screen of the Settings module, its intent, route, composition, states, permissions, platform behavior and events. Authoritative components in 00-shared/03; module-specific components in 07_Component_Library.md.
Legend
States = idle / loading / success / empty / error(offline, 5xx, 404) / disabled / permission.
Analytics events follow {module}.{screen}.{action} (proposed; SDK open — 00-shared/10 §8).
1. Settings List (hub) — /settings
| Field | Detail |
|---|---|
| Purpose | Browse all tenant settings, grouped; edit in place; batch save |
| Entry | Settings nav destination, deep link, return from detail |
| Exit | detail push, organization cross-link, 403 (no perm) |
| Source | GET /api/v1/settings (all) — array, meta omitted (non-paginated, response-envelope.interceptor.ts:25-32,55-59); GET /settings?group= on chip tap |
| Composition | AppBar (settings icon + "Settings"), AppSearchBar (client-side filter), group AppChips (enum order, setting.schema.ts:7-14), ListView.builder of SettingRow cards, extended AppFAB "New setting" |
| States | loading AppSkeleton(list); empty "No settings yet"; group-empty "Nothing in this group"; error AppErrorState(code, retry); offline banner + cached rows |
| Row | key (mono, titleMedium), value preview (type-chipped: str/num/bool/JSON), group badge on GENERAL rows, encrypted badge if isEncrypted (never today — OQ-6) |
| Multi-select | long-press → selection mode, bottom Save all (N) bar; only dirty rows serialized (03 §3) |
| Permission | settings.read (client guard); settings.update enables editors |
| Analytics | settings.list.view, settings.list.group_tap.{group}, settings.list.search, settings.bulk.save.{n} |
| Adaptive | phone: stacked cards; tablet/desktop: two-pane (list + detail pane) ≥840 dp |
2. Setting Detail — /settings/:key
| Field | Detail |
|---|---|
| Purpose | Read/write one setting with meta |
| Entry | list row tap |
| Exit | back to list; delete pops |
| Source | GET /settings/:key (settings.controller.ts:31-35) — 404 RESOURCE_NOT_FOUND if key missing (settings.service.ts:20) |
| Composition | key header (mono), group picker (AppDropdown of enum), typed value editor (see 6 §S2), label/description read-only placeholders (server drops them — settings.service.ts:25), meta footer (created/updated/version/audit ids when present), Delete (menu) |
| States | loading, loaded, 404 → AppEmptyState "Setting not found" + back |
| Permission | settings.update gates Save; settings.delete gates Delete |
3. Typed Value Editors (per type — embedded in list row + detail)
| Editor | Value type | Notes |
|---|---|---|
| String editor | string | AppTextField; saved as-is |
| Number editor | number | AppTextField numeric + inputFormatters; float-safe (server stores JSON number) |
| Boolean editor | boolean | AppSwitch row; no Save needed if instant-save toggle (see 06 §S2 decision) |
| JSON editor | object/array/null | AppJsonEditor (multi-line mono + live parse check); null treated as JSON null |
| Unknown | anything else | fall back to JSON editor |
Type inference: from the runtime JSON type of the fetched value (setting.schema.ts:21-22);
string-y numbers stay strings (no coercion — server is byte-transparent).
4. New Setting (FAB flow) — sheet
| Field | Detail |
|---|---|
| Purpose | Create an arbitrary key |
| Form | key (required, non-empty, trim), group dropdown (default GENERAL), value typed editor (JSON box) |
| Submit | PUT /settings upsert — idempotent; on E11000/500 (recreate-after-delete, OQ-5) → error banner |
| Exit | success → row appears (server-sorted position) |
5. Delete Confirm (dialog/sheet)
Confirm (destructive) → DELETE /settings/:key → snackbar; 404 → treat as removed.
Soft delete server-side (base.repository.ts:68-74) — no undo (recreate broken, OQ-5).
6. History — NOT AVAILABLE
| Item | Status |
|---|---|
| Per-setting change history / audit trail in the UI | (planned) — no settings history endpoint exists (audit module logs events generically; settings emits none). OQ-7. |
7. Cross-surface references (not module-owned)
| Screen | Owner | Route |
|---|---|---|
| Org embedded settings tabs | Organizations | /organization (S4) |
| Feature flags list | Organizations (uses Feature Flags module API) | /organization flags tab |
| Roles/members | RBAC | /settings/roles, /settings/members |
| Security hub | Auth | /settings/security |
Shared components used
AppSkeleton, AppEmptyState, AppErrorState, AppOfflineBanner, AppSnackbar,
AppSearchBar, AppChips, AppDropdown, AppTextField, AppSwitch, AppCard,
AppListTile, AppMenu, AppDialog, AppBottomSheet, AppFAB, AppBadge.
Module-specific: SettingRow, AppTypedValueEditor, AppJsonEditor, SettingGroupChips
(07_Component_Library.md).
Analytics events (proposed)
settings.list.{view,group_tap,search}, settings.detail.view,
settings.edit.{save,error}, settings.create.{submit,error},
settings.bulk.{save,n,failed_m_of_n}, settings.delete.{confirm,completed}.
Keyboard / landscape / tablet / desktop
- Phone: single pane; landscape scrolls; keyboard avoidance on editors.
- Tablet/desktop: master-detail;
Ctrl+Fsearch; hover row highlight;Entersaves editor.