Files
Tradarr/CLAUDE.md

95 lines
4.7 KiB
Markdown
Raw 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.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
# Start all services (rebuilds images)
make up # docker compose up --build
# Run standalone (requires env vars)
make dev-backend # cd backend && go run ./cmd/server
make dev-frontend # cd frontend && npm run dev (proxies /api → :8080)
# Build
cd backend && go build ./cmd/server
cd frontend && npm run build # tsc -b && vite build
# Lint / type-check
cd frontend && npm run lint # eslint
cd backend && go vet ./...
# Tests (no test files exist yet)
cd backend && go test ./...
# Production release
./build-push.sh v1.0.0 # builds and pushes all three images to Gitea registry
docker compose -f docker-compose.prod.yml up -d
```
## Architecture
Three Docker services behind nginx:
```
Browser → nginx:80
├── serves React SPA (static build)
└── proxies /api/* → backend:8080
backend (Go/Gin) → PostgreSQL:5432
→ scraper-service:3001 (Bloomberg only)
→ ollama:11434 (optional)
scraper-service (Node.js/Puppeteer) — headless Chromium for Bloomberg login
```
### Backend layout
- `cmd/server/main.go` — entry point, wires all dependencies
- `internal/models/` — all DB structs (`models.go`) and every SQL query (`repository.go`)
- `internal/api/router.go` — all Gin routes; `handlers/` has one file per domain
- `internal/ai/` — AI providers, two-pass pipeline, async report manager
- `internal/scraper/` — scraper interface, registry, per-source Go implementations
- `internal/scheduler/``robfig/cron` v3 scheduler that runs scrape → summarize on each tick
- `internal/database/migrations/` — numbered SQL migrations (auto-applied at startup via golang-migrate)
### Frontend layout
- `src/api/client.ts` — fetch wrapper: reads `token` from `localStorage`, sets `Authorization: Bearer`, auto-redirects on 401, unwraps `{"data": ...}` envelopes
- `src/lib/auth.tsx``AuthProvider`/`useAuth` React context with `login()`/`logout()`
- `src/lib/router.tsx``createBrowserRouter`; authenticated pages nested under `AppLayout`; admin pages under `/admin`
- UI: Radix UI primitives + Tailwind CSS + CVA; path alias `@``src/`
### AI pipeline
1. **Filter pass** (optional): if article count > `2 × summary_max_articles`, batches articles in groups of `filter_batch_size` (default 20) and asks AI for relevant indices. Falls back to summary provider if no filter role is configured.
2. **Summary pass**: structured French-language prompt with watchlist symbols + truncated article bodies (max 1000 chars). Called with `Think: true, NumCtx: 32768`.
3. **Report generation**: async goroutine, 30-minute context. DB row created immediately with `status=generating`; frontend polls `GET /reports` — there is no WebSocket/SSE.
Three AI roles (`summary`, `report`, `filter`) resolve their provider via settings keys `ai_role_<role>_provider` / `ai_role_<role>_model`, falling back to the single `is_active=TRUE` provider.
Supported providers: `openai`, `anthropic`, `gemini`, `ollama`, `claudecode` (shells out to `claude -p`).
### Key non-obvious patterns
- **`httputil.OK`** uses reflection to convert nil slices to `[]` so the frontend never receives JSON `null` for lists.
- **Bloomberg scraping is split**: the Go backend calls `POST http://scraper:3001/bloomberg/scrape` — it does not run Chromium in-process.
- **API keys are never stored raw**: `ListAIProviders` replaces the encrypted key with a boolean `has_key` field.
- **Scheduler timezone**: cron specs are prefixed with `TZ=<iana>` so schedules respect the app timezone, not UTC.
- **Nginx resolver trick**: `resolver 127.0.0.11` + `set $backend http://backend:8080` (variable) prevents startup failures when the backend container isn't ready yet — Docker DNS is queried per-request.
- **`claudecode` provider model list** is hardcoded in `backend/internal/ai/claudecode.go` — update it when new Claude models are released.
- **UUID primary keys** require the `pgcrypto` Postgres extension (`gen_random_uuid()`). Migrations handle this automatically.
- **`scrape_jobs`** status values: `pending | running | done | error`. **`reports`** status values: `generating | done | error`.
## Environment variables
| Variable | Required | Description |
|----------|----------|-------------|
| `DATABASE_URL` | Yes | Postgres DSN |
| `JWT_SECRET` | Yes | JWT signing secret |
| `ENCRYPTION_KEY` | Yes | 32-byte hex for AES-256-GCM (`openssl rand -hex 32`) |
| `PORT` | No | HTTP port, default `8080` |
| `SCRAPER_URL` | No | Scraper service URL, default `http://scraper:3001` |
| `ADMIN_EMAIL` / `ADMIN_PASSWORD` | No | Bootstrap admin account created on startup |