# AGENTS.md Repo-specific notes for AI agents. ## Stack - Bun-only (`mise.toml` pins `bun = 1.3.13`). Do not use `npm` / `npx` / `node` / `yarn` / `pnpm`. - TanStack Start + React 19 SSR + Vite + Nitro `bun` preset. - ORPC contract-first API, TanStack Query v5, Tailwind v4. - Business data source is the customer's existing **MySQL** database. This app is read-only display software. - There is no PostgreSQL, Drizzle schema, embedded migration flow, or local DB mutation path in this project now. - `scripts/seed.ts` is the only local development helper allowed to create/truncate/insert sample data. The app runtime must stay read-only. ## Scripts ```bash bun run dev bun run build bun run compile bun run seed bun run typecheck bun run test bun run fix ``` Before shipping: `bun run fix && bun run typecheck && bun run test && bun run build`. ## MySQL Source Environment variable: ```bash DATABASE_URL=mysql://user:password@host:3306/database ``` Required AI prediction service: ```bash SOH_PREDICTION_API_BASE_URL=http://127.0.0.1:8000 SOH_PREDICTION_CACHE_TTL_SECONDS=86400 SOH_PREDICTION_TIMEOUT_MS=10000 ``` Customer table: `ls_battery_info`. | Column | Type | Meaning | | --- | --- | --- | | `id` | `int(11)` auto increment | primary key | | `user_id` | `int(11)` | user ID | | `mac` | `varchar(50)` | device MAC | | `dev_model` | `varchar(20)` | device model | | `dev_name` | `varchar(50)` | device name | | `is_low_power` | `varchar(10)` | `true` / `false` | | `power_status` | `tinyint(4)` | `0` not charging, `1` charging, `2` full | | `power` | `tinyint(4)` | current battery `0~100` | | `create_time` | `datetime` | created time | | `remark` | `varchar(500)` | nullable remark | Rules: - Only run `SELECT` queries against this table. Do not insert, update, delete, migrate, or create tables. - Do not add mock/fallback rows. If MySQL is unavailable, surface the error. - `is_low_power` is stored as a string and normalized to boolean in `src/domain/battery.ts`. - `power_status` is normalized to `0 | 1 | 2`. - `battery.batteries` returns paginated latest records per `mac`; supported filters are `pageSize`, `cursor`, `search`, `lowPower`, `powerStatus`, and `sort`. - `battery.history` takes `mac` and returns history ordered by `create_time DESC, id DESC`, limited to 500 rows. - Dashboard requires the external prediction API via `SOH_PREDICTION_API_BASE_URL`; missing configuration must fail environment validation. Per-device prediction failures may surface as unavailable values, but must not be rendered as `0%`. ## Layout ``` src/ ├── routes/ │ ├── index.tsx # SoH dashboard │ ├── batteries.tsx # battery monitor page │ └── api/ # ORPC handlers ├── server/ │ ├── api/ # contracts / routers / interceptors │ ├── battery/mysql.ts │ └── prediction/client.ts ├── domain/battery.ts ├── client/orpc.ts └── styles.css ``` ## ORPC - Contracts live in `src/server/api/contracts/`. - Routers live in `src/server/api/routers/`. - Use `os` from `@/server/api/server`. - Current business API: - `battery.dashboard` - `battery.batteries` - `battery.history` ## CLI And Deploy - `src/bin.ts` must keep static imports minimal. Nitro's bun preset starts the server as a side effect when `.output/server/index.mjs` is imported. - `serve` is lazy-loaded via citty. - `bun run compile` produces `out/server-`. - Runtime artifact is a single binary plus `DATABASE_URL` configuration. ## Code Style - 2-space indentation, LF, single quotes, semicolons as-needed, 120-column line width. - Route components use `function Foo()` declarations below route config. - No `console.*` in business code; use `getLogger([...])` from `@/server/logger` if logging is needed. - No `as any`, `@ts-ignore`, or `@ts-expect-error`. - Do not edit `src/routeTree.gen.ts` manually.