Step 1 of 2
The request
Finish and verify neighbourhood library lending app
Read the full request
Continue this project. The workspace already holds the application from earlier runs of this same goal: server.js, test/library.test.js, package.json, the UI under public/ and README.md. Its UI was validated in a browser and its README written; the last run was refused only because the API rules and the test suite were not verified again in that run. Keep what works, fix anything that fails, and verify everything below. Build a library lending web application for a fictional neighbourhood library, as a Node.js 24 project with no npm dependencies (Node built-in modules only). Server: server.js starts an HTTP server on the port given by the PORT environment variable (default 3000). It serves a JSON API under /api and a static single-page UI from public/. Data lives in one JSON file (path from the DATA_FILE environment variable, default data/library.json), always written atomically (temporary file, then rename). When the file does not exist, the server creates it with a seeded catalogue of 6 books and 3 members. Domain rules: - A book has id, title, author and copies (total owned). A member has id, name and type: standard (at most 3 active loans) or premium (at most 5). - Every request may carry an X-Today: YYYY-MM-DD header that replaces the server's current date for that request, so tests and demonstrations are deterministic. Without it the server uses today's UTC date. - POST /api/loans with {bookId, memberId} creates a loan due 14 days after its start date and answers 201. It is refused with 409 when no copy is free for that member, when the member already has their maximum of active loans, or when the member owes more than 5.00 in unpaid fines; with 404 when the book or member does not exist; with 400 when the body is malformed. - POST /api/loans/:id/return closes an active loan. A return after the due date adds a fine of 0.25 per late day, capped at 10.00 per loan. - POST /api/loans/:id/renew moves the due date 14 days later. A loan can be renewed at most twice, and never while another member has a hold on that book (both refused with 409). - POST /api/holds with {bookId, memberId} queues a hold only when no copy is available (409 otherwise) and answers 201. When a copy comes back, it is reserved for the oldest hold on that book: nobody else can borrow it, and that member's next loan of the book consumes the hold. - POST /api/members/:id/payments with {amount} records a payment against unpaid fines. - GET /api/books lists every book with its available copies. GET /api/members lists members. GET /api/members/:id shows the member's active loans with due dates, their holds and the fines they owe. - Amounts are exact to the cent (no floating-point drift). UI (public/index.html, public/app.js, public/styles.css): a catalogue table with availability, a member selector, buttons to borrow, return, renew and place a hold, the selected member's loans with due dates, holds and fines owed, and a visible message whenever the server refuses an action. It must be usable with the keyboard alone and on a 390-pixel-wide phone screen. Tests: npm test runs node:test suites that start from a temporary data file and cover every rule above, including loan limits, fines and their cap, the fine threshold, renewal limits, hold ordering and reservation, payments and the date override. They all pass. README.md explains how to install, run and test the application, documents every API route with an example request and response, and states the business rules.
The journey
- Read the requestTurned it into a list of things it would have to prove before calling the work done.
- Did the workPlanned the pieces, built them and checked the result as it went.
- Delivered8 files handed over.
The result
- data/library.json1.0 KB
- package.json146 B
- public/app.js4.4 KB
- public/index.html1.3 KB
- public/styles.css2.5 KB
- README.md6.8 KB
- server.js5.9 KB
- test/library.test.js7.1 KB