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.
States = idle / loading / success / empty / error(offline, rate, invalid) / disabled / permission.
Analytics events follow {module}.{screen}.{action} (proposed; SDK open — 00-shared/10 §8 ).
Field Detail
Purpose Browse and search the book catalog with live availability
Entry library tab/home; after create/edit/issue/return (refresh on focus)
Exit → book detail (row); → book form (FAB)
Source GET /api/v1/books?page&limit&q (library.controller.ts:33-41) — server regex on title/author/ISBN (book.repository.ts:26-30)
Widgets AppSearchBar (debounced q), AppListTile/AppCard per book (title, author, availability badge $available/$total), AppFAB "Add book", AppSkeleton, AppEmptyState ("No books match…"), AppPagination (infinite scroll)
Filters client-side chips only: category, status, availability (OQ-5)
Permissions read requires books.read (enforcement (planned)); FAB hidden without books.create
States loading, empty, error(offline/5xx/429), idle; permission state (hidden FAB)
Analytics library.catalog.search, library.catalog.open_book (proposed)
Realtime re-fetch on focus; WS (planned)
Field Detail
Purpose Full metadata, availability, and entry point to issue/edit
Source GET /api/v1/books/:id (library.controller.ts:43-47) → 404 RESOURCE_NOT_FOUND (library.service.ts:80)
Widgets AppCard header (title, author, ISBN), metadata rows (publisher, category, edition, shelfLocation, description), AppBadge status + $available/$total copies, action buttons
Actions Issue (enabled iff availableCopies >= 1, books.issue), Edit (books.update), Delete (books.delete, confirm dialog)
States loading skeleton, 404 → AppEmptyState + back, permission-based action hiding
Analytics library.book.open, library.book.issue_start (proposed)
Field Detail
Purpose Add a book (FAB) or edit metadata/copies
Source create: POST /api/v1/books (library.controller.ts:27-31); edit: PATCH /api/v1/books/:id (library.controller.ts:49-53)
Form title*, author*, isbn*, publisher?, category?, edition?, totalCopies?, shelfLocation?, description? (create-book.dto.ts:5-46; update = same fields optional, update-book.dto.ts:4)
Errors 409 duplicate ISBN inline (library.service.ts:37-39); 400 field errors; 404 on edit
Permissions books.create / books.update
Analytics library.book.create, library.book.update (proposed)
Field Detail
Purpose Lend a copy to a student with an explicit due date
Source POST /api/v1/books/issue (library.controller.ts:61-65)
Form student (picker from Students module), dueDate* (date picker, must be future), notes? (issue-book.dto.ts:5-20)
Conflicts 409 no copies (library.service.ts:109-111), 409 max 5 active (library.service.ts:116-120) → banners + refresh
Permissions books.issue
Side effect BookIssued event (library.service.ts:141-148)
Analytics library.issue.submit (proposed)
Field Detail
Purpose A student's current loans and full history (staff use for lookups too)
Source active: 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)
Widgets two tabs; per record AppCard: book title (populated bookId), borrowedAt, dueDate (prominent), returnedAt, fine chip
Derived overdue badge + fine preview when active && now > dueDate (OQ-2)
Permissions books.read; studentId from profile (OQ-9)
Analytics library.myborrows.open (proposed)
Field Detail
Purpose Close an ACTIVE borrow; compute or override the fine
Source POST /api/v1/books/return (library.controller.ts:67-71)
Form fineAmount? (prefilled with server-rule preview ceil(days) × 5, editable by staff), notes? (return-book.dto.ts:5-18)
Conflicts 409 "Book was not actively borrowed." (library.service.ts:155-157) → refresh
Permissions books.return
Side effect BookReturned event with fineAmount (library.service.ts:180-191)
Analytics library.return.submit, library.fine.pay (proposed)
Field Detail
Purpose Staff sweep of late loans
Source client-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)
Widgets list of overdue cards: student, book, days late, fine preview, "Return" shortcut
Permissions staff (books.issue/books.return)
Note This screen is honest about its data: shows "(derived — server scan planned)"
Analytics library.overdue.open (proposed)
Field Detail
Purpose Mark a fine paid
Source POST /api/v1/books/fines/:borrowRecordId/pay (library.controller.ts:85-89) → fineStatus: PAID (library.service.ts:203-209)
Widgets confirm AppDialog showing fineAmount → snackbar success
Permissions fines.pay
Note server does not guard state (OQ-6) — client only shows the button on fineStatus == pending records
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 .
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).
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.