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 (Library Module)

Every screen of the Library module, its intent, route, composition, states, permissions, platform behavior and events. Authoritative components in 00-shared/03; this file enumerates which ones each screen uses with module specifics.


Legend

States = idle / loading / success / empty / error(offline, rate, invalid) / disabled / permission. Analytics events follow {module}.{screen}.{action} (proposed; SDK open — 00-shared/10 §8).


1. Catalog List + Search (/library)

FieldDetail
PurposeBrowse and search the book catalog with live availability
Entrylibrary tab/home; after create/edit/issue/return (refresh on focus)
Exit→ book detail (row); → book form (FAB)
SourceGET /api/v1/books?page&limit&q (library.controller.ts:33-41) — server regex on title/author/ISBN (book.repository.ts:26-30)
WidgetsAppSearchBar (debounced q), AppListTile/AppCard per book (title, author, availability badge $available/$total), AppFAB "Add book", AppSkeleton, AppEmptyState ("No books match…"), AppPagination (infinite scroll)
Filtersclient-side chips only: category, status, availability (OQ-5)
Permissionsread requires books.read (enforcement (planned)); FAB hidden without books.create
Statesloading, empty, error(offline/5xx/429), idle; permission state (hidden FAB)
Analyticslibrary.catalog.search, library.catalog.open_book (proposed)
Realtimere-fetch on focus; WS (planned)

2. Book Detail (/library/books/:id)

FieldDetail
PurposeFull metadata, availability, and entry point to issue/edit
SourceGET /api/v1/books/:id (library.controller.ts:43-47) → 404 RESOURCE_NOT_FOUND (library.service.ts:80)
WidgetsAppCard header (title, author, ISBN), metadata rows (publisher, category, edition, shelfLocation, description), AppBadge status + $available/$total copies, action buttons
ActionsIssue (enabled iff availableCopies >= 1, books.issue), Edit (books.update), Delete (books.delete, confirm dialog)
Statesloading skeleton, 404 → AppEmptyState + back, permission-based action hiding
Analyticslibrary.book.open, library.book.issue_start (proposed)

3. Book Form — create (/library/books/new) & edit (/library/books/:id/edit)

FieldDetail
PurposeAdd a book (FAB) or edit metadata/copies
Sourcecreate: POST /api/v1/books (library.controller.ts:27-31); edit: PATCH /api/v1/books/:id (library.controller.ts:49-53)
Formtitle*, author*, isbn*, publisher?, category?, edition?, totalCopies?, shelfLocation?, description? (create-book.dto.ts:5-46; update = same fields optional, update-book.dto.ts:4)
Errors409 duplicate ISBN inline (library.service.ts:37-39); 400 field errors; 404 on edit
Permissionsbooks.create / books.update
Analyticslibrary.book.create, library.book.update (proposed)

4. Issue Form (/library/books/:id/issue — sheet on mobile)

FieldDetail
PurposeLend a copy to a student with an explicit due date
SourcePOST /api/v1/books/issue (library.controller.ts:61-65)
Formstudent (picker from Students module), dueDate* (date picker, must be future), notes? (issue-book.dto.ts:5-20)
Conflicts409 no copies (library.service.ts:109-111), 409 max 5 active (library.service.ts:116-120) → banners + refresh
Permissionsbooks.issue
Side effectBookIssued event (library.service.ts:141-148)
Analyticslibrary.issue.submit (proposed)

5. Borrowed-by-Me — Active & History (/library/my-borrows)

FieldDetail
PurposeA student's current loans and full history (staff use for lookups too)
Sourceactive: GET /api/v1/books/borrows/:studentId/active (library.controller.ts:79-83); history: GET /api/v1/books/borrows/:studentId (library.controller.ts:73-77, sorted borrowedAt desc, library.service.ts:196)
Widgetstwo tabs; per record AppCard: book title (populated bookId), borrowedAt, dueDate (prominent), returnedAt, fine chip
Derivedoverdue badge + fine preview when active && now > dueDate (OQ-2)
Permissionsbooks.read; studentId from profile (OQ-9)
Analyticslibrary.myborrows.open (proposed)

6. Return Form (/library/my-borrows/return/:recordId — sheet)

FieldDetail
PurposeClose an ACTIVE borrow; compute or override the fine
SourcePOST /api/v1/books/return (library.controller.ts:67-71)
FormfineAmount? (prefilled with server-rule preview ceil(days) × 5, editable by staff), notes? (return-book.dto.ts:5-18)
Conflicts409 "Book was not actively borrowed." (library.service.ts:155-157) → refresh
Permissionsbooks.return
Side effectBookReturned event with fineAmount (library.service.ts:180-191)
Analyticslibrary.return.submit, library.fine.pay (proposed)

7. Overdue View (/library/overdue)

FieldDetail
PurposeStaff sweep of late loans
Sourceclient-derived today: from Borrowed-by-Me / per-student active lists, filter now > dueDate; server findOverdue() exists unused (borrow-record.repository.ts:34-43); dedicated endpoint + scan (planned) (IMPLEMENTATION_PLAN.md:228)
Widgetslist of overdue cards: student, book, days late, fine preview, "Return" shortcut
Permissionsstaff (books.issue/books.return)
NoteThis screen is honest about its data: shows "(derived — server scan planned)"
Analyticslibrary.overdue.open (proposed)

8. Fine Pay (inline on any borrow record with fineStatus=pending)

FieldDetail
PurposeMark a fine paid
SourcePOST /api/v1/books/fines/:borrowRecordId/pay (library.controller.ts:85-89) → fineStatus: PAID (library.service.ts:203-209)
Widgetsconfirm AppDialog showing fineAmount → snackbar success
Permissionsfines.pay
Noteserver does not guard state (OQ-6) — client only shows the button on fineStatus == pending records

Shared components used

AppTextField, AppButton, AppSnackbar, AppCard, AppListTile, AppBottomSheet, AppDialog, AppMenu, AppSkeleton, AppEmptyState, AppOfflineBanner, AppFAB, AppBadge, AppChips, AppSearchBar, AppAvatar, AppDateField, AppPicker. Module-specific: availabilityBadge, fineChip, overdueTag, copyStepper — defined in 07_Component_Library.md.

Analytics events (proposed)

library.catalog.{search,open_book}, library.book.{create,update,delete,issue_start}, library.issue.{submit,conflict}, library.return.{submit,conflict}, library.fine.{pay,pay_conflict}, library.myborrows.open, library.overdue.open (all proposed).

Keyboard, landscape, tablet, desktop

  • Forms are sheets on phone, centered dialogs on tablet/desktop (≤ 480 dp, 00-shared/03).
  • Catalog List: phone single column; tablet/desktop two-column list/detail master-detail.
  • Date fields use AppDateField (native picker); no manual date typing.