The YUSEN LIMO Warehouse System is a single-page-style static web application. There is no build step, no module bundler, and no server-side runtime. All application logic is written in vanilla JavaScript and loaded directly by HTMLDocumentation 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.
<script> tags. State is persisted entirely in the browser’s Local Storage, and the app is fully functional from any static file server. Understanding how the files relate to each other — and how data flows between them — is the foundation for maintaining or extending the codebase.
Folder Structure
File Responsibilities
Each file has a clearly scoped role. The table below maps files to their purpose, extracted from the maintenance notes in the developer documentation.| File | Purpose |
|---|---|
index.html | Login page and application entry point. Loads styles.css, assets/auth.js, and assets/login.js. |
styles.css | Login screen styles, branding layout, and background image placement. |
assets/auth.js | AuthService object: authentication, session lifecycle, user account CRUD, and Local Storage persistence for accounts and sessions. |
assets/login.js | Login form behavior: reads form inputs, calls AuthService.authenticateUser(), handles errors, and redirects on success. |
assets/app.js | Main application logic for all authenticated pages: page guard, data aggregation, inventory/activity rendering, QR scanning, notifications, profile management, and export. |
assets/app.css | Shared authenticated UI styles: sidebar, topbar, cards, tables, modals, drawer, filters, and responsive breakpoints. |
pages/dashboard.html | Dashboard cards (total shipments, cargo in warehouse, outgoing today) and activity report interface. |
pages/inbound-outbound.html | Tabbed inbound and outbound shipment entry forms with QR scan support and quantity row management. |
pages/inventory.html | Inventory table with search, filters, sort, pagination, and a slide-out detail drawer. |
pages/profile.html | User profile metadata editor and profile picture upload modal. |
pages/user-management.html | Admin-only user table with add, edit, reset password, status toggle, and delete actions. |
tests/auth.test.js | Node.js unit tests for AuthService logic. Run with node tests/auth.test.js. |
Login Flow
The login sequence is the entry point for every user session. It spansindex.html, assets/auth.js, and assets/login.js.
Browser opens index.html
The browser loads
index.html, which includes assets/auth.js and assets/login.js as synchronous <script> tags. AuthService.initializeAuth() is called immediately when auth.js is parsed, seeding default accounts into warehouseAuthAccounts in Local Storage if none exist.login.js checks AuthService.isAuthenticated()
Inside the
DOMContentLoaded handler in login.js, after wiring up the password-visibility toggle, the script checks for an existing session:isAuthenticated() calls the internal readSession() helper, which reads and parses warehouseAuthSession from Local Storage. If a valid session object with a userId field is found, the function returns true.If authenticated → redirect to pages/dashboard.html
A returning user with an active session is immediately redirected to
pages/dashboard.html without ever seeing the login form. The redirect is a standard window.location.href assignment.On form submit → AuthService.authenticateUser() validates credentials
When the user submits the login form, Inside
login.js calls:authenticateUser(), credentials are trimmed, then matched against the account list returned by readAccounts(). The comparison is a strict string equality check against the stored password field — there is no hashing at this stage.Success → persist session under warehouseAuthSession, redirect to dashboard
On a successful credential match,
authenticateUser() constructs a session object:persistSession() serializes the object to warehouseAuthSession in Local Storage. The lastLogin timestamp is also updated on the matching account in warehouseAuthAccounts. login.js then redirects to pages/dashboard.html.Failure → display error message on login page
If the user ID is not found or the password does not match,
authenticateUser() returns { success: false, message: '...' }. The login.js handler writes this message to the #loginError element using setError() and re-enables the submit button via setLoading(false).Navigation Flow
Every page insidepages/ loads assets/app.js, which runs guardPageAccess() on startup:
isProtectedPage is true whenever the path includes /pages/. isAdminRoute matches paths containing /admin, /settings, or user-management. Any unauthenticated user is bounced back to index.html; any non-admin attempting to reach an admin route is redirected to dashboard.html.
The sidebar and topbar are shared across all authenticated HTML pages. Admin-only navigation items (the User Management link) use the CSS class .admin-only-nav. app.js reads the current role from AuthService.getCurrentUser() and hides or shows these elements at page initialization.
Data Flow
Shipment data originates from the inbound/outbound forms and flows through a multi-stage pipeline before it is displayed in the inventory or activity views.getStoredShipments() reads from localStorage.getItem(STORAGE_KEY) (key: warehouseShipments) and falls back to inMemoryShipmentStore if Local Storage is unavailable. The central aggregation function aggregateShipmentsByReference() groups raw shipment records by HAWB or MAWB, computes qtyInValue and qtyOutValue totals, derives remainingQuantity (qtyInValue - qtyOutValue), and collects all outbound events into outboundDetails sorted chronologically. Both the inventory page and the activity page consume the output of this function — they differ only in how normalizeShipmentForInventory and normalizeShipmentForActivity reshape each aggregated record for their respective table columns.
Global Event System
Thewarehouse:data-updated custom event is the application’s internal data bus. It decouples the shipment save operation from the UI refresh cycle. Any code that modifies shipment data calls saveStoredShipments(), which always dispatches the event at the end:
app.js handles all downstream refreshes:
refreshInventory and refreshActivity are module-level variables that are assigned to the page-specific render functions (renderInventoryPage and renderActivityPage) only after those pages have been initialized. The typeof guard prevents errors on pages where those functions are not yet defined.
Key Global Variables
The following variables are declared at the top ofassets/app.js and are accessible throughout the file. They represent the shared application state for any authenticated page.
| Variable | Type | Purpose |
|---|---|---|
STORAGE_KEY | string | Local Storage key for all shipment records. Value: 'warehouseShipments'. |
refreshInventory | function | null | Assigned to renderInventoryPage(1) after the inventory page initializes. Called by the warehouse:data-updated handler to re-render the inventory table. |
refreshActivity | function | null | Assigned to renderActivityPage(1) after the activity section initializes. Called on data updates and filter changes. |
inventoryData | array | In-memory cache of normalized inventory aggregates. Populated by getInventoryData() and consumed by the inventory table renderer and filters. |
activityData | array | In-memory cache of normalized activity aggregates. Populated by getActivityData() and consumed by the activity table renderer, filters, and export functions. |
inMemoryShipmentStore | array | Fallback shipment store used when Local Storage is unavailable or throws. Only updated inside the catch block of saveStoredShipments() — not written on every successful save. |
notificationState | array | In-memory list of notification objects (id, type, title, description, meta, time, read). Declared with let inside the DOMContentLoaded callback (not a module-level global). Persisted to and loaded from warehouseNotificationState in Local Storage. |