Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

05 — Screen Inventory (Organizations Module)

Every screen in the module. Data contracts derive from organizations.controller.ts, settings.controller.ts, feature-flags.controller.ts, DTOs, and schemas. States follow 00-shared/06 §3.1 (initial/loading/success/error) + empty + offline + permission. Analytics events are (proposed) per 10_QA_Baseline.md §8 ({module}.{screen}.{action}).


S1 — Org Overview (self)

AttributeValue
Route/organization
PurposeRead-only institution identity summary + entry to all org actions
EntryDrawer/rail "Organization"; post-login for admins; back-target of edit/branding/settings
ExitEdit/Branding/Settings/Flags/Members; back → shell home
Permissionany organization.* or settings.* read

Layout (phone / tablet+): AppBar "Organization" → hero header (logo AppAvatar, name, status chip, plan chip) → AppBanner if status === onboarding → section cards:

SectionCards/rows (from organization.schema.ts)Widgets
Identityname, slug, domain, logoFileIdAppCard + AppInfoRow
Contactcontact.email, contact.phone, contact.website (organization.schema.ts:53-58)AppInfoRow
Addressstreet, city, state, country, zip (:60-67)AppInfoRow
Localizationtimezone (default UTC), currency (default USD) (:69-73)AppInfoRow
Academic yearacademicYear.startDate, endDate, month (:75-80)AppInfoRow
Subscriptionplan (free/basic/premium/enterprise), status (active/inactive/suspended/trial) (:82-94)AppBadge plan + status
Settings summaryattendance workingDays, theme primaryColor (link → tabs)AppListTile/organization/settings
Feature flags countcount of enabled keys (link → flags)AppListTile/organization/feature-flags
  • Actions (top bar): Edit (organization.update), Branding shortcut.
  • States: loading → AppSkeleton list; error → AppErrorState + retry; empty/unknown → treated as 404 "organization not found"; offline → last-good cache + AppOfflineBanner.
  • Pull-to-refresh: re-fetch org (bypass cache).
  • Keyboard/tablet/desktop: no inputs; tablet = 2-column info grid; desktop = wider grid + breadcrumb.
  • A11y: one headlineMedium; status chips = icon + label (never color-only, 09 §9); hero logo Semantics name.
  • Analytics (proposed): organizations.overview.view, organizations.overview.edit.tap, organizations.overview.branding.tap.
  • Data: GET /api/v1/organizations/:id — id resolution: OQ-1 (no self endpoint; (planned) /me; stopgap: lookup via list q=<slug>).

S2 — Org Edit (self)

AttributeValue
Route/organization/edit
PurposeEdit name, slug, domain, contact, address, timezone, currency, academic year, subscription (read-only for non-billing roles)
EntryOverview "Edit"; Exit: back (unsaved guard) / save → overview
Permissionorganization.update

Sections (form groups, full screen — >3 fields per 00-shared/05 §5):

  1. Identity: name, slug, domain (update-organization.dto.ts:62-75); 2. Contact: email/phone/website (:85-87); 3. Address: street/city/state/country/zip (:89-94); 4. Localization: timezone (searchable sheet), currency (sheet); 5. Academic year: startDate/endDate (date pickers), month (number); 6. Subscription: plan + status dropdowns (org_admin) — read-only for custom roles without billing perms; (proposed) since no dedicated billing permission exists; 7. Branding link-out.
  • Widgets: AppTextField, AppDropdown, AppDatePicker, AppSearchBar (timezone/currency picker sheets).
  • States: load skeleton; save spinner on primary CTA "Save changes"; 409 → inline field conflict; 400 → field errors; offline → blocked; permission → CTA hidden.
  • Animations: section entrance stagger m-entrance (40 ms); unsaved guard dialog m-base.
  • Analytics (proposed): organizations.edit.save.success|error, organizations.edit.slug.conflict.

S3 — Branding

AttributeValue
Route/organization/branding
PurposeSet branding {primaryColor, secondaryColor, logo, favicon} (organization.schema.ts:114-120; DTO update-organization.dto.ts:125-128)
EntryOverview → Branding; Exit: save → overview
Permissionorganization.update

Widgets: live preview panel (theme card rendering current colors, (proposed) — applies primary override per 02_Design_Tokens.md §1), color picker (AppColorPicker — custom, (proposed)), logo upload (AppAttachmentTile upload → logoFileId, storage (planned) per IMPLEMENTATION_PLAN.md:24-34), favicon upload (optional).

  • States: upload progress per file; save spinner; error on upload → retry tile; offline → pick colors locally, upload blocked.
  • A11y: color picker also exposes hex text field (color-blind safe, 09 §9); preview Semantics summary.
  • Analytics (proposed): organizations.branding.preview, organizations.branding.save.

S4 — Settings tabs

AttributeValue
Route/organization/settings
PurposeEdit embedded settings (attendance/academic/theme) + glance at standalone settings collection groups
EntryOverview → Settings; Exit: back
Permissionorganization.settings.update (save); settings.read for read-only tabs

Tabs (from update-organization-settings.dto.ts:4-30 + setting.schema.ts:7-14):

TabFieldsSource
General(standalone collection group general)setting.schema.ts:14
AttendancegracePeriod, lateThreshold, halfDayThreshold (minutes), workingDays[] (0–6)update-organization-settings.dto.ts:8-12
AcademicgradingScale, passingPercentage:18-21
Grading(standalone group grading)setting.schema.ts:10
Notification(standalone group notification):11
ThemeprimaryColor, secondaryColor:26-29
  • Widgets: AppTabs keep-alive; numeric AppTextField (number keyboard, (proposed) bounds: thresholds 0–300, workingDays 0–6 with day-chip multi-select AppChips, passingPercentage 0–100); hex color fields.
  • Save model: one global "Save all" → PATCH :id/settings with full merged object (full-replace semantics — organizations.service.ts:134); per-tab autosave is forbidden (would wipe siblings).
  • States: per-tab loading skeleton; dirty-indicator per tab; save spinner; success snackbar; 400 field errors.
  • Analytics (proposed): organizations.settings.tab.view, organizations.settings.save.

S5 — Feature flags

AttributeValue
Route/organization/feature-flags
PurposeView + toggle tenant feature map
EntryOverview → Feature flags; Exit: back
Permissionfeature-flags.read (view), feature-flags.update (toggle)

Content: merged view of (a) org map metadata.featureFlags (GET :id/feature-flagsRecord<string,boolean>, organizations.service.ts:139-142) and (b) catalog GET /api/v1/feature-flags (feature-flags.controller.ts:23-28) for labels/descriptions/module. Rows grouped by module with collapsible sections; row = AppListTile + AppSwitch (optimistic).

  • Actions: toggle → optimistic update, then PATCH :id/feature-flags full map (organizations.service.ts:144-154); rollback + snackbar on error. Delete flag (standalone) → DELETE /feature-flags/:key (feature-flags.controller.ts:54-58).
  • Empty state: AppEmptyState "No feature flags configured" (both lists empty).
  • Analytics (proposed): organizations.flags.toggle.{key}.

S6 — Invite admin (members)

AttributeValue
Route/organization/members
PurposeAdd an organization admin (cross-module: user + membership)
EntryOverview → Members; Exit: back
Permissionuser.create + rbac.member.create

Content: member list (GET /api/v1/rbac/members, rbac.controller.ts:57-61) + invite form: firstName/lastName/email/phone/roles (user.create + rbac.member.createrbac.controller.ts:63-67, add-member.dto roles). Row menu: change roles (PATCH /rbac/members/:id, rbac.controller.ts:69-73), remove (DELETE /rbac/members/:id, :75-79).

  • Note: exact user-creation fields follow the Users module contract (users.controller.ts:36-40) — see Users module docs. No invitation-token flow exists (OQ-2).
  • States: list skeleton; invite spinner; 409 duplicate email; empty "No members yet".
  • Analytics (proposed): organizations.members.invite, organizations.members.role.change.

S7 — Tenants list (platform)

AttributeValue
Route/admin/tenants
PurposeBrowse all tenants (paginated)
EntryPlatform drawer; Exit: back
PermissionisPlatformAdmin only (OQ-4 — server guard (planned))

Content: AppSearchBar (q → name/slug regex, organizations.service.ts:78-83), sort dropdown (sort default -createdAt:85-87; name/-name/createdAt), paginated list (page,limit default 20, pagination-query.dto.ts:5-30), infinite scroll + hasNext (buildPaginationMeta:41-54), pull-to-refresh.

  • Row: logo, name, slug, status chip, plan badge, created date. Context menu: View · Edit · Suspend · Delete.
  • States: skeleton; empty ("No tenants match"); error+retry; offline cache + banner.
  • Filters (proposed): status filter chip row (organization.schema.ts:20-25).
  • Tablet/desktop: master-detail — tapping row loads detail in right pane (00-shared/05 §3).
  • Analytics (proposed): organizations.tenants.list.view, organizations.tenants.search.

S8 — Tenant detail (+ create/edit reuse)

AttributeValue
Route/admin/tenants/:id
PurposePlatform view of one tenant: identity, subscription, status actions, delete
EntryTenants list row; Exit: back (pane)
PermissionisPlatformAdmin

Content: same identity/subscription cards as S1 (id-driven), plus status switcher (PATCH :id statusupdate-organization.dto.ts:130-133), plan/status edit, typed-confirm delete (organizations.service.ts:156-159), link-outs to Settings/Branding/Flags (reusing S3/S4/S5 with :id).

  • Tenant create (/admin/tenants/new): full-screen form = CreateOrganizationDto fields (create-organization.dto.ts:57-112) — name required, optional slug/domain/contact/address/timezone/currency/plan/branding/metadata; success → detail with slug handoff banner.
  • States/analytics: as S7 + organizations.tenants.create.success, organizations.tenants.delete.confirmed.

Screen × data × analytics matrix

ScreenPrimary endpointLoad patternKey analytics (proposed)
S1 OverviewGET /organizations/:idcache+revalidate (TTL 5 min, volatile)organizations.overview.view
S2 EditGET + PATCH /organizations/:idno client cache (form)organizations.edit.save.*
S3 BrandingGET + PATCH /organizations/:id (+ storage upload (planned))no client cacheorganizations.branding.save
S4 SettingsGET :id/settings + PATCH :id/settingsno client cacheorganizations.settings.save
S5 FlagsGET :id/feature-flags + GET /feature-flags + PATCH :id/feature-flags5-min cacheorganizations.flags.toggle.*
S6 MembersGET/POST /rbac/members, users endpoints5-min cacheorganizations.members.invite
S7 TenantsGET /organizations (page/limit/sort/q)paginated cache sl:{module}:{query}organizations.tenants.list.view
S8 Tenant detailGET/PATCH/DELETE /organizations/:idno client cacheorganizations.tenants.delete.confirmed