14 KiB
Project Files Guide
A junior-friendly walk-through of every folder and file that matters in this repository. Read it alongside README.md: the README tells you how to run the project, this guide tells you where things live once it is running.
How the application is organised
There are three parts:
- Backend — Node.js + Express in src/. Talks to MariaDB, serves
the API under
/api/v1/, and serves the static frontend files. - Frontend — two single-page shells in public/:
user.htmlfor operators andadmin.htmlfor administrators. Both are ES-module based (no bundler) and use Bootstrap 5. - Database — MariaDB. Schema and seed data are in sql/. Docker loads them automatically on a fresh volume.
End-to-end request flow (simplified)
docker compose upstarts three containers:app,db,phpmyadmin.- src/server.js boots Express and connects to MariaDB.
- The browser loads
/→portal.html(chooser page). - The user clicks a link and goes to
/login-adminor/login-user. - After login,
/adminor/useris served — both require a validauth_tokencookie (see src/middleware/authMiddleware.js). - The frontend shell loads either
admin-app.jsoruser-app.js, which hands off topublic/js/admin.jsorpublic/js/user.js. - The frontend calls
/api/v1/admin/allto bulk-load every entity needed for rendering, and keeps working drafts in IndexedDB.
Root files
package.json
Defines the Node project: scripts (start, dev, test:environment),
dependencies (Express, MariaDB driver, cookie-parser, cors, dotenv), and the
minimum Node version.
docker-compose.yml
Spins up app, db, and phpmyadmin containers with the right volumes and
ports for local development.
.env.example / .env
.env.example documents the variables the backend expects. Copy it to .env
and fill in real values; src/config/env.js loads them at
startup and fails fast if a required one is missing.
.devcontainer/
VS Code Dev Containers definition so the editor opens directly inside the
app container.
docker/mariadb/init/
Mount point for extra init scripts. sql/schema.sql and sql/seed.sql are
placed here by Docker Compose so they run the first time the DB volume is
created.
public/ — what the browser gets
HTML shells
- public/portal.html — the neutral landing page at
/. Two links: one to the user login, one to the admin login. - public/login-admin.html and
public/login-user.html — login forms. They POST
to
/api/v1/auth/admin/loginor/api/v1/auth/user/loginand follow the JSONredirecton success. - public/admin.html — Bootstrap sidebar + main area for
the admin console. Loads
admin-app.js. The sidebar opens on the Reports panel by default; nav categories are ordered Reports → CheckLists → Sites → Users → Settings. - public/user.html — Bootstrap shell for the operator
task workflow. Loads
user-app.js. Contains a Sync button in the Assigned Tasks header that refreshes the task list from the server without a full page reload.
Top-level scripts
- public/admin-app.js — opens the shared IndexedDB
(
check-list-poc-db), reads the cached image rules, then callsinitAdmin()from public/js/admin.js. - public/user-app.js — opens the shared IndexedDB
(
check-list-poc-db) and callsinitUser()from public/js/user.js.user.jsadditionally opens a second database (user-portal-db) for per-task record data and images.
Static assets
- public/styles.css — custom styles layered on top of
Bootstrap 5. Includes
.admin-table(full-width, striped header, hover rows),.admin-table-compact(denser column padding for wide entity tables), and.admin-table-actions(shrink-wraps the actions column so data columns take all remaining space). - public/icon.svg — PWA icon referenced by public/manifest.webmanifest.
public/js/ — frontend modules
Each file has a single responsibility and imports only what it needs.
- public/js/constants.js — store names, API base path, timings.
- public/js/state.js — tiny shared object holding the
current IndexedDB handle. Kept deliberately small; most feature-specific
state lives inside
admin.jsoruser.js. - public/js/api.js —
fetchJson(path, options)wrapper that prepends the versioned base path and turns{ message }error bodies into thrown errors. - public/js/db.js — opens and wraps
check-list-poc-db(the shared IndexedDB used by both admin and user consoles) with generic CRUD helpers: get, put, delete, transaction. - public/js/user-db.js — opens and wraps
user-portal-db(a second, separate IndexedDB used only by the user console). Stores per-task record answers, visit dates, and imagedataUrlblobs keyed by numeric task ID. - public/js/validation.js — pure validators for reports and image-rule forms. No DOM or state dependencies, so the same logic can be reused server-side.
- public/js/images.js — image optimisation entry
point. Detects Web Worker +
OffscreenCanvassupport and falls back to main-thread canvas when not available. Preserves the EXIF block so the backend gets the same metadata the user saw. - public/js/image-worker.js — the worker
implementation used by
images.js. - public/js/exif.js — lightweight JPEG EXIF parser (IFD0 + GPS tags) used by both the user flow and the admin lightbox.
- public/js/admin.js — the admin console controller. Navigation, render functions, and CRUD handlers for every admin category. The Users table includes a Tasks column with a badge showing how many tasks are assigned to each user (blue if > 0, grey if 0).
- public/js/user.js — the operator workflow controller.
Key responsibilities:
loadFromServer()— fetches/api/v1/admin/all; on401(stale cookie after a server restart) it redirects to/login-user; on any other failure it falls back to the IndexedDB cache.filterTasksByUser()— keeps only tasks wheretask.userIdmatches the?userId=URL parameter.showDetailView(id)— chainsmaybeHydrateFromServer()(seeds IndexedDB from the server if the task has no local data) →maybeDownloadImages()(fetches image blobs from the server if they were previously uploaded) →renderTaskDetail().forceSyncWithServer()— called by the Sync button; re-fetches live data without a page reload.- Record editing, image attachment, save-as-draft, and submit-as-final with image optimisation and validation.
src/ — backend
src/server.js
Boot file. Imports the Express app, confirms the DB connection, starts
listening, and wires up SIGINT / SIGTERM for a clean shutdown.
src/app.js
Express wiring. Middleware stack in mount order:
cors()— wide-open CORS for PoC usecookieParser()— parses theauth_tokencookieexpress.json({ limit: '50mb' })— accepts large base64 image payloadsnoCacheHtml— setsCache-Control: no-cacheon every HTML response so browsers revalidate page content after a Docker restart instead of serving a stale cached copy- API routes under
/api/v1/ - HTML page routes (
/,/login-admin,/login-user,/admin,/user) express.static(public/)withsetHeadersapplyingno-cachefor.htmlfiles; JS/CSS use default ETag revalidation- 404 + global error handlers
requireAnyAuth is applied to /api/v1/admin/* and /api/v1/reports/*;
requireUserAuth / requireAdminAuth gate the HTML workspaces.
src/config/
- src/config/env.js — loads
.envviadotenv, checks required keys, exposes a normalisedenvobject.
src/db/
- src/db/pool.js — creates the shared MariaDB pool and
exposes
query()/closePool().
src/middleware/
- src/middleware/authMiddleware.js —
requireAdminAuth,requireUserAuth,requireAnyAuth. For API callers (detected viareq.originalUrl/Accept) an unauthenticated response returns401 JSON; browser navigation is redirected to the relevant login page. - src/middleware/errorHandler.js —
notFoundHandlerand globalerrorHandlerthat convert everything to a consistent JSON shape. - src/middleware/validateParams.js — regex / numeric URL-parameter guards used by route definitions.
src/routes/
| File | Prefix | Notes |
|---|---|---|
| healthRoutes.js | /api/v1/health |
Liveness + DB ping. |
| authRoutes.js | /api/v1/auth |
Admin/user login, logout, me. Issues the auth_token cookie. |
| adminRoutes.js | /api/v1/admin |
CRUD for every admin entity and /all bulk load. Gated by requireAnyAuth. |
| reportRoutes.js | /api/v1/reports |
Submit/get/list/delete reports and their images. Gated by requireAnyAuth. |
| configRoutes.js | /api/v1/config |
Image-rules read/write (audit-logged) and export profile. |
| lookupRoutes.js | /api/v1/lookups |
Reference lookup sets and values. |
| templateRoutes.js | /api/v1/templates |
Legacy template catalogue (kept for the seeded sample + smoke test). |
src/services/
Thin layer between routes and SQL. Each file owns a domain.
- adminService.js — everything under
admin_*tables, plus the bulkloadAllAdminData()used by both the admin and user consoles. - auditService.js — writes to
audit_logwhenever something sensitive changes (report submit/delete, image rules update, template publish). - authService.js — credential verification
and an in-memory session
Mapwith 24-hour expiry. Plain-text password comparison — PoC only. - cacheService.js — generic LRU + TTL
factory, pre-configured
templateCache,lookupCache,configCache. - configService.js — image rules and
export profile queries. (Previous
app_confighelpers were removed along with the table.) - lookupService.js —
lookup_sets/lookup_values. - reportService.js —
reportsandreport_images. Images are stored asLONGBLOBrows; list helpers group them byrecord_id. - templateService.js — template +
template_versionsqueries and publish flow.
src/utils/
- asyncHandler.js — wraps async route handlers so rejected promises reach the Express error middleware.
- json.js — safely parses JSON columns returned by MariaDB.
sql/
sql/schema.sql
Defines every table the app touches:
- Template catalogue:
templates,template_versions. - Reference data:
lookup_sets,lookup_values,image_rules,export_profiles. - Reports:
reports(answers as JSON) andreport_images(binary blobs). - Audit:
audit_log. - Admin entities:
admin_categories,admin_sub_categories,admin_severities,admin_statuses,admin_handled_by,admin_projects,admin_processes,admin_users,admin_sites,admin_cl_records,admin_cl_templates,admin_cl_template_records(join),admin_tasks. - Credentials:
admin_credentials.
sql/seed.sql
Inserts enough data for the frontend to boot: the sample
incoming-inspection template, pass-fail / draft-status lookups, the
default image-rules row, the default export profile, and seed admin/user
credentials.
scripts/
scripts/test-environment.js
Connectivity smoke test — hits /api/v1/health, /api/v1/templates, the DB
directly, and phpMyAdmin. Useful after docker compose up and after any
infrastructure change.
Recommended reading order
- README.md
- docker-compose.yml
- sql/schema.sql
- src/server.js → src/app.js
- src/middleware/authMiddleware.js
- src/routes/adminRoutes.js and src/services/adminService.js
- public/admin-app.js → public/js/admin.js
- public/user-app.js → public/js/user.js
Quick "where do I look" rule
- Page layout looks wrong → the relevant
.htmlin public/ and public/styles.css. - Browser behaviour is wrong →
public/js/admin.jsorpublic/js/user.js, or the feature-specific module (validation.js,images.js,exif.js). - API endpoint is wrong → the matching file in src/routes/, then the service it delegates to.
- Data looks wrong → sql/schema.sql and sql/seed.sql, plus the service file that owns the query.
- App won't start → src/server.js, src/config/env.js, and docker-compose.yml.