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

01 — Product Overview (Library Module)

StudyLyon — multi-tenant ERP / School Management API. This package designs the Library module client (Flutter, forward-looking spec) against the implemented NestJS backend. All endpoints, DTO fields, schemas, domain events, permissions, and wire contracts are derived directly from src/modules/library/**, src/modules/rbac/permissions.constants.ts, and docs/IMPLEMENTATION_PLAN.md. No feature is invented — anything not present in source is flagged (planned) / (proposed) / (forward-looking) in Assumptions & Open Questions.

Heads-up: per the PRD, the mobile client is out of Phase 1; this package is the forward-looking spec the client will be built against later. Everything below is best-effort UI design on top of the current backend surface.

Blueprint note: studylyon-blueprint/04-Modules/ has no dedicated Library doc; the module is only sketched as "Books / Issue / Return / Fines" responsibilities (MODULE_ARCHITECTURE.md:546-557) and appears in the fee-category list (COLLECTIONS.md:2247). The code is the source of truth.


1. Purpose

Library manages the school's physical book collection and the borrow lifecycle:

  • Catalog: books with title/author/ISBN, optional publisher/category/edition, copy counts (totalCopies/availableCopies), and a status (available|borrowed|damaged|lost).
  • Issue/return: staff hand a copy to a student with an explicit due date; returning closes the record, restores availability, and computes a fine when late.
  • Fines: computed server-side at return time at a fixed daily rate, tracked as fineStatus (pending|paid|waived), payable via a dedicated endpoint.
  • Borrow visibility: full history and active-borrow lists per student.
ResponsibilitySource
Book CRUD (create/list/search/get/patch/soft-delete)library.controller.ts:27-59, library.service.ts:34-105
Unique ISBN per tenant (409 on duplicate)library.service.ts:35-40, book.schema.ts:51
Issue book (availability + 5-book cap, decrement copies)library.service.ts:107-150
Return book (restore copies, compute fine, BookReturned event)library.service.ts:152-193
Borrow history / active borrows per studentlibrary.service.ts:195-201, borrow-record.repository.ts:21-43
Pay finelibrary.service.ts:203-209
Daily fine rate = 5 units/day (hardcoded)library.service.ts:25,211-217
Permissions vocabulary (books.read/create/update/delete/issue/return, fines.pay)permissions.constants.ts:55-61
Tenant scoping + soft-delete on every queryBaseRepository (base.repository.ts), all repos extend it

2. Business goals

GoalMeasure
No duplicate booksunique index {tenantId, isbn} (book.schema.ts:51) + service 409 (library.service.ts:37-39)
Never over-issueavailableCopies >= 1 checked before decrement (library.service.ts:109-111)
Never exceed student limitmax 5 active borrows enforced (library.service.ts:116-120)
Fines always computablefineAmount = overdueDays × 5 at return (library.service.ts:211-217)
No orphaned deletesbook with active borrows cannot be deleted — 409 (library.service.ts:97-102)
Cross-tenant isolationevery query tenant-scoped via BaseRepository.scopedFilter
Audit trailBookIssued / BookReturned domain events on the event bus (library.service.ts:141-148,180-191)

3. User goals

  • Librarian / staff: search the catalog; add, edit, delete books; issue and return copies; see overdue borrowers; collect fine payments.
  • Student: browse/search the catalog; see which books are currently on loan to them and their history; know what's overdue.
  • Parent: (read-only, via student) see the child's active loans and any fine.
  • Org admin: catalog oversight, permission assignment (who may issue/return), configuration of limits (planned).

4. Stakeholders

Librarian/staff with books.* permissions, org admin (RBAC), students, parents, the RBAC module (permissions.constants.ts), events/notifications pipeline, QA + design + engineering.

5. Why this exists

A school library without tracking loses books and revenue. The backend enforces the hard invariants (ISBN uniqueness, availability, 5-book cap, tenant isolation, soft delete). The client's job is to present the catalog and loan state authoritatively, never guess server state, and treat every write (create, issue, return, fine pay) as server-confirmed.

6. Dependencies

DependencyRoleSource
Students modulestudentId on borrow records (ref: 'Student')borrow-record.schema.ts:25-26
Users moduleissuedBy actor (ref: 'User', currently never written)borrow-record.schema.ts:28-29
Event busBookIssued, BookReturned eventslibrary.service.ts:141-148,180-191
Files modulecover/attachment upload surface (not wired to books yet)files.controller.ts:29-71
RBACbooks.*, fines.pay permissions (enforced later (planned))permissions.constants.ts:55-61

7. Success metrics

  • Catalog search (title/author/ISBN) round-trip < 2 s (regex search, indexed title/author).
  • Duplicate-ISBN attempt handled as 409 100% of the time.
  • Issue of an exhausted book always blocked (409), even under concurrent requests (see QA-1 in 14_QA_Checklist.md — read-then-write race today).
  • Fine amount at return always equals ceil(daysOverdue) × 5 unless staff overrides.
  • Zero cross-tenant leaks (BaseRepository scope).

8. Edge cases (contract level)

  • Duplicate ISBN → 409 DUPLICATE_RESOURCE "Book with ISBN "..." already exists." (library.service.ts:37-39).
  • No copies available → 409 "No copies available for borrowing." (library.service.ts:109-111).
  • Student at 5 active loans → 409 "Student already has maximum number of borrowed books." (library.service.ts:116-120).
  • Delete book with active loans → 409 "Cannot delete book with active borrow records." (library.service.ts:99-101); delete is a soft delete (book.repository.ts via BaseRepository.softDelete, library.service.ts:103).
  • Return a non-active record → 409 "Book was not actively borrowed." (library.service.ts:155-157).
  • Unknown book/record → 404 RESOURCE_NOT_FOUND (library.service.ts:80,92,103,154,170,207).
  • Invalid Mongo idCastError → 400 VALIDATION_ERROR "Invalid resource identifier." (http-exception.filter.ts).
  • Copy-count edits adjust availableCopies by the same delta, floored at 0 (library.service.ts:87-90).
  • Staff override fine — return DTO may set fineAmount explicitly (return-book.dto.ts:9-13); server uses dto.fineAmount ?? calculateFine(dueDate) (library.service.ts:159).
  • fineStatus on time — records with fineAmount = 0 keep fineStatus: undefined (library.service.ts:166); WAIVED is never produced by any endpoint.

9. Assumptions (module)

  • PRD: mobile client out of Phase 1 — forward-looking spec; backend remains the contracts authority.
  • Endpoints are guarded only by JwtAuthGuard (library.controller.ts:22) — no @Permissions() metadata anywhere; books.read/create/update/delete/issue/return and fines.pay exist in ALL_PERMISSIONS (permissions.constants.ts:55-61) but are not enforced. Real RBAC is (planned) (OQ-1).
  • Overdue is not computed by the server. BorrowStatus.OVERDUE and repository findOverdue() exist (borrow-record.schema.ts:9-11, borrow-record.repository.ts:34-43) but no service endpoint/worker sets it. Overdue detection is client-derived today; a scheduled scan is (planned) (IMPLEMENTATION_PLAN.md:228) (OQ-2).
  • issuedBy is never populated — the schema has the field (borrow-record.schema.ts:28-29) but issueBook doesn't set it (library.service.ts:132-139) (OQ-3).
  • Fines are units (plain Number, library.service.ts:25 rate = 5); no currency/format contract server-side.
  • BookStatus.DAMAGED/LOST and BorrowStatus.LOST exist in enums but no endpoint transitions to them — damage/loss workflow (planned) (OQ-4).
  • No pagination on borrow endpoints (library.service.ts:195-201) — client paging (proposed).
  • Search covers title/author/ISBN only (book.repository.ts:26-30); category/ publisher/status filters must be client-side (OQ-5).
  • Catalog import/export is (planned) (IMPLEMENTATION_PLAN.md:172,228); QR/barcode scanning is (forward-looking); analytics (proposed).

10. Open questions (module-grain; global ledger in 00-shared/12)

#ItemImpact
OQ-1No RBAC decorators on library endpoints; perms exist but unenforcedRole-gated UI waits for guard wiring
OQ-2No overdue worker — OVERDUE status and findOverdue() unusedOverdue badge derived client-side; server scan (planned)
OQ-3issuedBy never written on issue"Issued by" attribution unavailable
OQ-4No damage/lost transitions, no renew/reserve endpointsThose workflows (planned)
OQ-5Server search limited to title/author/ISBN; no status/category filtersClient-side filter only
OQ-6payFine doesn't guard status — can pay a fine on a still-active loan, or twice (idempotent overwrite)Pay button gating is client responsibility
OQ-7Issue is read-then-write (availableCopies) — no atomic conditional updateConcurrent double-issue race (QA-1)
OQ-8No book-cover field on Book; files module exists separatelyCover upload (proposed)
OQ-9No me borrows endpoint — student view needs studentId from profileGET /books/borrows/:studentId/active requires profile lookup

11. Glossary (this module)

TermMeaning
Bookbooks doc: title, author, isbn, publisher?, category?, edition?, totalCopies, availableCopies, status `available
Borrow recordborrow_records doc: bookId, studentId, issuedBy?, borrowedAt, dueDate, returnedAt?, status `active
Issuestaff lends a copy: decrement availability, create ACTIVE record with due date
Returnclose an ACTIVE record: restore availability, set RETURNED + returnedAt, compute fine
FineoverdueDays × 5 units (library.service.ts:25,211-217), status `pending
Envelope{success, message, data, meta?, timestamp, requestId} (response-envelope.interceptor.ts:44-52)