# 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 supplied by the deployment platform or shell, 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. **TypeScript: Never use `any` type.** Always define proper interfaces/types for all data structures. Use `unknown` with type narrowing if the type is truly unknown. ### 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`.