Scrum4Me/scripts/README.md
Janpeter Visser eaabec8471
feat(PBI-66): wekelijkse sync van model_prices via Anthropic /v1/models (#167)
Nieuw script `npm run db:sync-model-prices` haalt de actuele Claude 4.x
modellijst op bij de Anthropic API en upsert prijzen in `model_prices`.
Anthropic biedt geen prijs-API, dus prijzen blijven onderhouden in een
PRICE_TABLE constante in het script. Cache-tier-prijzen worden afgeleid
via vaste multipliers (read 0.1x, write 1.25x). Nieuwe Claude 4.x modellen
worden gedetecteerd en gelogd als warning zodat duidelijk is wanneer de
tabel handmatig moet worden bijgewerkt.

- scripts/sync-model-prices.ts: idempotent upsert, --dry-run, retry op 5xx
- ANTHROPIC_API_KEY als optional env-var (.env.example, lib/env.ts)
- scripts/README.md: gebruiksinstructies + edge cases
- docs/plans/sync-model-prices.md: ontwerpdocument

Verificatie: `npm run lint`, `vitest` (563/563), TypeScript clean.
Echt gedraaid tegen DB: 3 created (eerste run) -> 3 unchanged (tweede run).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:38:33 +02:00

146 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scripts
## sync-model-prices.ts
Wekelijks handmatig draaibaar script dat de tabel `model_prices` synchroniseert. Haalt de actuele Claude 4.x modellijst op via `GET /v1/models` (Anthropic API) en upsert de prijzen vanuit een hardcoded `PRICE_TABLE` in het script. Anthropic biedt geen prijs-API; bij elke prijswijziging update je de tabel in [`scripts/sync-model-prices.ts`](./sync-model-prices.ts).
### Prerequisites
| What | How |
|---|---|
| `ANTHROPIC_API_KEY` in `.env.local` | Genereer op [console.anthropic.com](https://console.anthropic.com/) → API Keys. Free Evaluation tier is voldoende — `/v1/models` is een gratis metadata-call. |
| `DATABASE_URL` in `.env.local` | Standaard Scrum4Me-setup. |
### Gebruik
```bash
# Eerst droog draaien — toont wat er zou gebeuren, schrijft niets
npm run db:sync-model-prices -- --dry-run
# Echt synchroniseren
npm run db:sync-model-prices
```
### Output
```
Fetching /v1/models from Anthropic API...
→ 12 models received, 4 match Claude 4.x filter
Syncing prices:
✓ claude-opus-4-7 (unchanged)
✓ claude-sonnet-4-6 (unchanged)
✓ claude-haiku-4-5-20251001 (unchanged)
⚠ claude-sonnet-4-9 (geen prijs in PRICE_TABLE — ...)
Result: 0 created, 0 updated, 3 unchanged, 1 skipped
```
### Bij een nieuw model (`⚠ skipped`)
1. Open de Anthropic [pricing-pagina](https://platform.claude.com/docs/en/about-claude/pricing).
2. Voeg het model toe aan `PRICE_TABLE` in [`scripts/sync-model-prices.ts`](./sync-model-prices.ts):
```ts
'claude-sonnet-4-9': { input: 3.0, output: 15.0 },
```
3. Draai het script opnieuw.
### Edge cases
- **API geeft 401**: controleer `ANTHROPIC_API_KEY`.
- **API geeft 5xx**: script doet 1× retry met 2s delay, daarna falen.
- **Model in DB maar niet meer in API**: wordt niet verwijderd — alleen gelogd, zodat oude `claude_jobs` rijen kostberekening blijven hebben.
---
## test-api.sh
Runs curl-based tests against all 7 Scrum4Me API endpoints. Covers happy paths, auth (401), demo-block (403), and input validation (400).
### Prerequisites
| What | How |
|---|---|
| Database seeded | `npx prisma db seed` |
| Dev server running | `npm run dev` |
| `curl` installed | `curl --version` |
### Step 1 — Get a token for lars
1. Open `http://localhost:3000` in your browser
2. Log in as `lars` / `scrum4me123`
3. Go to **Settings → API Tokens**
4. Click **New token**, give it any label
5. Copy the token — it is shown only once
Open `scripts/test-api.sh` and paste it into `TOKEN=""`.
### Step 2 — Find your IDs
You need four IDs. The easiest way is to use the API itself:
```bash
# 1. Get PRODUCT_ID — run this after setting TOKEN
curl -s -H "Authorization: Bearer <TOKEN>" http://localhost:3000/api/products | grep -o '"id":"[^"]*"' | head -1
# 2. SPRINT_ID — look in the database or the UI (Sprint → copy ID from the URL)
# 3. STORY_ID — open a story in the Sprint Board, copy the ID from the URL or the activity log
# 4. TASK_ID — open a task, copy its ID
```
Or query the database directly:
```bash
# With psql / Neon CLI:
SELECT id FROM "Sprint" WHERE status = 'ACTIVE' LIMIT 1;
SELECT id FROM "Story" WHERE status = 'IN_SPRINT' LIMIT 1;
SELECT id FROM "Task" WHERE story_id = '<story-id>' LIMIT 1;
```
Paste the four values into the variables at the top of `test-api.sh`.
### Step 3 — (Optional) Get a demo token for 403 tests
The 403 demo-block tests are skipped unless you set `DEMO_TOKEN`.
1. Log out, log in as `demo` / `demo1234`
2. Go to **Settings → API Tokens**, create a token
3. Paste it into `DEMO_TOKEN=""` in `test-api.sh`
### Step 4 — Run
```bash
bash scripts/test-api.sh
```
Expected output when all IDs are set and a demo token is provided:
```
============================================================
Scrum4Me API Test Suite
Base URL : http://localhost:3000
Token : scrum4me... (lars)
Demo : demo1234... (403 tests active)
============================================================
── GET /api/products ──────────────────────────────────────────────
PASS TC-P-09 happy path (lars)
PASS TC-P-01 no token → 401
PASS TC-P-02 invalid token → 401
── GET /api/products/:id/next-story ───────────────────────────────
PASS TC-NS-08 happy path (lars, 200 or 404 both valid)
PASS TC-NS-01 no token → 401
...
============================================================
Results: 30 passed, 0 failed
============================================================
```
### Notes
- **product_id is required** for `POST /api/todos`. The Zod schema enforces `z.string().min(1)`. Sending a todo without a product_id returns 400.
- **TC-NS-08** accepts both 200 and 404. After a fresh seed lars has no active sprint, so 404 is the expected response unless you create a sprint and add stories to it.
- **Reorder test (TC-RO-10)** uses a single task ID. A reorder with one element is valid (sort_order is updated to 1).
- The todos happy-path test appends `$(date +%s)` to the title to avoid duplicate-title issues on repeated runs.