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>
146 lines
5.2 KiB
Markdown
146 lines
5.2 KiB
Markdown
# 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.
|