modified version

This commit is contained in:
Stan
2026-04-21 23:26:13 +02:00
parent e7127f3215
commit bdd06105dd
46 changed files with 1250 additions and 5248 deletions
+269 -641
View File
@@ -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).