diff --git a/README.md b/README.md index dd7b74b..8bd44e5 100644 --- a/README.md +++ b/README.md @@ -1 +1,150 @@ -# MCS Lose \ No newline at end of file +# MCS Lose + +A small full-stack demo app to manage "Lose" entries (Losnummer records) using a React + TypeScript frontend, an Express (Node) backend, and a MySQL database. The project is containerised with Docker Compose for easy local development. + +## Quick overview + +- Backend: Express.js (ES Modules), serves JSON APIs and EJS root view. +- Frontend: React + TypeScript + Vite (UI for importing CSVs and managing entries). +- Database: MySQL 8.0 with a simple schema (`lose` and `admin_user`). +- Orchestration: `docker-compose.yml` to run backend and MySQL (frontend is prepared but commented out in compose). + +## Goals + +- Import and manage losnummer (ticket) entries. +- Allow admins to login and perform protected operations (create, delete, update rows). +- Keep the setup easy to run locally via Docker. + +## Prerequisites + +- Docker & Docker Compose (tested on macOS in this workspace). +- Alternatively, Node 18+ and npm/yarn to run services locally without containers. + +## Quick start (recommended: Docker) + +Start backend + MySQL using Docker Compose: + +```zsh +docker compose up -d --build +``` + +Stop and remove containers: + +```zsh +docker compose down +``` + +The backend will be available at http://localhost:8002 by default (see `docker-compose.yml`). MySQL is exposed on host port 3308 -> container 3306. + +## Running services locally (without Docker) + +Backend + +```zsh +cd backend +npm install +# set env vars (see Environment section) or create a .env file +npm start +``` + +Frontend + +```zsh +cd frontend +npm install +npm run dev +``` + +## Environment variables + +The backend reads configuration from environment variables (some are present in `docker-compose.yml`): + +- DB_HOST - MySQL host (e.g. `mysql` in compose) +- DB_USER - MySQL user (`root` in compose) +- DB_PASSWORD - MySQL root password +- DB_NAME - MySQL database name (e.g. `mcs_lose`) +- SECRET_KEY - secret used to sign JWT tokens (required for authentication) + +Important: do not commit secrets to source control. In production, provide `SECRET_KEY` through a secure secret manager. + +## API (backend) + +All endpoints are served by the Express backend in `backend/server.js`. + +Public + +- GET / — renders `index.ejs` (simple root view) +- POST /lose — accepts an update payload and attempts a conditional UPDATE on `lose` rows (no auth) +- POST /login — admin login; returns a JWT token on success + +Protected (require Authorization: Bearer ) + +- GET /table-data — returns all rows from `lose` +- POST /create-entry — bulk-insert losnummer values (body: { losnummer: [...] }) +- DELETE /remove-entries — delete rows by losnummer (body: { losnummern: [...] }) +- PUT /save-row — update a single row (body contains row fields) +- DELETE /reset-data — delete all rows from `lose` + +Authentication + +- Tokens are generated using `jose` and signed with `SECRET_KEY` in `backend/services/tokenService.js`. +- The `authenticate` middleware expects an `Authorization` header with `Bearer `. + +## Database schema + +Schema available in `backend/scheme.sql` — main tables: + +- `lose` (columns): + - `losnummer` VARCHAR(255) UNIQUE + - `vorname`, `nachname`, `adresse`, `plz`, `email` (nullable) +- `admin_user` (columns): `username` (unique), `password` (plain text in current implementation) + +Notes: + +- The current SQL uses simple types and a single `losnummer` unique constraint. Consider adding an auto-increment id column if needed. + +## Project structure (high level) + +- backend/ + + - `server.js` — Express app, routes and middleware + - `services/database.js` — MySQL pool and query helpers + - `services/tokenService.js` — token generation and authentication middleware + - `scheme.sql` — DDL for tables + +- frontend/ + + - React + TypeScript app scaffolded with Vite + - `src/components` — UI components (Admin, Table, Import GUI, Forms) + +- docker-compose.yml — config for backend and MySQL containers + +## Notable implementation details & known issues + +- Body size limits are increased in `server.js` to accept large CSV/JSON payloads (limit: 10mb). +- Passwords for `admin_user` are stored and checked as plaintext in `database.js` — this is insecure. Use salted password hashing (bcrypt) for real deployments. +- `tokenService.js` currently logs the generated token to console — remove that in production. +- `getTableData()` in `services/database.js` has an incorrect code path checking `result.entries.length` (should check `result.length`). This may cause unexpected behavior when the table is empty. +- Queries use parameterized queries with `mysql2` which protects against SQL injection for provided query parameters. + +## Suggestions / TODOs + +- Fix the `getTableData()` empty-check bug. +- Hash admin passwords and add a registration/migration path for admin accounts. +- Add input validation on API endpoints and better error handling/user feedback. +- Consider adding database migrations (Flyway, knex, sequelize migrations). +- Add tests and CI for backend endpoints. +- Optionally enable the frontend service in `docker-compose.yml` (it's currently commented out). + +## Development tips + +- To inspect the MySQL data created by Docker Compose, you can connect with your preferred MySQL client to `localhost:3308` (user and password from `docker-compose.yml`). +- To generate a token from the backend for testing, create an admin user entry in `admin_user` and POST to `/login`. + +## License + +No license specified. Add a LICENSE file if you want to open-source this project. + +## Contacts / credits + +Project created in this workspace. See `backend` and `frontend` folders for authorship and details.