This page documents the constraints inherent to the current architecture and the recommended direction for evolving the system into a production-grade application. The items below are drawn directly from the developer handover notes in the repository and from an audit of the source code inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/raceliciouss/YUSEN-LIMO-WAREHOUSE/llms.txt
Use this file to discover all available pages before exploring further.
assets/auth.js and assets/app.js.
Known Limitations
LocalStorage instead of a database
LocalStorage instead of a database
All persistent data — user accounts (
warehouseAuthAccounts), sessions (warehouseAuthSession), shipments (warehouseShipments), profiles (warehouseProfile, warehouseProfilePictures), and notifications (warehouseNotificationState) — is stored in the browser’s LocalStorage.This introduces several hard constraints:- Size limit — Browsers typically cap LocalStorage at 5–10 MB per origin. Warehouses processing high shipment volumes will hit this limit, after which
persistAccounts()andsaveStoredShipments()will fail silently (thecatchblocks inauth.jslog a warning but do not surface errors to the user). - No transactions — Concurrent writes from multiple tabs can clobber each other. There is no locking or conflict resolution.
- No backup — Clearing browser data or switching browsers wipes all operational history. There is no export-on-clear safeguard.
- Single-device — Each browser instance has its own isolated LocalStorage. Two users on different machines see completely independent datasets.
Client-side plaintext passwords
Client-side plaintext passwords
Passwords are stored as plaintext strings in the
warehouseAuthAccounts LocalStorage key. Anyone with access to the machine can open DevTools → Application → Local Storage and read every credential in the system.The default seed password (Admin@123) and the password-reset default (Password123, defined as the DEFAULT_PASSWORD constant in auth.js) are hardcoded in the source. changePassword() and resetPassword() write the new values back to LocalStorage in the same plaintext format — no hashing is applied at any point.Client-side-only authentication
Client-side-only authentication
AuthService runs entirely in the browser. Role checks — currentUser.role !== 'admin' guards at the top of createUser(), updateUser(), deleteUser(), resetPassword(), and toggleUserStatus() — are enforced only inside the JavaScript running on the user’s own machine.A user who opens DevTools and calls AuthService.createUser(...) or AuthService.deleteUser(...) directly from the browser console bypasses the UI entirely. Because there is no server to validate the request, the operation succeeds. There is no real authorization boundary.No server-side validation
No server-side validation
Shipment records are saved by writing directly to LocalStorage via
saveStoredShipments() in assets/app.js. There is no server to reject malformed entries, enforce required fields beyond basic UI-layer checks, or detect business-rule violations such as:- Duplicate HAWB or MAWB numbers across separate inbound entries
- Outbound quantities exceeding the recorded inbound quantity
- Missing mandatory fields that were bypassed by manipulating the DOM
aggregateShipmentsByReference() attempts to handle missing or malformed quantity values by treating them as 0, but this means corrupt records silently skew inventory totals rather than raising an error.QR codes may carry full shipment payloads
QR codes may carry full shipment payloads
The
normalizeShipmentPayload() function in assets/app.js accepts QR codes that encode a full JSON object containing client, HAWB, MAWB, invoice, transaction type, plate number, date, and time fields. Embedding all of this data in a QR code creates large, dense codes that are harder to scan reliably and expose the full shipment record to anyone who scans the code.The recommended approach is described in the README: store only the HAWB or MAWB identifier in the QR code, then look up the full record from a backend database by that identifier. The existing normalizeShipmentPayload() already handles plain-text QR values as a HAWB/MAWB search term, so the scanner-side code is already partially prepared for this transition.Profile edits not synced back to auth account data
Profile edits not synced back to auth account data
The profile page (
pages/profile.html) reads from and writes to warehouseProfile in LocalStorage, which is a separate storage key from warehouseAuthAccounts. When a user edits their name on the profile page, the change is persisted to warehouseProfile but the corresponding account object inside warehouseAuthAccounts — and the active session stored under warehouseAuthSession — is not updated.As a result, AuthService.getCurrentUser().name continues to return the original name from the session, while the profile page displays the edited name. The two sources diverge silently.Limited UI field validation
Limited UI field validation
Several form fields across the inbound/outbound and user management pages lack advanced validation. Examples include:
- No format enforcement on HAWB/MAWB fields — any string is accepted
- No check for outbound quantities exceeding available stock at the time of entry
- The user management add-user modal checks for duplicate
employeeIdanduserIdviaAuthService.createUser(), but the UI does not pre-validate before submission - Date and time fields fall back to current Philippine time when empty, which can silently produce incorrect timestamps for backdated entries
Recommended Improvements
Backend & Database
Replace LocalStorage with a REST API backed by a relational database. Define tables for
users, sessions, shipments, profiles, and notifications. Move all persistence calls — currently scattered across auth.js and app.js — behind API client functions. See the migration path for a proposed table schema derived from the existing LocalStorage object shapes.Secure Authentication
Hash passwords with bcrypt before storage — never persist plaintext. Issue JWTs or server-managed session tokens on login. Validate the token on every API request server-side so that role checks cannot be bypassed from the browser console. Retire the
DEFAULT_PASSWORD constant (Password123) in favour of a forced password-change flow on first login after a reset.QR Code Optimization
Store only the HAWB or MAWB identifier in each QR code. On scan, look up the full shipment record from the backend by that identifier rather than decoding a JSON payload from the code itself. This produces smaller, more reliably scannable codes and prevents shipment data from being exposed in printed labels. See QR payload format for the proposed minimal payload structure.
Barcode Support
Add barcode scanning alongside the existing QR scanning flow. Standard warehouse labels (GS1-128, Code 128, ITF-14) carry HAWB and MAWB values as barcodes rather than QR codes. Integrating a barcode decode library (e.g., ZXing-js) into the existing
startQrScanner() animation-frame loop would allow the same scan modal to handle both formats.Bulk Import
Add an Excel import path for bulk shipment data entry. The application already exports activity data as
.xlsx via the xlsx library. Implementing the inverse — parsing an uploaded spreadsheet and calling saveStoredShipments() (or a future API endpoint) for each row — would significantly reduce manual entry time for large receiving batches.Real-Time Dashboard
Replace the current
warehouse:data-updated custom-event pattern — which only refreshes data within a single browser tab — with a WebSocket connection or a short-interval polling mechanism against the backend API. This would allow renderDashboardData(), refreshInventory(), and refreshActivity() to reflect changes made by other users without requiring a manual page reload.Audit Logging
Record who created or modified each shipment and user account, and when. The current data model has no
createdBy or modifiedBy field on shipment records, and user accounts only track createdAt and lastLogin. A backend audit log table keyed by userId, action, targetId, and timestamp would satisfy compliance requirements and make it possible to investigate data discrepancies.Carrier Integration
Integrate with carrier tracking APIs (e.g., FedEx, DHL, local freight carriers) to automatically update shipment status and estimated delivery dates. This would replace the current manual outbound entry flow for tracked shipments and reduce the risk of inventory counts drifting out of sync with actual carrier status.
Security Hardening Checklist
The following steps should be completed before deploying the system with real operational data:- Hash passwords with bcrypt — Replace all plaintext password storage in
warehouseAuthAccountsand theDEFAULT_PASSWORDreset value. Use a work factor of at least 12. - Use secure, HTTP-only session cookies or short-lived JWTs — Remove
warehouseAuthSessionfrom LocalStorage. Issue tokens server-side and store them in HTTP-only cookies or in-memory only, so they are not accessible to JavaScript running in the page. - Enforce role checks server-side on every API endpoint — Do not rely on the
currentUser.role !== 'admin'guards inAuthService. Validate the caller’s role from the server-side session on every mutating request. - Sanitize and validate all form inputs server-side — Treat every value arriving from the browser as untrusted. Enforce field types, lengths, and business rules (e.g., outbound quantity ≤ remaining inbound quantity) in the API layer, not only in the UI.
- Replace plaintext QR payloads with signed identifiers — If QR codes must carry more than a bare HAWB/MAWB, sign the payload with a server-generated HMAC so that forged or tampered codes can be detected before any data is written.
- Add rate limiting to login endpoints — The current
AuthService.authenticateUser()has no lockout or throttle mechanism. A backend login endpoint should enforce a limit (e.g., five failed attempts per minute per IP) to prevent credential-stuffing attacks. - Enable HTTPS with HSTS — All production deployments must serve the application over TLS. Add an
HTTP Strict-Transport-Securityheader with amax-ageof at least one year to prevent protocol downgrade attacks.