docs: SMOKE_TEST.md — verifizierter E2E-Lauf gegen lokale Postgres
Phase-3-Verifikation 2026-05-08: - Drizzle push erfolgreich: 8 Tabellen, 11 Indizes, 6 FKs in Schema `cards` - E2E-Flow durchgespielt: Deck-Create, Card-Create (basic-reverse, 2 Auto-Reviews), Reviews-Due, FSRS-Grade (state new→learning, stability 0→2.3, learning_steps 0→1), Cross-User-Schutz (403), Cascade-Delete (Deck→Cards→Reviews alle 0) - Type-Check + 46 Vitest-Tests grün Runbook für reproduzierbaren Lauf in docs/SMOKE_TEST.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5f67bd9f3e
commit
e3b3a2b478
1 changed files with 111 additions and 0 deletions
111
docs/SMOKE_TEST.md
Normal file
111
docs/SMOKE_TEST.md
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
# Smoke-Test Runbook
|
||||||
|
|
||||||
|
Reproduzierbarer End-to-End-Lauf für `cards-api` ohne Frontend.
|
||||||
|
Validiert: Drizzle-Schema-Push, Auth-Gate, CRUD, FSRS-Berechnung,
|
||||||
|
Cascade-Delete.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Docker läuft
|
||||||
|
- pnpm 9.x installiert
|
||||||
|
- Bun installiert (`brew install bun` oder via nvm)
|
||||||
|
- `pnpm install` einmalig im Repo-Root durchgelaufen
|
||||||
|
|
||||||
|
## Ablauf
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Postgres-Container starten (auf :5435, kollidiert nicht mit Mana-Plattform-:5432)
|
||||||
|
pnpm docker:up
|
||||||
|
|
||||||
|
# 2. Drizzle-Schema pushen (--force, weil non-interactive)
|
||||||
|
cd apps/api
|
||||||
|
DATABASE_URL='postgresql://cards:cards@localhost:5435/cards' pnpm exec drizzle-kit push --force
|
||||||
|
# Erwartet: 8 Tabellen + 11 Indizes + 6 Foreign-Keys in Schema `cards`
|
||||||
|
|
||||||
|
# 3. cards-api starten (auf :3081)
|
||||||
|
DATABASE_URL='postgresql://cards:cards@localhost:5435/cards' CARDS_API_PORT=3081 bun run src/index.ts &
|
||||||
|
APIPID=$!
|
||||||
|
|
||||||
|
# Warten bis ready
|
||||||
|
until curl -s http://localhost:3081/healthz > /dev/null; do sleep 0.5; done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verifizierte Endpoints
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Plattform-Endpunkte
|
||||||
|
curl http://localhost:3081/healthz
|
||||||
|
# → {"status":"ok"}
|
||||||
|
|
||||||
|
curl http://localhost:3081/version
|
||||||
|
# → {"app":"cards","version":"0.0.0","build":"dev"}
|
||||||
|
|
||||||
|
curl http://localhost:3081/.well-known/mana-app.json | jq '.id'
|
||||||
|
# → "cards"
|
||||||
|
|
||||||
|
# Auth-Gate
|
||||||
|
curl -i http://localhost:3081/api/v1/decks
|
||||||
|
# → HTTP/1.1 401 Unauthorized
|
||||||
|
# → {"error":"unauthenticated","detail":"X-User-Id header missing (dev stub)"}
|
||||||
|
|
||||||
|
# Deck CRUD
|
||||||
|
curl -X POST http://localhost:3081/api/v1/decks \
|
||||||
|
-H 'X-User-Id: u-test-1' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"name":"Deck-Name","color":"#ff8800"}'
|
||||||
|
# → {"id":"<ULID>","user_id":"u-test-1","name":"Deck-Name",...}
|
||||||
|
|
||||||
|
# Card mit basic-reverse → automatisch 2 Reviews initialisiert
|
||||||
|
curl -X POST http://localhost:3081/api/v1/cards \
|
||||||
|
-H 'X-User-Id: u-test-1' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"deck_id":"<DECK_ID>","type":"basic-reverse","fields":{"front":"Q","back":"A"}}'
|
||||||
|
# → {"id":"<CARD_ID>",...}
|
||||||
|
|
||||||
|
# Reviews fällig (zwei sub_indices)
|
||||||
|
curl -H 'X-User-Id: u-test-1' http://localhost:3081/api/v1/reviews/due
|
||||||
|
# → {"reviews":[{...sub_index:0,state:"new"},{...sub_index:1,state:"new"}],"total":2}
|
||||||
|
|
||||||
|
# Grade triggert FSRS-Berechnung
|
||||||
|
curl -X POST http://localhost:3081/api/v1/reviews/<CARD_ID>/0/grade \
|
||||||
|
-H 'X-User-Id: u-test-1' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"rating":"good"}'
|
||||||
|
# → state:"learning", stability:2.3..., learning_steps:1, due:<now+10min>
|
||||||
|
|
||||||
|
# Cross-User-Schutz
|
||||||
|
curl -X POST http://localhost:3081/api/v1/cards \
|
||||||
|
-H 'X-User-Id: u-attacker' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"deck_id":"<DECK_ID>","type":"basic","fields":{"front":"Q","back":"A"}}'
|
||||||
|
# → {"error":"deck_not_owned"} (HTTP 403)
|
||||||
|
|
||||||
|
# Cascade-Delete (DELETE deck → Cards weg → Reviews weg)
|
||||||
|
curl -X DELETE http://localhost:3081/api/v1/decks/<DECK_ID> -H 'X-User-Id: u-test-1'
|
||||||
|
# → {"deleted":"<DECK_ID>"}
|
||||||
|
|
||||||
|
# Verifikation per SQL
|
||||||
|
docker exec cards-postgres psql -U cards -d cards -c "SELECT count(*) FROM cards.decks, cards.cards, cards.reviews;"
|
||||||
|
# → alle 0 (Cascade hat alles entfernt)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Aufräumen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kill $APIPID
|
||||||
|
pnpm docker:down
|
||||||
|
# Lokale DB-Daten in infrastructure/.volumes/cards-postgres bleiben.
|
||||||
|
# Komplett zurücksetzen: rm -rf infrastructure/.volumes/cards-postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
## Letzter erfolgreicher Lauf
|
||||||
|
|
||||||
|
**2026-05-08, Phase 3-Verifikation:**
|
||||||
|
- pnpm install: 136 packages, 8s
|
||||||
|
- type-check: 4/4 packages grün (svelte-check 0 errors)
|
||||||
|
- vitest: 46 Tests grün
|
||||||
|
- drizzle push: 8 Tabellen, 11 Indizes, 6 FKs in `cards`-Schema
|
||||||
|
- E2E-Flow: Deck-Create → Card-Create (basic-reverse, 2 Reviews) →
|
||||||
|
Reviews-Due (2 Einträge) → Grade rating=good (state new→learning,
|
||||||
|
stability 0→2.3, learning_steps 0→1) → 1 Review fällig → Cascade-
|
||||||
|
Delete leert alle Tabellen
|
||||||
Loading…
Add table
Add a link
Reference in a new issue