Files
mcs-lose/README.md
2025-08-14 16:29:51 +02:00

151 lines
5.4 KiB
Markdown

# 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 <token>)
- 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 <token>`.
## 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.