245 lines
6.8 KiB
Markdown
245 lines
6.8 KiB
Markdown
|
|
# Pokedexter ⚡
|
||
|
|
|
||
|
|
Pokémon TCG-samlerwebapp — bygget med **FastAPI**, **PostgreSQL**, **Nginx** og **Docker**.
|
||
|
|
|
||
|
|
Administratorer opretter serier, kort og brugere. Brugere kan logge ind, browse og søge. Ingen åben registrering.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Arkitektur
|
||
|
|
|
||
|
|
```
|
||
|
|
Browser ──► Nginx (:8080) ──► FastAPI (:8000) ──► PostgreSQL (:5432)
|
||
|
|
▲ │
|
||
|
|
└─── static/ ───────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
- **Nginx** — reverse proxy, serverer statiske filer
|
||
|
|
- **FastAPI** — async Python backend, Jinja2 templates
|
||
|
|
- **PostgreSQL 16** — database med SQLAlchemy (async)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Kom i gang
|
||
|
|
|
||
|
|
### Docker
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose up -d --build
|
||
|
|
```
|
||
|
|
|
||
|
|
### Podman
|
||
|
|
|
||
|
|
```bash
|
||
|
|
./start.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
### Stop
|
||
|
|
|
||
|
|
```bash
|
||
|
|
./stop.sh # podman
|
||
|
|
docker compose down # docker
|
||
|
|
```
|
||
|
|
|
||
|
|
Data i `pgdata`-volumen bevares mellem genstarter.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Login
|
||
|
|
|
||
|
|
| Brugernavn | Adgangskode | Rolle |
|
||
|
|
|------------|-------------|-------|
|
||
|
|
| `admin` | `admin123` | Admin |
|
||
|
|
|
||
|
|
Brugeren oprettes automatisk ved første opstart. Skift adgangskoden efter første login.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Sådan bruges det
|
||
|
|
|
||
|
|
### Opret en serie (set)
|
||
|
|
|
||
|
|
1. Log ind på `/login` med `admin` / `admin123`
|
||
|
|
2. Gå til **Admin → Serier**
|
||
|
|
3. Indtast **kode** (f.eks. `CRI`) og **navn** (f.eks. `Chaos Rising`)
|
||
|
|
4. Tryk **Opret**
|
||
|
|
|
||
|
|
### Tilføj kort til en serie
|
||
|
|
|
||
|
|
1. Gå til **Admin → Serier**
|
||
|
|
2. Klik **Vis kort** på det ønskede sæt
|
||
|
|
3. Udfyld kortets detaljer (nummer, navn, type, sjældenhed, HP, stadie)
|
||
|
|
4. Tryk **Tilføj kort**
|
||
|
|
|
||
|
|
Eksempel:
|
||
|
|
|
||
|
|
| Felt | Værdi |
|
||
|
|
|------------|-----------------|
|
||
|
|
| Nummer | `068` |
|
||
|
|
| Navn | `Chaos Dragon` |
|
||
|
|
| Type | `Dragon` |
|
||
|
|
| Rarity | `Rare` |
|
||
|
|
| HP | `120` |
|
||
|
|
| Stadie | `Basic` |
|
||
|
|
|
||
|
|
Kortet får automatisk koden `CRI-068`.
|
||
|
|
|
||
|
|
### Opret brugere (admin)
|
||
|
|
|
||
|
|
API — ingen HTML-side endnu:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -X POST http://localhost:8080/api/admin/users \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-b "token=DIN_JWT_TOKEN" \
|
||
|
|
-d '{"username":"glenn","password":"hemmeligt","role":"user"}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### Browse kort
|
||
|
|
|
||
|
|
- `/sets` — liste alle serier
|
||
|
|
- `/sets/CRI` — se alle kort i serie `CRI`
|
||
|
|
- `/card/CRI-068` — detaljer om et specifikt kort
|
||
|
|
|
||
|
|
### Søg
|
||
|
|
|
||
|
|
- `/search?q=CRI-068` — søg på fuld kortkode
|
||
|
|
- `/search?q=dragon` — søg på kortnavn
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## API-oversigt
|
||
|
|
|
||
|
|
### Offentlige endpoints
|
||
|
|
|
||
|
|
| Metode | Sti | Beskrivelse |
|
||
|
|
|--------|----------------|------------------------|
|
||
|
|
| GET | `/` | Forside |
|
||
|
|
| GET | `/sets` | Liste alle serier |
|
||
|
|
| GET | `/sets/{code}` | Kort i en serie |
|
||
|
|
| GET | `/search` | Søgeside |
|
||
|
|
| GET | `/api/search` | Søg (JSON) |
|
||
|
|
| GET | `/api/cards/{full_code}` | Enkelt kort (JSON) |
|
||
|
|
|
||
|
|
### Auth endpoints
|
||
|
|
|
||
|
|
| Metode | Sti | Beskrivelse |
|
||
|
|
|--------|----------------|------------------------------|
|
||
|
|
| GET | `/login` | Loginside |
|
||
|
|
| POST | `/api/login` | Login (sætter cookie) |
|
||
|
|
| GET | `/logout` | Logout |
|
||
|
|
|
||
|
|
### Admin endpoints (kræver admin)
|
||
|
|
|
||
|
|
| Metode | Sti | Beskrivelse |
|
||
|
|
|--------|-------------------------------------|--------------------------------|
|
||
|
|
| GET | `/admin` | Admin dashboard |
|
||
|
|
| GET | `/admin/sets` | Administrér serier |
|
||
|
|
| GET | `/admin/cards/{code}` | Administrér kort i serie |
|
||
|
|
| POST | `/api/admin/users` | Opret bruger |
|
||
|
|
| GET | `/api/admin/users` | List brugere |
|
||
|
|
| POST | `/api/admin/sets` | Opret serie |
|
||
|
|
| GET | `/api/admin/sets` | List serier |
|
||
|
|
| DELETE | `/api/admin/sets/{id}` | Slet serie |
|
||
|
|
| POST | `/api/admin/sets/{code}/cards` | Opret kort |
|
||
|
|
| GET | `/api/admin/sets/{code}/cards` | List kort i serie |
|
||
|
|
| DELETE | `/api/admin/cards/{id}` | Slet kort |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Datamodel
|
||
|
|
|
||
|
|
```
|
||
|
|
User
|
||
|
|
id Integer (PK)
|
||
|
|
username String (unique)
|
||
|
|
password_hash String (bcrypt)
|
||
|
|
role String ("admin" | "user")
|
||
|
|
created_at DateTime
|
||
|
|
|
||
|
|
Set
|
||
|
|
id Integer (PK)
|
||
|
|
code String (unique) — "CRI"
|
||
|
|
name String — "Chaos Rising"
|
||
|
|
release_date String (optional)
|
||
|
|
description Text (optional)
|
||
|
|
created_at DateTime
|
||
|
|
cards ► Card[]
|
||
|
|
|
||
|
|
Card
|
||
|
|
id Integer (PK)
|
||
|
|
set_id Integer (FK → sets.id)
|
||
|
|
number String — "068"
|
||
|
|
name String — "Chaos Dragon"
|
||
|
|
type String — "Dragon", "Fire", ...
|
||
|
|
rarity String — "Common", "Uncommon", "Rare", ...
|
||
|
|
hp Integer
|
||
|
|
stage String — "Basic", "Stage 1", "Stage 2"
|
||
|
|
description Text
|
||
|
|
image_url String (optional)
|
||
|
|
set ► Set
|
||
|
|
full_code [property] — "CRI-068"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Miljøvariable
|
||
|
|
|
||
|
|
| Variabel | Standard | Beskrivelse |
|
||
|
|
|---------------|----------------------------------|----------------------|
|
||
|
|
| `DATABASE_URL` | `postgresql+asyncpg://...` | PostgreSQL forbindelse |
|
||
|
|
| `SECRET_KEY` | `skift-mig-til-en-sikker-noegle` | JWT signeringsnøgle |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Projektstruktur
|
||
|
|
|
||
|
|
```
|
||
|
|
pokedexter/
|
||
|
|
├── docker-compose.yml
|
||
|
|
├── start.sh # podman start
|
||
|
|
├── stop.sh # podman stop
|
||
|
|
├── backend/
|
||
|
|
│ ├── Dockerfile
|
||
|
|
│ ├── requirements.txt
|
||
|
|
│ └── app/
|
||
|
|
│ ├── main.py # FastAPI app, middleware
|
||
|
|
│ ├── database.py # async engine + session
|
||
|
|
│ ├── models.py # SQLAlchemy modeller
|
||
|
|
│ ├── auth.py # bcrypt + JWT
|
||
|
|
│ ├── routers/
|
||
|
|
│ │ ├── auth.py # login/logout + admin user mgmt
|
||
|
|
│ │ ├── admin.py # admin CRUD for sets/cards
|
||
|
|
│ │ └── cards.py # browse + search
|
||
|
|
│ ├── templates/ # Jinja2 HTML templates
|
||
|
|
│ └── static/ # CSS, JS, billeder
|
||
|
|
├── nginx/
|
||
|
|
│ ├── Dockerfile
|
||
|
|
│ └── nginx.conf
|
||
|
|
└── db/
|
||
|
|
└── init.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Udvikling
|
||
|
|
|
||
|
|
Genstart backend efter kodeændringer:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose up -d --build backend
|
||
|
|
# eller med podman:
|
||
|
|
podman stop pokedexter-backend && podman rm pokedexter-backend
|
||
|
|
podman build -t pokedexter-backend ./backend
|
||
|
|
# ... og kør igen med podman run ...
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Planlagte features
|
||
|
|
|
||
|
|
- [ ] Personlig mappe — brugere kan markere kort de ejer/samler
|
||
|
|
- [ ] Kortbilleder (upload eller URL)
|
||
|
|
- [ ] Filtrering på type, sjældenhed, HP
|
||
|
|
- [ ] Dark mode toggle gemt i localStorage *(done)*
|
||
|
|
- [ ] Mobilvenlig navigation *(done)*
|