借书/还书/续借/逾期管理
This commit is contained in:
@@ -302,6 +302,131 @@ readers/form.jsp -> JDBC -> DELETE FROM readers using request parameters
|
||||
readers/form.jsp -> ReaderManagementServlet -> ReaderService -> ReaderDao -> readers.status = inactive
|
||||
```
|
||||
|
||||
## Scenario: Borrowing Circulation Management Slice
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: borrowing circulation now spans `borrow_records`, book inventory,
|
||||
reader eligibility, Servlet routes, service transactions, DAO locks, and JSP
|
||||
management/history screens.
|
||||
- Schema path: `src/main/resources/db/schema.sql`.
|
||||
- JSP paths: `WEB-INF/jsp/borrowing/manage.jsp`,
|
||||
`borrowing/form.jsp`, and `reader/loans.jsp`.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Entity signatures: `BorrowRecord` fields are `id`, `readerId`,
|
||||
`readerIdentifier`, `readerName`, `bookId`, `bookIdentifier`, `bookTitle`,
|
||||
`borrowedAt`, `dueAt`, nullable `returnedAt`, `renewalCount`, `status`,
|
||||
`createdAt`, and `updatedAt`.
|
||||
- Status signature: `BorrowRecordStatus` enum codes are `active` and
|
||||
`returned`; overdue is derived from active, non-returned rows where
|
||||
`due_at < CURRENT_TIMESTAMP`.
|
||||
- Search signature: `BorrowRecordSearchCriteria(readerIdentifier,
|
||||
bookIdentifier, statusCode)` where `statusCode` may be empty, `active`,
|
||||
`returned`, or the derived filter `overdue`.
|
||||
- DAO signatures: `BorrowRecordDao.search(criteria)`,
|
||||
`findByReaderId(readerId)`, `findReaderByUserId(userId)`,
|
||||
`findReaderByIdentifierForUpdate(connection, identifier)`,
|
||||
`findBookByIdentifierForUpdate(connection, identifier)`,
|
||||
`findByIdForUpdate(connection, id)`, `countActiveByReaderId(connection,
|
||||
readerId)`, `create(connection, record)`, `decrementAvailableCopies(...)`,
|
||||
`incrementAvailableCopies(...)`, `markReturned(...)`, and `renew(...)`.
|
||||
- Service signatures: `BorrowingService.searchRecords(actor, criteria)`,
|
||||
`borrowBook(actor, readerIdentifier, bookIdentifier)`,
|
||||
`returnBook(actor, recordId)`, `renewLoan(actor, recordId)`, and
|
||||
`listCurrentReaderHistory(actor)`, all returning `ServiceResult<T>`.
|
||||
- Management routes: `GET /borrowing`, `GET /borrowing/new`,
|
||||
`POST /borrowing/create`, `POST /borrowing/return`, and
|
||||
`POST /borrowing/renew`.
|
||||
- Reader route: `GET /reader/loans`.
|
||||
- Protected permissions: `/borrowing*` requires `MANAGE_BORROWING`;
|
||||
`/reader/loans` requires `BORROW_BOOKS` and the `reader` role because it
|
||||
displays only the signed-in reader's own history.
|
||||
- DB signature: `borrow_records(id, reader_id, book_id, borrowed_at, due_at,
|
||||
returned_at, renewal_count, status, created_at, updated_at)`, with foreign
|
||||
keys to `readers(id)` and `books(id)`, indexes on reader, book, status, and
|
||||
due date, and checks for non-negative renewal count and supported statuses.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Borrow operations require an active reader and a borrowable book with
|
||||
`BookStatus.AVAILABLE` and `available_copies > 0`.
|
||||
- Reader active-loan count is rows with `status = active` and `returned_at IS
|
||||
NULL`; overdue rows still count toward `max_borrow_count`.
|
||||
- Borrowing creates one `borrow_records` row and decrements
|
||||
`books.available_copies` in the same transaction.
|
||||
- Returning an active loan sets `status = returned`, stores `returned_at`, and
|
||||
increments `books.available_copies` with a cap at `total_copies` in the same
|
||||
transaction.
|
||||
- Renewing an active loan extends `due_at`, increments `renewal_count`, and is
|
||||
limited to one renewal per MVP loan.
|
||||
- `JdbcUtil.executeInTransaction` is the local transaction helper for
|
||||
multi-table borrowing workflows. Services decide the workflow boundary; DAOs
|
||||
own SQL and row-lock statements.
|
||||
- Demo `readers` and `books` seed rows must not overwrite existing rows during
|
||||
schema replay, because resetting reader eligibility or `available_copies` can
|
||||
corrupt live borrowing state.
|
||||
- Servlet controllers set JSP attributes such as `criteria`, `statuses`,
|
||||
`overdueStatus`, `maxRenewals`, `borrowRecords`, `formValues`, `errors`,
|
||||
`errorMessage`, and `successMessage`.
|
||||
- JSP pages render JavaBean properties only; they must not call DAOs or embed
|
||||
SQL.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Missing reader ID or book ID -> return to `borrowing/form.jsp` with field
|
||||
errors.
|
||||
- Unknown reader -> field error on `readerIdentifier`.
|
||||
- Inactive or suspended reader -> field error on `readerIdentifier`.
|
||||
- Reader at or above `max_borrow_count` active loans -> field error on
|
||||
`readerIdentifier`.
|
||||
- Unknown book -> field error on `bookIdentifier`.
|
||||
- Unavailable, archived, or zero-copy book -> field error on `bookIdentifier`.
|
||||
- Missing or non-positive record ID for return/renew -> flash error.
|
||||
- Returning or renewing a returned loan -> validation failure on `status`.
|
||||
- Renewing after the renewal limit -> validation failure on `renewalCount`.
|
||||
- DAO/transaction failure -> log server-side details and return
|
||||
`Borrowing service is temporarily unavailable. Please try again later.`
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: a librarian creates a loan for active reader `RD-1000` and available
|
||||
book `BK-1000`; the loan appears in `/borrowing` and book availability is
|
||||
decremented.
|
||||
- Base: `/borrowing?status=overdue` lists active, non-returned loans past due
|
||||
without requiring a scheduler or stored overdue status.
|
||||
- Bad: a Servlet updates `books.available_copies` outside the borrowing
|
||||
transaction or a JSP issues SQL to filter loan records.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Run `BorrowingServiceCheck` assertions for permission denial, inactive
|
||||
readers, unavailable/no-copy books, max active loan count, successful borrow,
|
||||
return inventory restoration, one-renewal limit, overdue search, reader loan
|
||||
history, and DAO failure fallback.
|
||||
- Run `PermissionPolicyCheck` to confirm readers have `BORROW_BOOKS`, readers
|
||||
lack `MANAGE_BORROWING`, and librarians lack reader self-borrow permission.
|
||||
Service or filter checks should also confirm staff use `/borrowing`, not the
|
||||
reader-only `/reader/loans` history route.
|
||||
- Scan JSPs for scriptlets and SQL/JDBC references.
|
||||
- When Maven/Tomcat dependencies are installed, run `mvn clean package` to
|
||||
compile Servlets and package JSP resources.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```text
|
||||
borrowing/manage.jsp -> JDBC -> UPDATE books SET available_copies = ...
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```text
|
||||
borrowing/form.jsp -> BorrowingManagementServlet -> BorrowingService -> BorrowRecordDao -> borrow_records + books in one transaction
|
||||
```
|
||||
|
||||
## Scenario: Login And Permission Scaffold Schema
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{"file": ".trellis/spec/backend/index.md", "reason": "Backend architecture overview for final spec compliance review."}
|
||||
{"file": ".trellis/spec/backend/database-guidelines.md", "reason": "Verify schema, DAO, transaction, and integrity handling for circulation operations."}
|
||||
{"file": ".trellis/spec/backend/error-handling.md", "reason": "Verify user-facing validation failures and exception boundaries."}
|
||||
{"file": ".trellis/spec/backend/logging-guidelines.md", "reason": "Verify logging expectations for key borrowing operations and exceptions."}
|
||||
{"file": ".trellis/spec/backend/quality-guidelines.md", "reason": "Verify backend layer boundaries and code quality."}
|
||||
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend JSP/CSS conventions for final review."}
|
||||
{"file": ".trellis/spec/frontend/component-guidelines.md", "reason": "Verify forms, tables, reusable fragments, and UI consistency."}
|
||||
{"file": ".trellis/spec/frontend/state-management.md", "reason": "Verify request/session/form state and validation message handling."}
|
||||
{"file": ".trellis/spec/frontend/type-safety.md", "reason": "Verify JavaBean display contracts and JSP-safe data access."}
|
||||
{"file": ".trellis/spec/frontend/quality-guidelines.md", "reason": "Verify UI quality and responsive JSP/CSS behavior."}
|
||||
{"file": ".trellis/spec/guides/cross-layer-thinking-guide.md", "reason": "Verify cross-layer data flow from schema through JSP."}
|
||||
{"file": ".trellis/spec/guides/code-reuse-thinking-guide.md", "reason": "Verify reuse of existing patterns and avoid duplicate helper logic."}
|
||||
@@ -0,0 +1,15 @@
|
||||
{"file": ".trellis/spec/backend/index.md", "reason": "Backend architecture overview and pre-development checklist for Servlet -> Service -> DAO -> MySQL work."}
|
||||
{"file": ".trellis/spec/backend/directory-structure.md", "reason": "Required backend package and class placement conventions for new entity, DAO, service, and servlet files."}
|
||||
{"file": ".trellis/spec/backend/database-guidelines.md", "reason": "Required MySQL schema, DAO CRUD, transaction, and data-integrity conventions for borrowing records."}
|
||||
{"file": ".trellis/spec/backend/error-handling.md", "reason": "Required Servlet validation and ServiceResult-style failure handling for borrow/return/renew workflows."}
|
||||
{"file": ".trellis/spec/backend/logging-guidelines.md", "reason": "Guidance for operation logging and exception tracing for circulation actions."}
|
||||
{"file": ".trellis/spec/backend/quality-guidelines.md", "reason": "Layer boundary and review constraints for backend implementation."}
|
||||
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend JSP/CSS conventions and pre-development checklist for new circulation screens."}
|
||||
{"file": ".trellis/spec/frontend/directory-structure.md", "reason": "Required JSP and static asset placement conventions."}
|
||||
{"file": ".trellis/spec/frontend/component-guidelines.md", "reason": "Existing JSP fragments, forms, tables, and reusable UI conventions."}
|
||||
{"file": ".trellis/spec/frontend/state-management.md", "reason": "Server-rendered request/session/form state conventions for validation messages and filters."}
|
||||
{"file": ".trellis/spec/frontend/type-safety.md", "reason": "JSP/Servlet validation and JavaBean display contracts."}
|
||||
{"file": ".trellis/spec/frontend/quality-guidelines.md", "reason": "UI quality checks for JSP/CSS changes."}
|
||||
{"file": ".trellis/spec/guides/cross-layer-thinking-guide.md", "reason": "Borrowing spans schema, DAO, service, servlet, JSP, and permissions."}
|
||||
{"file": ".trellis/spec/guides/code-reuse-thinking-guide.md", "reason": "Feature should reuse existing patterns for search criteria, ServiceResult, DAOs, forms, and JSP tables."}
|
||||
{"file": ".trellis/tasks/archive/2026-04/00-bootstrap-guidelines/research/project-requirements.md", "reason": "Original project requirements include borrowing/return management in the overall library system scope."}
|
||||
@@ -0,0 +1,108 @@
|
||||
# Borrowing circulation management
|
||||
|
||||
## Goal
|
||||
|
||||
Implement the next core library-management slice: borrowing circulation for borrow, return, renew, overdue visibility, and reader loan history.
|
||||
|
||||
## What I already know
|
||||
|
||||
* The project is a Java 11 Maven WAR application using JSP + Servlet on Tomcat and MySQL through JDBC DAO classes.
|
||||
* Existing implemented slices cover login, role/permission checks, dashboard navigation, book catalog/search, book management, and reader profile/eligibility management.
|
||||
* Current routes include `/login`, `/logout`, `/dashboard`, role homes, `/catalog`, `/books`, and `/readers`.
|
||||
* The schema already defines roles, permissions, role permissions, users, system logs, readers, book categories, and books.
|
||||
* Permissions already include `manage_borrowing` and `borrow_books`.
|
||||
* Dashboard copy mentions borrowing, return, renewal, and overdue workflows, but there are no borrowing tables, Servlet routes, JSP pages, DAO classes, services, or tests for that workflow yet.
|
||||
* The user selected borrowing circulation as the next feature slice.
|
||||
* `AuthorizationFilter` currently protects `/librarian/**` with `MANAGE_BORROWING` and `/reader/**` with `VIEW_CATALOG`.
|
||||
* `PermissionPolicy` grants `MANAGE_BORROWING` to administrators and librarians, and `BORROW_BOOKS` to readers.
|
||||
|
||||
## Scope
|
||||
|
||||
* Administrators and librarians can manage circulation records from a borrowing management screen.
|
||||
* Readers can view their own borrowing records from the reader area when their account is linked to a reader profile.
|
||||
* Borrowing workflow covers borrow, return, renew, active loans, returned loans, and overdue loans.
|
||||
* Overdue handling should be visible in lists and service results; no background scheduler is required for this task.
|
||||
* The implementation should preserve the existing Servlet -> Service -> DAO boundary and JSP view style.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Persistence
|
||||
|
||||
* Add a borrowing/loan table to `src/main/resources/db/schema.sql`.
|
||||
* Store the borrowing record id, reader id, book id, borrow date/time, due date/time, optional return date/time, renewal count, status, and timestamps.
|
||||
* Relate borrowing rows to `readers` and `books` with foreign keys.
|
||||
* Add useful indexes for reader, book, status, and due date lookups.
|
||||
* Keep seed data safe and optional; do not require destructive schema resets.
|
||||
|
||||
### Business Rules
|
||||
|
||||
* Borrowing a book requires an active reader.
|
||||
* Borrowing a book requires the book status to allow borrowing and `available_copies > 0`.
|
||||
* Borrowing must reject readers at or above `max_borrow_count` for active, non-returned loans.
|
||||
* Successful borrowing creates a borrowing record and decrements `books.available_copies`.
|
||||
* Returning an active loan marks it returned, records the return time, and increments `books.available_copies` without exceeding `total_copies`.
|
||||
* Renewing an active loan extends the due date and increments the renewal count.
|
||||
* Renewal should be limited to a small, explicit maximum, preferably one renewal per loan for this MVP.
|
||||
* Overdue records are records not returned by their due date. They should be searchable or filterable.
|
||||
* Service methods should return `ServiceResult` style validation errors instead of throwing user-facing exceptions for normal validation failures.
|
||||
|
||||
### Backend
|
||||
|
||||
* Add entity, DAO, JDBC DAO, service, and service implementation classes for borrowing circulation.
|
||||
* Add Servlet routes for borrowing management under an administrator/librarian-accessible path such as `/borrowing`, `/borrowing/new`, `/borrowing/create`, `/borrowing/return`, and `/borrowing/renew`.
|
||||
* Add a reader-facing route for own borrowing records under the existing reader area or another path protected appropriately.
|
||||
* Update `web.xml` and authorization rules as needed.
|
||||
* Keep transaction-sensitive borrow/return/renew operations consistent. If the existing JDBC helper does not provide transactions, implement the smallest safe local transaction pattern needed for multi-table updates.
|
||||
|
||||
### Frontend
|
||||
|
||||
* Add JSP pages for borrowing list/history and the borrow form.
|
||||
* Add navigation entries from dashboard, role home, and header where appropriate.
|
||||
* Keep the UI consistent with existing card, table, form, alert, and button patterns.
|
||||
* Show clear success and validation messages for borrow, return, and renew actions.
|
||||
* Lists should show reader identifier/name, book identifier/title, borrow date, due date, return date when present, renewal count, and status.
|
||||
|
||||
### Tests
|
||||
|
||||
* Add or update service-level check classes for borrowing rules.
|
||||
* Update permission tests if new path/permission logic changes.
|
||||
* Build with Maven after implementation if Maven is available.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
* [ ] Administrator/librarian can open a borrowing management page.
|
||||
* [ ] Administrator/librarian can create a valid borrowing record by selecting or entering an existing active reader and borrowable book.
|
||||
* [ ] Borrowing decrements available copies and blocks unavailable books.
|
||||
* [ ] Borrowing blocks inactive/suspended readers and readers over their max active borrowing count.
|
||||
* [ ] Administrator/librarian can return an active loan; the book copy count is restored.
|
||||
* [ ] Administrator/librarian can renew an active loan within the configured renewal limit.
|
||||
* [ ] Borrowing lists can distinguish active, returned, and overdue records.
|
||||
* [ ] Reader can view their own borrowing records when logged in with a linked reader profile.
|
||||
* [ ] Relevant service checks pass.
|
||||
* [ ] Maven build/check commands pass where available.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
* Tests added/updated where appropriate.
|
||||
* Lint/typecheck/build checks are green.
|
||||
* Docs/notes updated if behavior changes.
|
||||
* Rollback considered if risky.
|
||||
|
||||
## Out of Scope (explicit)
|
||||
|
||||
* Reader self-service borrow requests/reservations are not part of this MVP.
|
||||
* Email/SMS notifications are out of scope.
|
||||
* Fine calculation/payment is out of scope.
|
||||
* Background jobs/schedulers are out of scope.
|
||||
* Full reports/rankings remain out of scope.
|
||||
* No unrelated refactors or visual redesigns.
|
||||
|
||||
## Technical Notes
|
||||
|
||||
* `README.md` confirms implemented scaffold slices and project stack.
|
||||
* `src/main/webapp/WEB-INF/web.xml` defines current Servlet mappings.
|
||||
* `src/main/resources/db/schema.sql` has no borrowing/loan table yet.
|
||||
* `src/main/webapp/WEB-INF/jsp/dashboard.jsp` and `role-home.jsp` already refer to borrowing workflows in UI copy.
|
||||
* `src/main/java/com/mzh/library/entity/Permission.java` already defines `MANAGE_BORROWING` and `BORROW_BOOKS`.
|
||||
* `src/main/java/com/mzh/library/filter/AuthorizationFilter.java` may need a `/borrowing` rule mapped to `MANAGE_BORROWING` and reader borrowing history should not expose other readers' records.
|
||||
* The local `codebase-retrieval` MCP call was rejected by the approval layer, so context was gathered from targeted repo file reads instead.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "continue-development",
|
||||
"name": "continue-development",
|
||||
"title": "brainstorm: 继续开发程序",
|
||||
"description": "",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "Zzzz",
|
||||
"assignee": "Zzzz",
|
||||
"createdAt": "2026-04-27",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "master",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user