Some checks failed
CI / ci (push) Failing after 22s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
156 lines
7.0 KiB
Markdown
156 lines
7.0 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
GearBox is a single-user web app for managing gear collections (bikepacking, sim racing, etc.), tracking weight/price, and planning purchases through research threads. Full-stack TypeScript monolith running on Bun.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Development
|
|
bun run dev # Starts both Vite client (:5173) and Hono server (:3000) concurrently
|
|
bun run dev:client # Vite dev server on :5173 (proxies /api to :3000)
|
|
bun run dev:server # Hono server on :3000 with hot reload
|
|
|
|
# Database
|
|
bun run db:generate # Generate Drizzle migration from schema changes
|
|
bun run db:push # Apply migrations to gearbox.db
|
|
|
|
# Testing
|
|
bun test # Run all unit/integration tests
|
|
bun test tests/services/item.service.test.ts # Run single test file
|
|
bun run test:e2e # Run Playwright E2E tests
|
|
bun run test:e2e:ui # Playwright UI mode for debugging
|
|
|
|
# Lint & Format
|
|
bun run lint # Biome check (tabs, double quotes, organized imports)
|
|
|
|
# Build
|
|
bun run build # Vite build → dist/client/
|
|
```
|
|
|
|
## Architecture
|
|
|
|
**Stack**: React 19 + Hono + Drizzle ORM + SQLite, all running on Bun.
|
|
|
|
### Client (`src/client/`)
|
|
- **Routing**: TanStack Router with file-based routes in `src/client/routes/`. Route tree auto-generated to `routeTree.gen.ts` — never edit manually.
|
|
- **Data fetching**: TanStack React Query via custom hooks in `src/client/hooks/` (e.g., `useItems`, `useThreads`, `useSetups`). Mutations invalidate related query keys.
|
|
- **UI state**: Zustand store (`stores/uiStore.ts`) for panel/dialog state only — server data lives in React Query.
|
|
- **API calls**: Thin fetch wrapper in `lib/api.ts` (`apiGet`, `apiPost`, `apiPut`, `apiDelete`, `apiUpload`).
|
|
- **Styling**: Tailwind CSS v4.
|
|
|
|
### Server (`src/server/`)
|
|
- **Routes** (`routes/`): Hono handlers with Zod validation via `@hono/zod-validator`. Delegate to services.
|
|
- **Services** (`services/`): Pure business logic functions that take a db instance. No HTTP awareness — testable without mocking.
|
|
- Route registration in `src/server/index.ts` via `app.route("/api/...", routes)`.
|
|
|
|
### Shared (`src/shared/`)
|
|
- **`schemas.ts`**: Zod schemas for API request validation (source of truth for types).
|
|
- **`types.ts`**: Types inferred from Zod schemas + Drizzle table definitions. No manual type duplication.
|
|
|
|
### Database (`src/db/`)
|
|
- **Schema**: `schema.ts` — Drizzle table definitions for SQLite.
|
|
- **Prices stored as cents** (`priceCents: integer`) to avoid float rounding.
|
|
- **Timestamps**: stored as integers (unix epoch) with `{ mode: "timestamp" }`.
|
|
- Tables: `categories`, `items`, `threads`, `threadCandidates`, `setups`, `setupItems`, `settings`, `users`, `sessions`, `apiKeys`.
|
|
|
|
### Testing (`tests/` and `e2e/`)
|
|
- **Unit/integration**: Bun test runner (`bun test`). Tests at service level and route level.
|
|
- `tests/helpers/db.ts`: `createTestDb()` creates in-memory SQLite via Drizzle migrations and seeds an "Uncategorized" category.
|
|
- **E2E**: Playwright (`bun run test:e2e`). Tests in `e2e/` run against a seeded SQLite database with the server in production mode. Seed script: `e2e/seed.ts`.
|
|
|
|
## Branching
|
|
|
|
- **Develop** is the main branch. Keep it clean — don't commit large feature work directly.
|
|
- For each new brainstorming/implementation session, create a feature branch off Develop (e.g., `feature/setup-impact-preview`, `fix/error-handling`).
|
|
- Merge back to Develop via PR or fast-forward merge when the work is complete and verified.
|
|
|
|
## Path Alias
|
|
|
|
`@/*` maps to `./src/*` (configured in tsconfig.json).
|
|
|
|
## Key Patterns
|
|
|
|
- **Thread resolution**: Resolving a thread copies the winning candidate's data into a new item in the collection, sets `resolvedCandidateId`, and changes status to "resolved".
|
|
- **Setup item sync**: `PUT /api/setups/:id/items` replaces all setup_items atomically (delete all, re-insert).
|
|
- **Image uploads**: `POST /api/images` saves to `./uploads/` with UUID filename, returned as `imageFilename` on item/candidate records.
|
|
- **Image URL fetching**: `POST /api/images/from-url` fetches an image from a URL, saves locally, returns `{ filename, sourceUrl }`.
|
|
- **Aggregates** (weight/cost totals): Computed via SQL on read, not stored on records.
|
|
- **Authentication**: Public-read, authenticated-write. Cookie sessions for web UI, API keys (`X-API-Key` header) for programmatic access. `POST /api/auth/setup` for first-time account creation. Auth middleware protects all POST/PUT/DELETE on `/api/*` except `/api/auth/*`.
|
|
|
|
## Authentication
|
|
|
|
- **First run**: No users exist. Visit `/login` to create your admin account.
|
|
- **Web UI**: Cookie-based sessions (`gearbox_session`), 30-day expiry, auto-refreshed.
|
|
- **Programmatic access**: API keys created in Settings > API Keys. Pass via `X-API-Key` header.
|
|
- **Public read**: All GET endpoints work without auth. POST/PUT/DELETE require auth.
|
|
- **Auth routes**: `/api/auth/login`, `/api/auth/logout`, `/api/auth/setup`, `/api/auth/me`, `/api/auth/password`, `/api/auth/keys`.
|
|
|
|
## MCP Server
|
|
|
|
GearBox includes a built-in MCP server for integration with Claude Code and Claude Desktop. Enabled by default, disable with `GEARBOX_MCP=false`. Authenticated via API key.
|
|
|
|
### Tools (19 total)
|
|
|
|
| Tool | Description |
|
|
|------|-------------|
|
|
| `list_items` | List all items, optionally filter by category |
|
|
| `get_item` | Get item details by ID |
|
|
| `create_item` | Add item to collection (for decided items; use `create_thread` for research) |
|
|
| `update_item` | Update item details |
|
|
| `delete_item` | Remove item from collection |
|
|
| `list_categories` | List all categories |
|
|
| `create_category` | Create a new category |
|
|
| `list_threads` | List research threads (recommended workflow for gear purchases) |
|
|
| `get_thread` | Get thread with candidates |
|
|
| `create_thread` | Start a research thread to compare gear options |
|
|
| `resolve_thread` | Pick winning candidate, adds it to collection |
|
|
| `add_candidate` | Add candidate to a research thread |
|
|
| `update_candidate` | Update candidate details |
|
|
| `remove_candidate` | Remove candidate from thread |
|
|
| `list_setups` | List gear setups |
|
|
| `get_setup` | Get setup with items and totals |
|
|
| `create_setup` | Create a new setup |
|
|
| `update_setup` | Update setup name or items |
|
|
| `upload_image_from_url` | Fetch image from URL, save locally |
|
|
|
|
### Resources
|
|
|
|
- `gearbox://collection/summary` — Overview of collection: totals, items per category, active threads.
|
|
|
|
### Configuration
|
|
|
|
**Claude Code** (`.claude/settings.json`):
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"gearbox": {
|
|
"type": "streamable-http",
|
|
"url": "http://localhost:3000/mcp",
|
|
"headers": {
|
|
"X-API-Key": "<your-api-key>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Claude Desktop** (`claude_desktop_config.json`):
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"gearbox": {
|
|
"type": "streamable-http",
|
|
"url": "http://localhost:3000/mcp",
|
|
"headers": {
|
|
"X-API-Key": "<your-api-key>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Generate an API key from Settings > API Keys after logging in. |