Add a sortable "Out/In Ratio" (completion_tokens / prompt_tokens) column with a portal-based tooltip explaining the metric. Fix hydration mismatch by switching to useSyncExternalStore for localStorage reads in TimeRangeProvider. Update CLAUDE.md with project documentation.
64 lines
2.9 KiB
Markdown
64 lines
2.9 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
@AGENTS.md
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
npm run dev # Start dev server (localhost:3000)
|
|
npm run build # Production build (standalone output)
|
|
npm run start # Start production server
|
|
npm run lint # ESLint (eslint-config-next/core-web-vitals + typescript)
|
|
```
|
|
|
|
Docker deployment: port 8019, `docker-compose up` with `.env.production`, external network `sinobridge`.
|
|
|
|
## Architecture
|
|
|
|
Next.js 16 App Router analytics dashboard for an API gateway. React 19, TypeScript strict mode, Tailwind CSS 4, Recharts 3, PostgreSQL.
|
|
|
|
### Three Global Contexts (wrapped in `components/ClientProviders.tsx`)
|
|
|
|
1. **ThemeProvider** (`lib/theme.tsx`) — light/dark/system, localStorage `theme`, supports iframe embedding via `?theme=` query param and postMessage sync
|
|
2. **I18nProvider** (`lib/i18n.tsx`) — zh/en, localStorage `locale`, all translation keys in a single `translations` object
|
|
3. **TimeRangeProvider** (`lib/time-range-context.tsx`) — today/7d/30d/all/custom, localStorage `time-range`, exposes `getEffectiveRange()` returning `{ start?, end? }` unix timestamps (seconds)
|
|
|
|
Pages consume these via `useTheme()`, `useI18n()`, `useTimeRange()`. The `TimeRangeSelector` component reads from context (no props).
|
|
|
|
### Data Flow
|
|
|
|
Pages call `getEffectiveRange()` → `buildQuery("/api/...", { start, end })` → API route → `lib/queries.ts` SQL → PostgreSQL → JSON response → Recharts/tables.
|
|
|
|
### Database Layer (`lib/db.ts`, `lib/queries.ts`)
|
|
|
|
- `pg` pool (max 10 connections), env var `PG_CONNECTION_STRING`
|
|
- All queries filter `type = 2`, timezone `Asia/Shanghai`
|
|
- Real model name resolution: `COALESCE(other::jsonb->>'upstream_model_name', model_name)`
|
|
- Quota to USD: `quota / 500000`
|
|
- Parameterized queries with `$N` positional params
|
|
|
|
### API Routes (all GET, query-param driven)
|
|
|
|
| Route | Key Params | Returns |
|
|
|-------|-----------|---------|
|
|
| `/api/overview` | start, end | Aggregate stats (calls, tokens, users, models, channels) |
|
|
| `/api/trends` | start, end, granularity (day/week/month) | Time-series array |
|
|
| `/api/rankings` | start, end, type (user/model/channel), limit | Ranked items |
|
|
| `/api/detail/[type]/[id]` | start, end | Stats + breakdown (models or users) |
|
|
| `/api/logs` | start, end, page, page_size, username, model, token_name | Paginated logs |
|
|
| `/api/aggregation` | start, end | All users aggregated (top 500) |
|
|
|
|
### Styling
|
|
|
|
CSS variables in `globals.css` — dark theme default (cyan `#00e5ff` accent), light theme (blue `#0284c7`). Key classes: `.glass` (glassmorphic card), `.gradient-text`, `.btn-accent`, `.input-glass`, `.row-glow`. Portal page (`/portal`) has its own extensive animation system.
|
|
|
|
### Path Alias
|
|
|
|
`@/*` maps to project root (tsconfig).
|
|
|
|
### Fonts
|
|
|
|
Outfit (sans, `--font-geist-sans`) and JetBrains Mono (mono, `--font-geist-mono`) via `next/font/google`.
|