🐐 Several security fixes
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# WikiTCG
|
||||
|
||||
A trading card game where every card is procedurally generated from a Wikipedia
|
||||
article. Players open booster packs, build decks, trade with each other, and
|
||||
play real-time matches over WebSocket.
|
||||
|
||||
- **Backend** — FastAPI (`backend/`), PostgreSQL, SQLAlchemy + Alembic
|
||||
- **Frontend** — SvelteKit with the static adapter (`frontend/`)
|
||||
- **External** — Wikipedia API (card generation), Resend (email), Stripe (payments)
|
||||
|
||||
## Running locally
|
||||
|
||||
```bash
|
||||
# Backend — dev server on :8000
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
uvicorn main:app --reload
|
||||
|
||||
# Frontend — dev server on :5173
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Tests and checks:
|
||||
|
||||
```bash
|
||||
cd backend && pytest test_game.py # game logic
|
||||
cd frontend && npm run check # svelte-check
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
The stack runs as three Docker Compose services (`db`, `backend`, `frontend`)
|
||||
behind Nginx Proxy Manager. No service publishes a port; NPM reaches the
|
||||
containers by name over an external `proxy` network. The database sits on a
|
||||
second network marked `internal: true`, so it has no route off the host.
|
||||
|
||||
```bash
|
||||
git pull && docker compose up -d --build
|
||||
```
|
||||
|
||||
## Database and migrations
|
||||
|
||||
The database has **two roles, and they are not interchangeable**:
|
||||
|
||||
| Role | Used by | Rights |
|
||||
| --- | --- | --- |
|
||||
| `wikitcg_app` | the running app, via `DATABASE_URL` | SELECT/INSERT/UPDATE/DELETE — no DDL |
|
||||
| `wikitcg` | Alembic only, via `MIGRATION_DATABASE_URL` | owns the schema |
|
||||
|
||||
Migrations therefore run as `wikitcg`, never as the app role:
|
||||
|
||||
```bash
|
||||
docker compose run --rm backend alembic upgrade head # apply
|
||||
docker compose run --rm backend alembic revision --autogenerate -m "description"
|
||||
```
|
||||
|
||||
`alembic/env.py` reads `MIGRATION_DATABASE_URL` and **fails loudly if it is
|
||||
unset**. There is deliberately no fallback to `DATABASE_URL`: the app role has no
|
||||
DDL rights, so falling back would surface as a confusing permissions error partway
|
||||
through a migration instead of an obvious configuration error up front.
|
||||
|
||||
`sqlalchemy.url` in `alembic.ini` is intentionally empty — the URL comes from the
|
||||
environment so no credential lives in version control.
|
||||
|
||||
The split needs no sequence grants: every primary key is either a
|
||||
client-generated UUID or a string.
|
||||
|
||||
## Environment variables
|
||||
|
||||
Set in `.env` at the repo root (untracked). See `backend/core/config.py`.
|
||||
|
||||
**Required** — the app refuses to start without these:
|
||||
|
||||
| Variable | Notes |
|
||||
| --- | --- |
|
||||
| `JWT_SECRET_KEY` | signing key for access and refresh tokens |
|
||||
| `DATABASE_URL` | app role (`wikitcg_app`) |
|
||||
| `RESEND_API_KEY`, `EMAIL_FROM` | transactional email |
|
||||
| `STRIPE_SECRET_KEY`, `STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET` | payments |
|
||||
|
||||
**Required for migrations:**
|
||||
|
||||
| Variable | Notes |
|
||||
| --- | --- |
|
||||
| `MIGRATION_DATABASE_URL` | schema owner (`wikitcg`) — Alembic only |
|
||||
|
||||
**Optional:**
|
||||
|
||||
| Variable | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `FRONTEND_URL` | `http://localhost:5173` | links in outbound email |
|
||||
| `CORS_ORIGINS` | `http://localhost:5173` | comma-separated |
|
||||
| `WIKIRANK_USER_AGENT` | `WikiTCG/1.0` | sent to the Wikipedia API |
|
||||
| `ENABLE_DOCS` | unset (disabled) | set to exactly `true` to serve `/docs`, `/redoc` and `/openapi.json`. Any other value leaves them disabled, so a new environment fails closed. |
|
||||
Reference in New Issue
Block a user