Ready-to-run single-page web application for recording material inward entries with image uploads, MySQL storage, automatic inward numbers, role-based access, admin search, image viewing, and Excel-friendly export.
SOURCE database.sql;
Or run database.sql from your MySQL client after opening this folder.
npm install
.env from the example and update your MySQL credentials:copy .env.example .env
npm start
http://localhost:3000/register
Admin records:
http://localhost:3000/admin
public/index.html - single-page form and admin pagepublic/styles.css - responsive light theme UIpublic/app.js - validation, previews, submit, admin search, image modalserver.js - Express API, MySQL save/search/export, upload handlingdatabase.sql - MySQL database and material_inward_register tableuploads/ - uploaded PO/invoice and material photos/register - entry form only. Admin records and Excel export are hidden./admin - admin records screen. Register/Admin navigation and Excel export are visible.Admin records show every submitted record by default. Use the Filled By Name search field to filter entries by the staff member who submitted them.
The server automatically adds created_by_role and created_by_name columns to an existing material_inward_register table if they are missing.
POST /api/material-inward - create entry with imagesGET /api/material-inward - admin-only list/search entriesGET /api/material-inward/export - admin-only Excel exportInward numbers are generated per year in this format:
MIR-2026-0001
This application is a Node.js + MySQL app. It cannot be hosted as a static GitHub Pages page because it needs the Express backend, file uploads, and MySQL database.
Example target:
https://material.yourdomain.com/register
https://material.yourdomain.com/admin
Use a VPS, cloud server, cPanel Node.js app, Render/Railway/DigitalOcean, or any host that supports:
uploads/Create a DNS record for your subdomain:
Type: A
Name: material
Value: your-server-public-ip
If your hosting provider gives a hostname instead of an IP, use CNAME:
Type: CNAME
Name: material
Value: your-host-provider-domain
Copy the production env example:
cp .env.production.example .env
Update:
DB_HOST
DB_USER
DB_PASSWORD
DB_NAME
PORT
npm install --omit=dev
mysql -u root -p < database.sql
npm install -g pm2
pm2 start ecosystem.config.cjs
pm2 save
pm2 startup
Use the template:
deploy/nginx-subdomain.conf
Replace:
material.yourdomain.com
with your real subdomain, then reload Nginx.
Use SSL on the subdomain. Camera capture from mobile browsers commonly requires HTTPS unless you are on localhost.
With Certbot/Nginx:
certbot --nginx -d material.yourdomain.com
Security entry screen:
https://material.yourdomain.com/register
Admin records screen:
https://material.yourdomain.com/admin