modified version
This commit is contained in:
+269
-641
@@ -1,676 +1,304 @@
|
||||
# Project Files Guide
|
||||
|
||||
This document explains the role of the main files in this project in a way that should be easy to follow for a junior developer.
|
||||
A junior-friendly walk-through of every folder and file that matters in this
|
||||
repository. Read it alongside [README.md](README.md): the README tells you how
|
||||
to run the project, this guide tells you where things live once it is running.
|
||||
|
||||
The project is split into a few clear parts:
|
||||
- server code in [src/app.js](src/app.js) and the rest of [src](src)
|
||||
- browser frontend files in [public](public)
|
||||
- database structure and example data in [sql](sql)
|
||||
- environment and local development helpers in the root folder and [scripts](scripts)
|
||||
## How the application is organised
|
||||
|
||||
## How The Application Works At A High Level
|
||||
There are three parts:
|
||||
|
||||
The project has two big sides:
|
||||
- the backend, which provides templates, lookups, configuration, report storage, and audit logging through REST API endpoints
|
||||
- the frontend, which runs in the browser, stores drafts locally, and uses the backend for centrally managed configuration and report submission
|
||||
1. **Backend** — Node.js + Express in [src/](src/). Talks to MariaDB, serves
|
||||
the API under `/api/v1/`, and serves the static frontend files.
|
||||
2. **Frontend** — two single-page shells in [public/](public/): `user.html` for
|
||||
operators and `admin.html` for administrators. Both are ES-module based
|
||||
(no bundler) and use Bootstrap 5.
|
||||
3. **Database** — MariaDB. Schema and seed data are in [sql/](sql/). Docker
|
||||
loads them automatically on a fresh volume.
|
||||
|
||||
In simple terms:
|
||||
1. Express starts the server.
|
||||
2. The server exposes API endpoints under `/api/v1/...`.
|
||||
3. The server also serves the frontend files from the [public](public) folder.
|
||||
4. The browser loads the frontend entry point [public/app.js](public/app.js) which imports modules from [public/js/](public/js).
|
||||
5. The frontend downloads templates and config from the API using a single batch request.
|
||||
6. The frontend stores reports and images locally in IndexedDB.
|
||||
7. Reports can be submitted to the server via `POST /api/v1/reports`.
|
||||
### End-to-end request flow (simplified)
|
||||
|
||||
## Root Files
|
||||
1. `docker compose up` starts three containers: `app`, `db`, `phpmyadmin`.
|
||||
2. [src/server.js](src/server.js) boots Express and connects to MariaDB.
|
||||
3. The browser loads `/` → `portal.html` (chooser page).
|
||||
4. The user clicks a link and goes to `/login-admin` or `/login-user`.
|
||||
5. After login, `/admin` or `/user` is served — both require a valid
|
||||
`auth_token` cookie (see [src/middleware/authMiddleware.js](src/middleware/authMiddleware.js)).
|
||||
6. The frontend shell loads either `admin-app.js` or `user-app.js`, which
|
||||
hands off to `public/js/admin.js` or `public/js/user.js`.
|
||||
7. The frontend calls `/api/v1/admin/all` to bulk-load every entity needed
|
||||
for rendering, and keeps working drafts in IndexedDB.
|
||||
|
||||
## Root files
|
||||
|
||||
### [package.json](package.json)
|
||||
|
||||
Role:
|
||||
Defines the Node.js project itself.
|
||||
|
||||
What it contains:
|
||||
- project name and version
|
||||
- npm scripts such as `start`, `dev`, and `test:environment`
|
||||
- dependency list such as `express`, `mariadb`, and `dotenv`
|
||||
|
||||
Why it matters:
|
||||
When you run `npm install` or `npm start`, Node uses this file to know how the project should behave.
|
||||
|
||||
### [README.md](README.md)
|
||||
|
||||
Role:
|
||||
Main entry document for developers.
|
||||
|
||||
What it contains:
|
||||
- project purpose
|
||||
- setup steps
|
||||
- available endpoints
|
||||
- development notes
|
||||
|
||||
Why it matters:
|
||||
This is the first file a new developer should read before touching the code.
|
||||
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](docker-compose.yml)
|
||||
|
||||
Role:
|
||||
Starts the full local development environment.
|
||||
|
||||
What it contains:
|
||||
- the application container
|
||||
- the MariaDB container
|
||||
- the phpMyAdmin container
|
||||
- port mappings and volume configuration
|
||||
|
||||
Why it matters:
|
||||
Instead of installing and configuring everything manually, you can start the full stack with one command.
|
||||
|
||||
### [.env.example](.env.example)
|
||||
|
||||
Role:
|
||||
Example environment configuration.
|
||||
|
||||
What it contains:
|
||||
- default port values
|
||||
- database host, name, user, and password placeholders
|
||||
|
||||
Why it matters:
|
||||
It shows which environment variables the application expects.
|
||||
|
||||
### [.env](.env)
|
||||
|
||||
Role:
|
||||
Real environment file used on the current machine.
|
||||
|
||||
What it contains:
|
||||
- actual local values for ports and database credentials
|
||||
|
||||
Why it matters:
|
||||
The backend reads this file during startup through `dotenv`.
|
||||
|
||||
## Public Folder
|
||||
|
||||
The [public](public) folder contains files that are sent directly to the browser.
|
||||
|
||||
### [public/user.html](public/user.html)
|
||||
|
||||
Role:
|
||||
Operator workspace HTML shell.
|
||||
|
||||
What it contains:
|
||||
- shared sidebar with template selector, sync button, report list, and search/filter
|
||||
- report editor main area with hero, summary cards, form, inspector panel
|
||||
- report list item `<template>` for runtime rendering
|
||||
|
||||
When you edit it:
|
||||
- when you need to change the report editing layout
|
||||
- when adding new user-facing controls or sections
|
||||
|
||||
### [public/admin.html](public/admin.html)
|
||||
|
||||
Role:
|
||||
Administrator workspace HTML shell.
|
||||
|
||||
What it contains:
|
||||
- simplified sidebar with template selector and sync button (no report list)
|
||||
- admin main area with image policy editor form and admin summary panel
|
||||
|
||||
When you edit it:
|
||||
- when adding new admin configuration panels
|
||||
- when changing the image policy form fields
|
||||
|
||||
### [public/index.html](public/index.html)
|
||||
|
||||
Role:
|
||||
Legacy combined app shell (no longer served by routes).
|
||||
|
||||
Note:
|
||||
This file has been superseded by [user.html](public/user.html) and [admin.html](public/admin.html).
|
||||
It remains in the repository for reference but is not routed to by the Express server.
|
||||
|
||||
### [public/portal.html](public/portal.html)
|
||||
|
||||
Role:
|
||||
Simple chooser page that lets the user open either the user area or the admin area.
|
||||
|
||||
What it contains:
|
||||
- a short explanation of the two entry points
|
||||
- a link to `/user`
|
||||
- a link to `/admin`
|
||||
|
||||
What it does:
|
||||
It is the landing page served at `/`. It does not contain complex logic. Its job is only to separate the entry points.
|
||||
|
||||
### [public/app.js](public/app.js)
|
||||
|
||||
Role:
|
||||
Thin orchestrator entry point for the frontend.
|
||||
|
||||
What it contains:
|
||||
- imports from all ES modules under `public/js/`
|
||||
- startup flow (`init()`, `cacheElements()`, `bindEvents()`)
|
||||
- report CRUD operations (create, open, delete, submit)
|
||||
- sync logic with the API using batch template fetch
|
||||
- dirty-flag autosave loop
|
||||
- admin image-policy save
|
||||
- event delegation for the report list
|
||||
- search/filter event wiring
|
||||
- null guards for page-specific elements (user vs admin)
|
||||
|
||||
What changed:
|
||||
This file was originally a monolithic ~1700-line file. It has been split into modules (A1)
|
||||
and now acts as a controller. It is shared between user.html and admin.html — it detects
|
||||
which DOM elements exist and only binds behavior for the current page.
|
||||
|
||||
### [public/styles.css](public/styles.css)
|
||||
|
||||
Role:
|
||||
Main styling file for the frontend.
|
||||
|
||||
What it contains:
|
||||
- color variables
|
||||
- layout rules
|
||||
- sidebar and panel styles
|
||||
- form field styles
|
||||
- admin and user page styles
|
||||
- responsive behavior for smaller screens
|
||||
|
||||
What it does:
|
||||
It controls how the application looks on desktop and mobile.
|
||||
|
||||
When you edit it:
|
||||
- when spacing or sizing is wrong
|
||||
- when a section needs a new visual style
|
||||
- when mobile layout needs improvement
|
||||
|
||||
### [public/sw.js](public/sw.js)
|
||||
|
||||
Role:
|
||||
Service worker for offline behavior.
|
||||
|
||||
What it contains:
|
||||
- cache name
|
||||
- app shell file list (including all new JS modules)
|
||||
- install, activate, and fetch event handlers
|
||||
- LRU cache trimming for dynamic entries (P5)
|
||||
|
||||
What it does:
|
||||
It tells the browser how to cache frontend files and API responses.
|
||||
|
||||
Important behavior:
|
||||
- static files use cache-first strategy
|
||||
- API calls use network-first strategy
|
||||
- dynamic cache is bounded to prevent unbounded storage growth
|
||||
|
||||
### [public/icon.svg](public/icon.svg)
|
||||
|
||||
Role:
|
||||
SVG icon used by the PWA manifest (F5).
|
||||
|
||||
### Frontend ES Modules (public/js/)
|
||||
|
||||
These modules were extracted from the original monolithic `app.js` (A1).
|
||||
All render functions include null guards so the shared `app.js` can safely run on
|
||||
both user.html (operator workspace) and admin.html (administrator workspace).
|
||||
|
||||
### [public/js/constants.js](public/js/constants.js)
|
||||
|
||||
Role:
|
||||
Shared constants used across frontend modules.
|
||||
|
||||
What it contains:
|
||||
- IndexedDB name, version, and store names
|
||||
- API base path (`/api/v1`)
|
||||
- autosave interval, render debounce timing, cache limits
|
||||
|
||||
### [public/js/state.js](public/js/state.js)
|
||||
|
||||
Role:
|
||||
Centralized state management for the frontend.
|
||||
|
||||
What it contains:
|
||||
- `state` object with all application state (including dirty flag, search query, filter)
|
||||
- `elements` object for cached DOM references
|
||||
- `getCurrentReport()` and `getTemplateRecord()` helpers
|
||||
- `stateHelpers` bundle used by other modules to avoid circular imports
|
||||
|
||||
### [public/js/i18n.js](public/js/i18n.js)
|
||||
|
||||
Role:
|
||||
Internationalization locale extraction (F7).
|
||||
|
||||
What it contains:
|
||||
- English locale with ~80 UI string keys
|
||||
- `t(key, ...params)` translation function with placeholder replacement
|
||||
- `setLocale()` for future language support
|
||||
|
||||
### [public/js/utils.js](public/js/utils.js)
|
||||
|
||||
Role:
|
||||
Pure utility and formatting functions.
|
||||
|
||||
What it contains:
|
||||
- `prettifyStatus()`, `formatDateTime()`, `formatTime()`, `formatRelativeTime()`, `formatFileSize()`
|
||||
- `sanitizeForFilename()`, `generateReportNumber()`, `buildGeneratedFilename()`
|
||||
- `makeTemplateKey()`, `deriveTemplateCatalog()`
|
||||
- `debounce()` helper for rate-limiting function calls (P2)
|
||||
|
||||
### [public/js/db.js](public/js/db.js)
|
||||
|
||||
Role:
|
||||
IndexedDB operations with multi-store transaction support.
|
||||
|
||||
What it contains:
|
||||
- `openDatabase()` with schema version 2
|
||||
- CRUD helpers: `dbGetAll()`, `dbGet()`, `dbPut()`, `dbDelete()`, `dbGetAllByIndex()`
|
||||
- `dbTransaction()` for atomic multi-store operations (A5)
|
||||
- `saveSetting()` and `loadSetting()` for UI preferences
|
||||
|
||||
### [public/js/api.js](public/js/api.js)
|
||||
|
||||
Role:
|
||||
API communication layer with versioned base path (A3).
|
||||
|
||||
What it contains:
|
||||
- `fetchJson(path, options)` that prepends the API base path automatically
|
||||
- `registerServiceWorker()`
|
||||
|
||||
### [public/js/validation.js](public/js/validation.js)
|
||||
|
||||
Role:
|
||||
Shared validation logic for reports and admin forms (A7).
|
||||
|
||||
What it contains:
|
||||
- `validateReport()` — checks required fields, number ranges, attachment counts
|
||||
- `validateImageRulesPayload()` — validates image policy form submissions
|
||||
- `evaluateRequiredWhen()` — conditional field requirement logic
|
||||
- `isBlankValue()` — blank check by field type
|
||||
|
||||
### [public/js/images.js](public/js/images.js)
|
||||
|
||||
Role:
|
||||
Image optimization with Web Worker support (P1).
|
||||
|
||||
What it contains:
|
||||
- `optimizeImage(file, imageRules)` — automatically detects Web Worker support
|
||||
- Worker path: delegates to `image-worker.js` via `OffscreenCanvas`
|
||||
- Falls back to main-thread canvas when OffscreenCanvas is unavailable
|
||||
|
||||
### [public/js/image-worker.js](public/js/image-worker.js)
|
||||
|
||||
Role:
|
||||
Web Worker for background image processing (P1).
|
||||
|
||||
What it contains:
|
||||
- `self.onmessage` handler using `createImageBitmap` and `OffscreenCanvas`
|
||||
- Sends optimized blob back to main thread with matching message ID
|
||||
|
||||
### [public/js/forms.js](public/js/forms.js)
|
||||
|
||||
Role:
|
||||
Dynamic form field creation from template JSON.
|
||||
|
||||
What it contains:
|
||||
- `createFieldNode(field, report, callbacks)` — renders fields with callback pattern
|
||||
- `createAttachmentFieldNode()` with IntersectionObserver for lazy-loading thumbnails (P3)
|
||||
- `escapeHtml()` for XSS prevention
|
||||
|
||||
### [public/js/renderer.js](public/js/renderer.js)
|
||||
|
||||
Role:
|
||||
All DOM render functions with search and filter support (F4).
|
||||
|
||||
What it contains:
|
||||
- `render()` orchestrator — conditionally calls user or admin renders
|
||||
- `renderReportList()` — filters by search query and status
|
||||
- `renderCurrentReport(fieldCallbacks)` — accepts callbacks for field changes
|
||||
- `renderTemplateSelector()`, `renderTemplateSummary()`
|
||||
- `renderSyncSummary()`, `renderImagePolicy()`, `renderAdminImageRules()`
|
||||
- `updateConnectionBadge()`, `updateSaveBadge()`
|
||||
- Uses `t()` for all user-visible strings
|
||||
- Null guards on all page-specific functions for safe user/admin coexistence
|
||||
|
||||
### [public/js/export.js](public/js/export.js)
|
||||
|
||||
Role:
|
||||
Report data export functionality (F2).
|
||||
|
||||
What it contains:
|
||||
- `exportReportCSV()` — generates CSV from template fields and report answers
|
||||
- `exportReportAttachments()` — triggers download for each attachment blob
|
||||
- `csvEscape()` and `downloadBlob()` helper functions
|
||||
|
||||
### [public/manifest.webmanifest](public/manifest.webmanifest)
|
||||
|
||||
Role:
|
||||
Basic PWA metadata file.
|
||||
|
||||
What it contains:
|
||||
- app name
|
||||
- short name
|
||||
- theme color
|
||||
- start URL
|
||||
|
||||
What it does:
|
||||
Helps the browser treat the app more like an installable web application.
|
||||
|
||||
## Source Folder
|
||||
|
||||
The [src](src) folder contains backend code.
|
||||
Spins up `app`, `db`, and `phpmyadmin` containers with the right volumes and
|
||||
ports for local development.
|
||||
|
||||
### [.env.example](.env.example) / `.env`
|
||||
|
||||
`.env.example` documents the variables the backend expects. Copy it to `.env`
|
||||
and fill in real values; [src/config/env.js](src/config/env.js) loads them at
|
||||
startup and fails fast if a required one is missing.
|
||||
|
||||
### [.devcontainer/](.devcontainer/)
|
||||
|
||||
VS Code Dev Containers definition so the editor opens directly inside the
|
||||
`app` container.
|
||||
|
||||
### [docker/mariadb/init/](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](public/portal.html) — the neutral landing page at `/`.
|
||||
Two links: one to the user login, one to the admin login.
|
||||
- [public/login-admin.html](public/login-admin.html) and
|
||||
[public/login-user.html](public/login-user.html) — login forms. They POST
|
||||
to `/api/v1/auth/admin/login` or `/api/v1/auth/user/login` and follow the
|
||||
JSON `redirect` on success.
|
||||
- [public/admin.html](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](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](public/admin-app.js) — opens the shared IndexedDB
|
||||
(`check-list-poc-db`), reads the cached image rules, then calls
|
||||
`initAdmin()` from [public/js/admin.js](public/js/admin.js).
|
||||
- [public/user-app.js](public/user-app.js) — opens the shared IndexedDB
|
||||
(`check-list-poc-db`) and calls `initUser()` from
|
||||
[public/js/user.js](public/js/user.js). `user.js` additionally opens a
|
||||
second database (`user-portal-db`) for per-task record data and images.
|
||||
|
||||
### Static assets
|
||||
|
||||
- [public/styles.css](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](public/icon.svg) — PWA icon referenced by
|
||||
[public/manifest.webmanifest](public/manifest.webmanifest).
|
||||
|
||||
## public/js/ — frontend modules
|
||||
|
||||
Each file has a single responsibility and imports only what it needs.
|
||||
|
||||
- [public/js/constants.js](public/js/constants.js) — store names, API base
|
||||
path, timings.
|
||||
- [public/js/state.js](public/js/state.js) — tiny shared object holding the
|
||||
current IndexedDB handle. Kept deliberately small; most feature-specific
|
||||
state lives inside `admin.js` or `user.js`.
|
||||
- [public/js/api.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](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](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 image
|
||||
`dataUrl` blobs keyed by numeric task ID.
|
||||
- [public/js/validation.js](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](public/js/images.js) — image optimisation entry
|
||||
point. Detects Web Worker + `OffscreenCanvas` support 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](public/js/image-worker.js) — the worker
|
||||
implementation used by `images.js`.
|
||||
- [public/js/exif.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](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](public/js/user.js) — the operator workflow controller.
|
||||
Key responsibilities:
|
||||
- `loadFromServer()` — fetches `/api/v1/admin/all`; on `401` (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 where `task.userId` matches
|
||||
the `?userId=` URL parameter.
|
||||
- `showDetailView(id)` — chains `maybeHydrateFromServer()` (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](src/server.js)
|
||||
|
||||
Role:
|
||||
Real server startup file.
|
||||
|
||||
What it contains:
|
||||
- startup function
|
||||
- database connection check
|
||||
- Express app startup
|
||||
- graceful shutdown logic
|
||||
|
||||
What it does:
|
||||
This is the file Node runs when the backend starts.
|
||||
|
||||
Simple mental model:
|
||||
- load the Express app
|
||||
- make sure MariaDB is reachable
|
||||
- start listening on a port
|
||||
- close cleanly when the process is stopped
|
||||
Boot file. Imports the Express app, confirms the DB connection, starts
|
||||
listening, and wires up `SIGINT` / `SIGTERM` for a clean shutdown.
|
||||
|
||||
### [src/app.js](src/app.js)
|
||||
|
||||
Role:
|
||||
Express application configuration file.
|
||||
|
||||
What it contains:
|
||||
- middleware registration
|
||||
- API v1 route registration under `/api/v1/` prefix (A3)
|
||||
- static file serving
|
||||
- frontend entry page routes
|
||||
- global error handling
|
||||
|
||||
Important routes:
|
||||
- `/api/v1/...` for versioned backend endpoints
|
||||
- `/` for the chooser page
|
||||
- `/user` and `/admin` for the frontend app shell
|
||||
|
||||
## Source Subfolders
|
||||
|
||||
### [src/config/env.js](src/config/env.js)
|
||||
|
||||
Role:
|
||||
Loads and validates environment variables.
|
||||
|
||||
What it contains:
|
||||
- `dotenv` setup
|
||||
- required environment key checks
|
||||
- normalized `env` object export
|
||||
|
||||
What it does:
|
||||
It reads raw values from `.env` and converts them into a safer object the rest of the code can use.
|
||||
|
||||
Why this is useful:
|
||||
Instead of reading `process.env` everywhere, the app reads from one clean place.
|
||||
|
||||
### [src/db/pool.js](src/db/pool.js)
|
||||
|
||||
Role:
|
||||
Creates and manages the MariaDB connection pool.
|
||||
|
||||
What it contains:
|
||||
- one shared database pool
|
||||
- `query()` helper
|
||||
- `closePool()` helper
|
||||
|
||||
What it does:
|
||||
It gives the service layer a standard way to run SQL queries.
|
||||
|
||||
Why it matters:
|
||||
Without this file, each route or service would have to manage its own connections, which would be messy and error-prone.
|
||||
|
||||
### [src/middleware/errorHandler.js](src/middleware/errorHandler.js)
|
||||
|
||||
Role:
|
||||
Handles not-found routes and server errors.
|
||||
|
||||
What it contains:
|
||||
- `notFoundHandler`
|
||||
- `errorHandler`
|
||||
|
||||
What it does:
|
||||
When a route does not exist, or when code throws an error, this file creates a JSON response instead of letting the app fail in an uncontrolled way.
|
||||
|
||||
### [src/middleware/validateParams.js](src/middleware/validateParams.js)
|
||||
|
||||
Role:
|
||||
URL parameter validation middleware (A7).
|
||||
|
||||
What it contains:
|
||||
- `validateParam(name)` — checks route params against safe patterns (code or UUID)
|
||||
- `validateNumericParam(name)` — validates numeric route parameters
|
||||
|
||||
What it does:
|
||||
It rejects malformed URL parameters at the middleware level before they reach route handlers.
|
||||
|
||||
### [src/routes/healthRoutes.js](src/routes/healthRoutes.js)
|
||||
|
||||
Role:
|
||||
Defines the health-check endpoint.
|
||||
|
||||
What it contains:
|
||||
- `GET /api/health`
|
||||
|
||||
What it does:
|
||||
Checks whether the server and database are working.
|
||||
|
||||
Why it matters:
|
||||
This endpoint is used by tests and is also useful when debugging container problems.
|
||||
|
||||
### [src/routes/templateRoutes.js](src/routes/templateRoutes.js)
|
||||
|
||||
Role:
|
||||
Defines template-related API endpoints.
|
||||
|
||||
What it contains:
|
||||
- list endpoint for active templates
|
||||
- batch endpoint with `?include=definitions` for single-request sync (A2)
|
||||
- endpoint for one active template
|
||||
- endpoint for a specific template version
|
||||
- version listing for a template (F3)
|
||||
- version publishing endpoint (F3)
|
||||
- parameter validation middleware
|
||||
- LRU cache integration (P4)
|
||||
|
||||
### [src/routes/lookupRoutes.js](src/routes/lookupRoutes.js)
|
||||
|
||||
Role:
|
||||
Defines lookup-related API endpoints.
|
||||
|
||||
What it contains:
|
||||
- list endpoint for lookup sets
|
||||
- endpoint for one lookup set
|
||||
- parameter validation and LRU cache integration
|
||||
|
||||
### [src/routes/configRoutes.js](src/routes/configRoutes.js)
|
||||
|
||||
Role:
|
||||
Defines configuration-related API endpoints.
|
||||
|
||||
What it contains:
|
||||
- image rule read and update endpoints
|
||||
- export profile endpoint
|
||||
- general app config endpoint
|
||||
- LRU cache read-through and invalidation (P4)
|
||||
- audit trail logging on image rules update (F6)
|
||||
|
||||
### [src/routes/reportRoutes.js](src/routes/reportRoutes.js)
|
||||
|
||||
Role:
|
||||
Defines report submission API endpoints (F1).
|
||||
|
||||
What it contains:
|
||||
- `GET /` — list submitted reports with filters (status, templateCode, limit, offset)
|
||||
- `GET /:reportId` — single report by UUID
|
||||
- `POST /` — submit or update a report (UPSERT by UUID, audit-logged)
|
||||
|
||||
### [src/services/templateService.js](src/services/templateService.js)
|
||||
|
||||
Role:
|
||||
Handles template-related database queries.
|
||||
|
||||
What it contains:
|
||||
- SQL for active template list
|
||||
- `getAllActiveTemplates()` — batch query returning all templates with definitions (A2)
|
||||
- `listTemplateVersions()` — all versions of a given template (F3)
|
||||
- `publishTemplateVersion()` — retire current active, activate specified version (F3)
|
||||
- template row mapping logic
|
||||
|
||||
### [src/services/lookupService.js](src/services/lookupService.js)
|
||||
|
||||
Role:
|
||||
Handles lookup-related database queries.
|
||||
|
||||
### [src/services/configService.js](src/services/configService.js)
|
||||
|
||||
Role:
|
||||
Handles configuration-related database queries.
|
||||
|
||||
### [src/services/reportService.js](src/services/reportService.js)
|
||||
|
||||
Role:
|
||||
Handles report submission and retrieval (F1).
|
||||
|
||||
What it contains:
|
||||
- `submitReport(report)` — UPSERT by report UUID
|
||||
- `getReport(uuid)` — fetch single report
|
||||
- `listReports({ status, templateCode, limit, offset })` — filtered listing
|
||||
|
||||
### [src/services/auditService.js](src/services/auditService.js)
|
||||
|
||||
Role:
|
||||
Audit trail logging for admin mutations (F6).
|
||||
|
||||
What it contains:
|
||||
- `logAuditEvent({ entityType, entityCode, action, oldValue, newValue })` — writes to audit_log table
|
||||
- `getAuditLog()` — reads audit entries with optional filters
|
||||
|
||||
### [src/services/cacheService.js](src/services/cacheService.js)
|
||||
|
||||
Role:
|
||||
In-memory LRU cache with TTL for server-side data (P4).
|
||||
|
||||
What it contains:
|
||||
- `createCache({ maxEntries, ttlMs })` factory function
|
||||
- Pre-configured singletons: `templateCache`, `lookupCache`, `configCache`
|
||||
- Each cache instance has `get()`, `set()`, `delete()`, and `clear()` methods
|
||||
|
||||
### [src/utils/asyncHandler.js](src/utils/asyncHandler.js)
|
||||
|
||||
Role:
|
||||
Small helper for async Express routes.
|
||||
|
||||
What it contains:
|
||||
- `asyncHandler()` wrapper
|
||||
|
||||
What it does:
|
||||
It catches rejected async route errors and forwards them to Express error middleware.
|
||||
|
||||
Why it matters:
|
||||
Without it, every async route would need repetitive `try/catch` blocks.
|
||||
|
||||
### [src/utils/json.js](src/utils/json.js)
|
||||
|
||||
Role:
|
||||
Small helper for parsing JSON values coming from MariaDB.
|
||||
|
||||
What it contains:
|
||||
- `parseJsonColumn()`
|
||||
|
||||
What it does:
|
||||
It safely converts JSON strings into objects and arrays.
|
||||
|
||||
Why it matters:
|
||||
Several database columns store JSON text, and this helper prevents the same parsing logic from being repeated in multiple files.
|
||||
|
||||
## SQL Folder
|
||||
Express wiring. Middleware stack in mount order:
|
||||
|
||||
1. `cors()` — wide-open CORS for PoC use
|
||||
2. `cookieParser()` — parses the `auth_token` cookie
|
||||
3. `express.json({ limit: '50mb' })` — accepts large base64 image payloads
|
||||
4. `noCacheHtml` — sets `Cache-Control: no-cache` on every HTML response so
|
||||
browsers revalidate page content after a Docker restart instead of
|
||||
serving a stale cached copy
|
||||
5. API routes under `/api/v1/`
|
||||
6. HTML page routes (`/`, `/login-admin`, `/login-user`, `/admin`, `/user`)
|
||||
7. `express.static(public/)` with `setHeaders` applying `no-cache` for
|
||||
`.html` files; JS/CSS use default ETag revalidation
|
||||
8. 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](src/config/env.js) — loads `.env` via `dotenv`, checks
|
||||
required keys, exposes a normalised `env` object.
|
||||
|
||||
### src/db/
|
||||
|
||||
- [src/db/pool.js](src/db/pool.js) — creates the shared MariaDB pool and
|
||||
exposes `query()` / `closePool()`.
|
||||
|
||||
### src/middleware/
|
||||
|
||||
- [src/middleware/authMiddleware.js](src/middleware/authMiddleware.js) —
|
||||
`requireAdminAuth`, `requireUserAuth`, `requireAnyAuth`. For API callers
|
||||
(detected via `req.originalUrl` / `Accept`) an unauthenticated response
|
||||
returns `401 JSON`; browser navigation is redirected to the relevant login
|
||||
page.
|
||||
- [src/middleware/errorHandler.js](src/middleware/errorHandler.js) —
|
||||
`notFoundHandler` and global `errorHandler` that convert everything to a
|
||||
consistent JSON shape.
|
||||
- [src/middleware/validateParams.js](src/middleware/validateParams.js) —
|
||||
regex / numeric URL-parameter guards used by route definitions.
|
||||
|
||||
### src/routes/
|
||||
|
||||
| File | Prefix | Notes |
|
||||
| --- | --- | --- |
|
||||
| [healthRoutes.js](src/routes/healthRoutes.js) | `/api/v1/health` | Liveness + DB ping. |
|
||||
| [authRoutes.js](src/routes/authRoutes.js) | `/api/v1/auth` | Admin/user login, logout, `me`. Issues the `auth_token` cookie. |
|
||||
| [adminRoutes.js](src/routes/adminRoutes.js) | `/api/v1/admin` | CRUD for every admin entity and `/all` bulk load. Gated by `requireAnyAuth`. |
|
||||
| [reportRoutes.js](src/routes/reportRoutes.js) | `/api/v1/reports` | Submit/get/list/delete reports and their images. Gated by `requireAnyAuth`. |
|
||||
| [configRoutes.js](src/routes/configRoutes.js) | `/api/v1/config` | Image-rules read/write (audit-logged) and export profile. |
|
||||
| [lookupRoutes.js](src/routes/lookupRoutes.js) | `/api/v1/lookups` | Reference lookup sets and values. |
|
||||
| [templateRoutes.js](src/routes/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](src/services/adminService.js) — everything under
|
||||
`admin_*` tables, plus the bulk `loadAllAdminData()` used by both the
|
||||
admin and user consoles.
|
||||
- [auditService.js](src/services/auditService.js) — writes to `audit_log`
|
||||
whenever something sensitive changes (report submit/delete, image rules
|
||||
update, template publish).
|
||||
- [authService.js](src/services/authService.js) — credential verification
|
||||
and an in-memory session `Map` with 24-hour expiry. Plain-text password
|
||||
comparison — PoC only.
|
||||
- [cacheService.js](src/services/cacheService.js) — generic LRU + TTL
|
||||
factory, pre-configured `templateCache`, `lookupCache`, `configCache`.
|
||||
- [configService.js](src/services/configService.js) — image rules and
|
||||
export profile queries. (Previous `app_config` helpers were removed along
|
||||
with the table.)
|
||||
- [lookupService.js](src/services/lookupService.js) — `lookup_sets` /
|
||||
`lookup_values`.
|
||||
- [reportService.js](src/services/reportService.js) — `reports` and
|
||||
`report_images`. Images are stored as `LONGBLOB` rows; list helpers
|
||||
group them by `record_id`.
|
||||
- [templateService.js](src/services/templateService.js) — template +
|
||||
`template_versions` queries and publish flow.
|
||||
|
||||
### src/utils/
|
||||
|
||||
- [asyncHandler.js](src/utils/asyncHandler.js) — wraps async route handlers
|
||||
so rejected promises reach the Express error middleware.
|
||||
- [json.js](src/utils/json.js) — safely parses JSON columns returned by
|
||||
MariaDB.
|
||||
|
||||
## sql/
|
||||
|
||||
### [sql/schema.sql](sql/schema.sql)
|
||||
|
||||
Role:
|
||||
Creates the database structure.
|
||||
Defines every table the app touches:
|
||||
|
||||
What it contains:
|
||||
- database creation
|
||||
- table definitions
|
||||
- keys and foreign keys
|
||||
|
||||
What it does:
|
||||
It defines how templates, lookups, image rules, export profiles, and app config are stored.
|
||||
- Template catalogue: `templates`, `template_versions`.
|
||||
- Reference data: `lookup_sets`, `lookup_values`, `image_rules`,
|
||||
`export_profiles`.
|
||||
- Reports: `reports` (answers as JSON) and `report_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](sql/seed.sql)
|
||||
|
||||
Role:
|
||||
Inserts example data.
|
||||
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.
|
||||
|
||||
What it contains:
|
||||
- one example checklist template
|
||||
- lookup values
|
||||
- one image policy
|
||||
- one export profile
|
||||
- app config values
|
||||
|
||||
What it does:
|
||||
It gives the frontend and API something real to work with immediately after startup.
|
||||
|
||||
## Scripts Folder
|
||||
## scripts/
|
||||
|
||||
### [scripts/test-environment.js](scripts/test-environment.js)
|
||||
|
||||
Role:
|
||||
Simple smoke test for the local environment.
|
||||
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.
|
||||
|
||||
What it contains:
|
||||
- API health checks
|
||||
- template endpoint checks
|
||||
- direct database checks
|
||||
- phpMyAdmin checks
|
||||
## Recommended reading order
|
||||
|
||||
What it does:
|
||||
It verifies that the main development services are working together.
|
||||
|
||||
When to use it:
|
||||
- after starting Docker containers
|
||||
- after changing infrastructure-related code
|
||||
- after big refactors when you want a quick confidence check
|
||||
|
||||
## Recommended Reading Order For A Junior Developer
|
||||
|
||||
If you are new to this project, a good reading order is:
|
||||
1. [README.md](README.md)
|
||||
2. [PROJECT_FILES_GUIDE.md](PROJECT_FILES_GUIDE.md)
|
||||
3. [src/server.js](src/server.js)
|
||||
4. [src/app.js](src/app.js)
|
||||
5. [src/routes/templateRoutes.js](src/routes/templateRoutes.js)
|
||||
6. [src/services/templateService.js](src/services/templateService.js)
|
||||
7. [public/js/constants.js](public/js/constants.js) and [public/js/state.js](public/js/state.js)
|
||||
8. [public/app.js](public/app.js) — the thin orchestrator that wires everything together
|
||||
9. [public/js/renderer.js](public/js/renderer.js) and [public/js/forms.js](public/js/forms.js)
|
||||
7. [public/index.html](public/index.html)
|
||||
8. [public/app.js](public/app.js)
|
||||
9. [sql/schema.sql](sql/schema.sql)
|
||||
10. [sql/seed.sql](sql/seed.sql)
|
||||
2. [docker-compose.yml](docker-compose.yml)
|
||||
3. [sql/schema.sql](sql/schema.sql)
|
||||
4. [src/server.js](src/server.js) → [src/app.js](src/app.js)
|
||||
5. [src/middleware/authMiddleware.js](src/middleware/authMiddleware.js)
|
||||
6. [src/routes/adminRoutes.js](src/routes/adminRoutes.js) and
|
||||
[src/services/adminService.js](src/services/adminService.js)
|
||||
7. [public/admin-app.js](public/admin-app.js) →
|
||||
[public/js/admin.js](public/js/admin.js)
|
||||
8. [public/user-app.js](public/user-app.js) →
|
||||
[public/js/user.js](public/js/user.js)
|
||||
|
||||
That order helps because it moves from the high-level entry points into the deeper details.
|
||||
## Quick "where do I look" rule
|
||||
|
||||
## Practical Rule Of Thumb
|
||||
|
||||
When you are trying to change something, use this shortcut:
|
||||
- if the browser layout looks wrong, check [public/index.html](public/index.html) and [public/styles.css](public/styles.css)
|
||||
- if browser behavior is wrong, check [public/app.js](public/app.js)
|
||||
- if an API endpoint is wrong, check [src/routes](src/routes) first and then [src/services](src/services)
|
||||
- if database data is wrong, check [sql/schema.sql](sql/schema.sql), [sql/seed.sql](sql/seed.sql), and the service file that runs the query
|
||||
- if the app does not start, check [src/server.js](src/server.js), [src/config/env.js](src/config/env.js), and [docker-compose.yml](docker-compose.yml)
|
||||
|
||||
This simple rule is often enough to help you find the right file quickly.
|
||||
- Page layout looks wrong → the relevant `.html` in [public/](public/) and
|
||||
[public/styles.css](public/styles.css).
|
||||
- Browser behaviour is wrong → `public/js/admin.js` or `public/js/user.js`,
|
||||
or the feature-specific module (`validation.js`, `images.js`, `exif.js`).
|
||||
- API endpoint is wrong → the matching file in [src/routes/](src/routes/),
|
||||
then the service it delegates to.
|
||||
- Data looks wrong → [sql/schema.sql](sql/schema.sql) and
|
||||
[sql/seed.sql](sql/seed.sql), plus the service file that owns the query.
|
||||
- App won't start → [src/server.js](src/server.js),
|
||||
[src/config/env.js](src/config/env.js), and
|
||||
[docker-compose.yml](docker-compose.yml).
|
||||
|
||||
Reference in New Issue
Block a user