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

06 - Screen Specifications (Houses Module)

Full per-screen specification: layout, states, widgets, data binding, interactions, permissions, a11y and motion. Authoritative patterns in 00-shared/03 (Component Library), 00-shared/08 (Interaction & Motion), 00-shared/09 (Accessibility Baseline). Widgets marked App* come from 00-shared/03; module widgets from 07_Component_Library.md.


1. House List Screen (/houses)

1.1 Layout (phone)

AppBar: "Houses"                        [houses.read]
 └─ (right) overflow menu? no - empty state only
HouseColorCard grid (2 columns)         # HouseColorCard, 07 §1
  [color swatch][Name            ]
  [code chip · motto 1-line]
FAB: "New house"                        [houses.create]

Tablet/desktop: 3-column grid, max content width 960 dp, master-detail optional.

1.2 Data binding

ElementSourceMapping
ListGET /houses?page=1&limit=20data: House[], metaHouseListCubit (13 §2)
CardHouse.name, code, color, mottohouse.schema.ts:9-19
Paginationmeta.totalItems/totalPages/hasNext/hasPreviouspagination-query.dto.ts:32-39

No server sort (houses.service.ts:30 finds with {}); client renders createdAt asc (creation order). q/sort query params exist in PaginationQueryDto (pagination-query.dto.ts:21-29) but the houses list ignores them - no search box.

1.3 States

StateRenderTrigger
Initialskeletons x4mount
Loadingskeletons (page>1: footer spinner)page change, pull-to-refresh
Successgrid + footer200 envelope
EmptyAppEmptyState "No houses yet. Create your first house."data.length == 0
ErrorAppOfflineBanner + retry button; stale grid keptnetwork 401/500/offline
Permissionempty + "contact admin" copy (no FAB)no houses.read/houses.create

1.4 Interactions

  • Tap card → /houses/:id (push).
  • FAB → editor sheet (create mode, 05 §3).
  • Pull-to-refresh → refetch page 1.
  • Card menu (ellipsis, admin): Edit → editor (update mode); Delete → confirm dialog (14 §4 warning about members).

1.5 Motion & a11y

  • Card appear: stagger m-fast fade-up (≤4 rows) per 00-shared/08.
  • Color cards: color must never be the only differentiator - name text always present (WCAG AA contrast for swatch badges, 00-shared/09).
  • Skeleton < 200 ms perceived; content < 2 s on network (00-shared/10 §1).

2. House Detail Screen (/houses/:id)

2.1 Layout

[ HouseHeader: full-width color banner (house.color → token, 11 §3) ]
  Name (displayLarge)   code chip   [houses.update: menu ▾ Edit/Delete]
  Motto (italic, muted)                      
[ Members section ]
  header: "Members" · count badge · refresh icon
  MemberTile list (AppAvatar initials, admissionNumber, class label*)
  *(class label not in student list payload today - omit, `(planned)`)
[ Meta section (admin) ]
  created · updated · version (small, muted)

2.2 Data binding

SectionSource
IdentityGET /houses/:idHouseDocument (houses.service.ts:36-40; 404 House not found. :38)
MembersClient join (planned): GET /students?page&limit (student.controller.ts:41-43) then filter houseId == id client-side. Server filter / members endpoint (planned) (09 §G1)
Metabase.schema.ts:13-34 (createdAt, updatedAt, version)

2.3 States

SectionStateRender
HeaderLoading / 404 / Successskeletons / "House not found" + pop / banner
MembersLoading / Empty / Loaded / Error3 skeleton tiles / "No members yet" / count + tiles / inline retry
MembersUnverified countif joined client-side, show ~ prefix + tooltip "server-side member count planned"
WholeOfflinebanner; detail cached from list when available (13 §6)

2.4 Interactions

  • Edit → editor sheet prefilled (update mode).
  • Delete → AppDialog confirm; on confirm: warning list (member count), then DELETE /houses/:id (houses.service.ts:51-54). No 409 expected - backend has no dependency guard; client warns pre-emptively (14 §4).
  • Member tap → student detail (cross-module navigation via /students/:id).
  • Pull-to-refresh → refetch house + members.

2.5 a11y & motion

  • Banner color: name/motto must pass contrast over arbitrary color - compute on tokenization (11 §3), fall back to dark scrim.
  • Delete dialog: destructive button styled error; focus trapped (00-shared/09).
  • Section transitions m-base fade; no parallax on color banner (motion budget).

3. House Editor (bottom sheet / dialog)

3.1 Layout (create mode)

Sheet header: "New House"                    [houses.create]
Form:                                        (08_Form_Specifications.md)
  Name        AppTextField (required)
  Code        AppTextField (required, uppercase hint, conflict inline)
  Color       ColorPickerField (preset swatches + custom hex)
  Motto       AppTextField (optional, multiline 1-2)
Actions: [Cancel] [Create house] (filled, fullWidth)

Update mode: title "Edit House", button "Save changes", fields prefilled.

3.2 Data binding

FieldDTORule (source)
nameCreateHouseDto.namerequired IsString (create-house.dto.ts:5-7); trimmed server-side (house.schema.ts:9-10)
codeCreateHouseDto.coderequired IsString (create-house.dto.ts:9-11); trimmed (house.schema.ts:12-13); unique per tenant (house.schema.ts:23)
colorCreateHouseDto.coloroptional IsOptional IsString (create-house.dto.ts:13-16; house.schema.ts:15-16)
mottoCreateHouseDto.mottooptional IsOptional IsString (create-house.dto.ts:18-21; house.schema.ts:18-19)

Create → POST /houses (houses.controller.ts:24-28); Update → PATCH /houses/:id (houses.controller.ts:42-46). PATCH sends the full DTO (name+code required in body even for edits) - see 03 J1 step 5, 08 §4.

3.3 States

StateRender
Idleform enabled, button enabled
Submittingbutton spinner, fields disabled (single-flight)
Conflict (409)inline error under code field, verbatim House code "X" already exists. (houses.service.ts:19-21); focus field
Update 404snackbar "House not found" + pop sheet; list refetches
Offlineform blocked, AppOfflineBanner (00-shared/10 §2)

3.4 Interactions

  • Enter submits (name+code filled).
  • Code field: suggest uppercase normalization; do not enforce - server trims only.
  • Cancel with dirty form → discard confirm dialog (motion m-fast).
  • Color picker: 8 preset swatches (design tokens 11 §3) + custom hex with contrast hint against white text.

3.5 Motion & a11y

  • Sheet slide-up m-base; field errors shake m-fast (00-shared/08).
  • Labels linked to fields; error messages in live regions (00-shared/09).
  • Custom hex input validates #RRGGBB; invalid → field error, not block.

4. Student-side house picker (cross-module, reused by Students forms)

Not a houses screen - the field contract it depends on:

  • optional houseId (IsMongoId) on create-student.dto.ts:39-42 and update-student.dto.ts:45-48.
  • Picker options from GET /houses (house list cubit cache, 13 §6).
  • "None" option to clear a house (send empty/omit houseId).

5. Permissions summary per screen

ScreenReadCreateUpdateDelete
House listhouses.readhouses.create (FAB)-houses.delete (menu)
House detailhouses.read-houses.update (menu)houses.delete (menu)
House editor-houses.createhouses.update-

Source: permissions.constants.ts:46-49. Server RBAC not wired yet (AGENTS.md - "Auth (JWT/RBAC guards) ... not yet implemented") - client gating only.