Repository navigation
Backend API
backend/ is an Express 4 API (ES modules) backed by MySQL. It is complete enough to serve events,
reviews and enquiries, but it is not deployed and the live frontend does not call it. Everything
here applies when you run it locally or deploy it yourself.
Base URL: http://localhost:5000/api by default.
| Method | Path | Validation / limits | Behaviour |
|---|---|---|---|
| GET | /health |
- | { status: "OK" } |
| GET | /reviews |
- | All reviews, newest first. Cached for 1 hour when Redis is enabled |
| POST | /reviews |
name, message, rating (1 to 5); 5 requests per 15 minutes per IP |
Inserts a review and clears the cached list |
| GET | /events |
- | Events dated today or later. Cached for 30 minutes when Redis is enabled |
| GET | /events/:id |
- | One event |
| POST | /events |
title, date, location, optional description
|
Creates an event |
| PUT | /events/:id |
same as POST | Updates an event |
| DELETE | /events/:id |
- | Deletes an event |
| POST | /enquiry |
name, email, optional phone, message; 10 requests per 15 minutes per IP |
Trims and length-limits the fields, stores the enquiry, then emails a notification if SMTP is configured |
Validation rules live in src/utils/validation.js (express-validator). Text fields are trimmed,
length-checked and HTML-escaped, and emails are normalised. Failed validation returns
400 { error: "Validation failed", details: [...] }. Unknown routes return 404 { error: "Route not found" }, and other
errors go through src/middleware/errorHandler.js.
The event write routes have no authentication. Add an auth layer (or remove the routes) before exposing the API publicly.
src/config/database.js creates a mysql2/promise pool (10 connections, SSL when DB_SSL=true).
src/models/initDatabase.js runs on every start and creates the tables if they do not exist:
| Table | Columns |
|---|---|
reviews |
id, name, message, rating (1 to 5), created_at
|
events |
id, title, date, location, image, description, created_at, updated_at
|
enquiries |
id, name, phone, email, message, created_at
|
All queries use prepared statements (pool.execute with ? placeholders). There are no migrations
beyond CREATE TABLE IF NOT EXISTS, so column changes must be applied by hand.
src/controllers/enquiryController.js builds a Nodemailer SMTP transport from EMAIL_HOST,
EMAIL_PORT (default 587), EMAIL_USER and EMAIL_PASS. When EMAIL_USER and EMAIL_PASS are set,
each enquiry is emailed to the client's address. A failed email is logged and does not fail the request.
src/utils/cache.js connects to Redis only when REDIS_ENABLED=true and REDIS_URL is set. If Redis
is missing or the connection fails, every cache call returns null or false and the API works
without caching.
-
helmetwith a Content Security Policy (default-src 'self', images fromself,data:andhttps:), cross-origin resource policy set tocross-origin -
corsallowing onlyFRONTEND_URL(any origin whenNODE_ENV=development), with credentials - JSON and URL-encoded bodies limited to 10 MB
- Graceful shutdown on
SIGTERM/SIGINTcloses Redis and the MySQL pool
EUPHORIC LIVE