Files
CLProject/PROJECT_FILES_GUIDE.md
T
2026-04-21 23:26:13 +02:00

305 lines
14 KiB
Markdown

# Project Files Guide
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.
## How the application is organised
There are three parts:
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.
### End-to-end request flow (simplified)
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)
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)
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)
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)
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)
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) 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)
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](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
1. [README.md](README.md)
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)
## Quick "where do I look" rule
- 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).