A server-rendered inventory app for computer parts. Visitors can browse the catalogue; signed-in users can add new parts and edit existing ones. Built with Express and EJS, with session-based authentication.
For visitors
- Browse a table of parts pulled from a remote API, with image, description, stock level and price
- Parts with zero quantity are shown as No Stock rather than a bare zero
For signed-in users
- Add a new part, with validation on required fields, quantity, and duplicate product names
- Edit any existing part, with the form pre-filled from the selected item
- Refresh the catalogue to re-fetch the current data from the remote API
Accounts
- Sign up with a username and password, rejected if the username is taken
- Log in and out, with the session driving what the navigation bar shows
Both the user list and the parts catalogue are read into memory when the server boots — users from users.json, parts from the remote API — and stored on global. Routes read from those collections rather than hitting the disk or the network on every request. Signing up appends to the in-memory array and writes back to disk, so a new account survives a restart.
A single requireLogin function checks the session and redirects to the login page if it is missing. It is applied to the add and edit routes, so authorisation is declared where the route is defined rather than repeated inside each handler. The parts table itself is deliberately public.
Each write path checks required fields, validates the quantity, and blocks duplicate product names before touching the collection. On failure the form re-renders with an error message and the user's input intact, rather than redirecting and losing what they typed.
The duplicate check on edit excludes the part being edited, so an item can be saved without renaming it — comparing on name alone would have made every edit fail.
EJS templates with shared partials for the head, navigation bar, and scripts. For an app whose pages are mostly a table and two forms, rendering on the server keeps the whole request cycle in one place, with no client-side state to keep in sync.
- Node.js with Express
- EJS templating
- express-session for authentication state
- axios for the remote API
- Bootstrap 5 and Bootstrap Icons
- Node.js
npm install
npm startThe app runs at http://localhost:3000.
Parts are fetched from the remote API on startup. The console logs how many were loaded, or reports the failure and starts with an empty catalogue if the API is unreachable.
users.json ships with seed accounts for trying the app:
| Username | Password |
|---|---|
| Admin | Admin1 |
| marcus1 | marcus123 |
You can also create your own account through the sign-up form.
| Method | Route | Description | Login required |
|---|---|---|---|
| GET | / | Home page | No |
| GET | /login | Login form | No |
| POST | /login | Authenticate and start a session | No |
| GET | /logout | Destroy the session | No |
| GET | /signup | Registration form | No |
| POST | /signup | Create an account | No |
| GET | /parts | Parts table | No |
| GET | /parts/refresh | Re-fetch parts from the remote API | No |
| GET | /part | Add-part form | Yes |
| POST | /part/add | Create a part | Yes |
| GET | /part/edit/:id | Edit form for one part | Yes |
| POST | /part/edit | Save changes to a part | Yes |
Passwords are stored in plain text. users.json holds raw passwords, so anyone with read access to the file has every account. Hashing with bcrypt on sign-up and comparing hashes on login is the correct approach and would be the first change I'd make.
The session secret is hard-coded. It sits in app.js rather than coming from an environment variable, so it is visible to anyone reading the source.
Parts exist only in memory. Added and edited parts live on the global collection and are lost when the server restarts or when Refresh replaces the collection with fresh remote data. This matches how the assignment was specified, but a real inventory would need to persist changes.
No role separation. users.json carries a role field, but the middleware only checks that someone is logged in. Any account can add and edit parts.
Built as a course assignment for Noroff back-end development. The remote API is supplied by the course, so the catalogue depends on that service being available.