From cca303c1f6573df7e53081bd64fc2b66f4375221 Mon Sep 17 00:00:00 2001 From: Theis Date: Wed, 20 May 2026 13:52:08 +0200 Subject: [PATCH] edited readme --- README.md | 193 +++++++++++++++++------------------------------------- 1 file changed, 59 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index 832848e..1fc927c 100644 --- a/README.md +++ b/README.md @@ -1,164 +1,89 @@ # CA-Lose -CA-Lose is a small full-stack app for collecting ticket-sale/order form entries. +Ticket intake and validation app with a React frontend and an Express + MySQL backend. -## Tech stack +## Tech Stack -![React](https://img.shields.io/badge/React-20232A?logo=react&logoColor=61DAFB) -![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=fff) -![Vite](https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=fff) -![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwindcss&logoColor=fff) -![MUI](https://img.shields.io/badge/MUI-007FFF?logo=mui&logoColor=fff) -![i18next](https://img.shields.io/badge/i18next-26A69A?logo=i18next&logoColor=fff) +![React](https://img.shields.io/badge/React-61DAFB?logo=react&logoColor=000&style=flat) +![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=fff&style=flat) +![Vite](https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=fff&style=flat) +![Tailwind%20CSS](https://img.shields.io/badge/Tailwind%20CSS-38B2AC?logo=tailwindcss&logoColor=fff&style=flat) +![MUI](https://img.shields.io/badge/MUI-007FFF?logo=mui&logoColor=fff&style=flat) +![React%20Query](https://img.shields.io/badge/React%20Query-FF4154?logo=reactquery&logoColor=fff&style=flat) +![React%20Router](https://img.shields.io/badge/React%20Router-CA4245?logo=reactrouter&logoColor=fff&style=flat) +![Node.js](https://img.shields.io/badge/Node.js-339933?logo=nodedotjs&logoColor=fff&style=flat) +![Express](https://img.shields.io/badge/Express-000000?logo=express&logoColor=fff&style=flat) +![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=fff&style=flat) +![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=fff&style=flat) +![Nginx](https://img.shields.io/badge/Nginx-009639?logo=nginx&logoColor=fff&style=flat) -![Node.js](https://img.shields.io/badge/Node.js-339933?logo=node.js&logoColor=fff) -![Express](https://img.shields.io/badge/Express-000000?logo=express&logoColor=fff) -![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=fff) +## Project Structure -![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=fff) -![Nginx](https://img.shields.io/badge/Nginx-009639?logo=nginx&logoColor=fff) +- Frontend (Vite + React + Tailwind + MUI): [frontend](frontend) +- Backend (Express): [backend](backend) +- Database schema: [backend/scheme.sql](backend/scheme.sql) +- Docker compose stack: [docker-compose.yml](docker-compose.yml) -## Architecture +## Quick Start (Docker) -- **Frontend**: React + TypeScript + Vite (UI uses MUI + Tailwind, i18n via i18next) -- **Backend**: Node.js + Express (also renders a minimal EJS page at `/`) -- **Database**: MySQL 8 - -In production, the frontend is served by **Nginx** and proxies `/backend/*` to the backend container. - -## Repos & folders - -``` -backend/ # Express API + EJS views -frontend/ # React app (Vite) + Nginx container -docker-compose.yml -docker-compose.prod.yml -``` - -## API overview - -The backend router is mounted at `/default`: - -- `GET /default/users` → returns `{ users: string[] }` -- `GET /default/confirm-user?username=` → validates user and returns metadata (e.g. next id) -- `POST /default/new-entry?username=` → stores a new entry in MySQL - -## Configuration - -### Backend environment variables - -The backend reads configuration from environment variables (and can also load a `backend/.env` file via `dotenv`). - -- `PORT` (e.g. `8004`) -- `DB_HOST` (e.g. `ca-lose-mysql` when using Docker Compose) -- `DB_USER` (e.g. `root`) -- `DB_PASSWORD` -- `DB_NAME` (e.g. `ca_lose`) - -### Docker Compose environment - -Both compose files expect `DB_PASSWORD` to be present in your shell environment or a root `.env` file. - -Create a root `.env` (not committed) like: - -```env -DB_PASSWORD=change-me -``` - -## Local development - -### Option A: Docker Compose (backend + database) - -This is the quickest way to get the API + MySQL running. +1. Set the database password env var used by Docker Compose: ```bash -docker compose up --build +export DB_PASSWORD=your_password ``` -What you get: - -- Backend: http://localhost:8004 -- MySQL: localhost:3311 (container port 3306) - -Note: In `docker-compose.yml` the `frontend` service is currently commented out. - -### Option B: Run frontend locally (Vite) + run backend & DB - -1. Start DB + backend (Docker): +2. Start MySQL and the backend: ```bash -docker compose up --build database backend -``` - -2. Start frontend (local Node): - -```bash -cd frontend -npm ci -npm run dev -``` - -Open the Vite dev server URL (usually http://localhost:5173). - -Important: - -- During local development (Vite), the frontend currently calls the backend via a hard-coded URL (`http://localhost:8004`). -- When the frontend is served by the Nginx container, requests are expected to go through the Nginx proxy at `/backend/*` (see `frontend/nginx.conf`). In that setup the frontend should use `/backend/default/...` instead of `http://localhost:8004/...`. - -## Database setup - -The schema file is in `backend/scheme.sql`. - -- The `users` table is required for the user dropdown. -- The backend creates an entry table dynamically per user and date when calling `GET /default/confirm-user`. - -Example (inside MySQL): - -```sql -INSERT INTO users (username, first_name, last_name) -VALUES ('demo', 'Demo', 'User'); -``` - -## Production / Deployment - -The production compose file builds and runs: - -- `frontend` (Nginx) -- `backend` (Express) -- `database` (MySQL) -- optional infrastructure: `dnsmasq` and `wireguard` (wg-easy) - -Start it: - -```bash -docker compose -f docker-compose.prod.yml up -d --build +docker compose up -d ``` Notes: -- `docker-compose.prod.yml` uses an **external** network called `proxynet`. Create it if it does not exist: +- The frontend service is commented out in [docker-compose.yml](docker-compose.yml). If you want the frontend container, uncomment that block and rebuild. +- The frontend container uses Nginx and proxies /backend to the backend service (see [frontend/nginx.conf](frontend/nginx.conf)). - ```bash - docker network create proxynet - ``` +## Local Development -- The production file assigns static IPs; adjust the subnets/IPs if they conflict with your environment. +### Backend -## Lint / build +1. Create a .env file in the backend folder with: -Frontend: +```env +PORT=8004 +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASSWORD=your_password +DB_NAME=ca_lose +``` + +2. Install deps and run: + +```bash +cd backend +npm install +node server.js +``` + +Backend listens on http://localhost:8004 and exposes routes under /default. + +### Frontend ```bash cd frontend -npm run lint -npm run build +npm install +npm run dev ``` -## Troubleshooting +Vite runs the app on the default dev port and talks to the backend using the API helpers in [frontend/src/utils/api](frontend/src/utils/api). -- **Backend does not start / ESM imports**: The backend code uses ESM `import` syntax. Node must treat the backend as an ESM project (commonly by adding `"type": "module"` to `backend/package.json`). Without that, the backend will fail to start (including in Docker). -- **MySQL timezone mount**: The compose files mount `./mysql-timezone.cnf` to `/etc/mysql/conf.d/timezone.cnf`. Ensure `mysql-timezone.cnf` is a file (not a directory) with valid MySQL config, or remove/adjust the mount. +## API Endpoints -## License +- GET /default/users +- GET /default/confirm-user?username={name} +- POST /default/new-entry?username={name} -Licensed under the Apache License 2.0. See [LICENSE](LICENSE). +## Database Notes + +- The base users table is defined in [backend/scheme.sql](backend/scheme.sql). +- Per-user ticket tables are created on demand by the backend (see [backend/routes/default/frontend.data.js](backend/routes/default/frontend.data.js)).