Remove PostgreSQL and move to SQLite3
This commit is contained in:
@@ -1,2 +1,217 @@
|
||||
# cluedo-hp-webapp
|
||||
# Cluedo HP Webapp
|
||||
|
||||
A small multiplayer web app that acts as a digital note sheet for a Harry Potter-inspired Cluedo game. Several logged-in players can join the same game and manage their personal clues independently.
|
||||
|
||||
## Features
|
||||
|
||||
- Login with user and admin roles
|
||||
- Admin-managed user creation and deactivation
|
||||
- Multiple games per user
|
||||
- Join games using a short join code
|
||||
- Automatic player list with host indication
|
||||
- Personal note sheet for each player and game
|
||||
- Categories for suspects, items, and locations
|
||||
- Entry status tracking: empty, ruled out, present, or maybe
|
||||
- Additional notes using `i`, `m`, and `s.<chip>`
|
||||
- Winner selection by the game host
|
||||
- Winner badge and confetti animation for all players
|
||||
- Live updates for new players and winner changes
|
||||
- Personal game statistics
|
||||
- Password change functionality
|
||||
- Harry Potter house themes: Default, Gryffindor, Slytherin, Ravenclaw, and Hufflepuff
|
||||
- Installable as a Progressive Web App
|
||||
|
||||
## Technology
|
||||
|
||||
### Frontend
|
||||
|
||||
- React 18
|
||||
- Vite
|
||||
- Nginx as the production web server
|
||||
- `canvas-confetti` for the winner animation
|
||||
- `vite-plugin-pwa` for PWA support
|
||||
|
||||
### Backend
|
||||
|
||||
- Python 3.12
|
||||
- FastAPI
|
||||
- SQLAlchemy 2
|
||||
- SQLite 3
|
||||
- Passlib and bcrypt for password hashing
|
||||
|
||||
### Deployment
|
||||
|
||||
- Docker Compose
|
||||
- Frontend on port `8081`
|
||||
- Backend on port `8080`
|
||||
- SQLite database stored in a persistent Docker volume
|
||||
|
||||
## Quick start with Docker
|
||||
|
||||
Requirements:
|
||||
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
1. Copy `.env.example` to `.env` and set a strong secret:
|
||||
|
||||
```env
|
||||
BACKEND_SECRET_KEY=use-a-long-random-secret-value
|
||||
```
|
||||
|
||||
2. Build and start the containers:
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
3. Open the application:
|
||||
|
||||
- Frontend: http://localhost:8081
|
||||
- Backend/API: http://localhost:8080
|
||||
|
||||
On the first startup, the application opens a setup screen where you create the first administrator with an email address, display name, and password. The default suspects, items, and locations are seeded automatically as well.
|
||||
|
||||
The SQLite database is stored in the Docker volume `cluedo-data` and survives normal container restarts.
|
||||
|
||||
Start the containers in the background:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
Stop the containers:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## Local development without Docker
|
||||
|
||||
### Backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
export DATABASE_URL=sqlite:///./data/cluedo.db
|
||||
export SECRET_KEY=use-a-long-random-secret-value
|
||||
|
||||
uvicorn app.main:app --reload --port 8080
|
||||
```
|
||||
|
||||
On Windows PowerShell, set the environment variables like this:
|
||||
|
||||
```powershell
|
||||
$env:DATABASE_URL = "sqlite:///./data/cluedo.db"
|
||||
$env:SECRET_KEY = "use-a-long-random-secret-value"
|
||||
uvicorn app.main:app --reload --port 8080
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The frontend is normally available at http://localhost:5173. During development, the API must be reachable under `/api`; the production Docker setup provides this through Nginx.
|
||||
|
||||
Create a production build:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Project structure
|
||||
|
||||
```text
|
||||
.
|
||||
├── backend/
|
||||
│ ├── app/
|
||||
│ │ ├── main.py # FastAPI app, startup, seed data
|
||||
│ │ ├── models.py # SQLAlchemy models
|
||||
│ │ ├── db.py # SQLite engine and sessions
|
||||
│ │ ├── security.py # Password and cookie logic
|
||||
│ │ └── routes/ # Auth, admin, and game APIs
|
||||
│ ├── Dockerfile
|
||||
│ └── requirements.txt
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── App.jsx # Main UI and game flow
|
||||
│ │ ├── api/client.js # API client
|
||||
│ │ ├── components/ # Pages, cards, and modals
|
||||
│ │ ├── styles/ # Themes and inline styles
|
||||
│ │ └── utils/ # Small helpers and storage utilities
|
||||
│ ├── Dockerfile
|
||||
│ └── nginx.conf
|
||||
├── docker-compose.yml
|
||||
└── .env
|
||||
```
|
||||
|
||||
## Data model
|
||||
|
||||
- `users`: users, roles, status, display names, and themes
|
||||
- `games`: game name, join code, host, and winner
|
||||
- `game_members`: assignment of users to games
|
||||
- `entries`: seeded suspects, items, and locations
|
||||
- `sheet_state`: personal status and notes for an entry
|
||||
|
||||
Each player has their own set of `sheet_state` records for every game. A player's notes are therefore not visible to other players.
|
||||
|
||||
## API overview
|
||||
|
||||
### Authentication
|
||||
|
||||
- `POST /auth/login`
|
||||
- `POST /auth/logout`
|
||||
- `GET /auth/me`
|
||||
- `PATCH /auth/password`
|
||||
- `PATCH /auth/theme`
|
||||
- `GET /auth/me/stats`
|
||||
|
||||
### First-run setup
|
||||
|
||||
- `GET /setup/status`
|
||||
- `POST /setup/admin`
|
||||
|
||||
The setup endpoint is available only while no administrator exists. After the first administrator has been created, the setup screen is disabled automatically.
|
||||
|
||||
### Administration
|
||||
|
||||
- `GET /admin/users`
|
||||
- `POST /admin/users`
|
||||
- `DELETE /admin/users/{user_id}` – deactivates a user
|
||||
|
||||
### Games
|
||||
|
||||
- `GET /games`
|
||||
- `POST /games`
|
||||
- `POST /games/join`
|
||||
- `GET /games/{game_id}`
|
||||
- `GET /games/{game_id}/members`
|
||||
- `PATCH /games/{game_id}/winner`
|
||||
- `GET /games/{game_id}/sheet`
|
||||
- `PATCH /games/{game_id}/sheet/{entry_id}`
|
||||
|
||||
## SQLite notes
|
||||
|
||||
SQLite is a good fit for this application: the data volume is small, the app is intended for internal use, and write operations are short. The database file is stored inside the container at `/app/data/cluedo.db` and persisted through the `cluedo-data` volume.
|
||||
|
||||
For larger deployments with many concurrent write operations, PostgreSQL would still be the more robust choice. For the intended private or small-group use case, SQLite is sufficient.
|
||||
|
||||
## Security notes
|
||||
|
||||
- The values in `.env` are examples and should be changed before production use.
|
||||
- When using HTTPS, set `COOKIE_SECURE` to `true`.
|
||||
- The application is intended for an internal or small user group.
|
||||
- The automatic database migration is intentionally pragmatic and does not replace a migration system such as Alembic.
|
||||
|
||||
Reference in New Issue
Block a user