chore: add CLAUDE.md, initial Drizzle migration, and update gitignore
Add project instructions for Claude Code, the initial database migration, and ignore the .claude/ local config directory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
70
CLAUDE.md
Normal file
70
CLAUDE.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 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 (run both in separate terminals)
|
||||
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 tests
|
||||
bun test tests/services/item.service.test.ts # Run single test file
|
||||
|
||||
# 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`.
|
||||
|
||||
### Testing (`tests/`)
|
||||
- Bun test runner. Tests at service level and route level.
|
||||
- `tests/helpers/db.ts`: `createTestDb()` creates in-memory SQLite with full schema and seeds an "Uncategorized" category. When adding schema columns, update both `src/db/schema.ts` and the test helper's CREATE TABLE statements.
|
||||
|
||||
## 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.
|
||||
- **Aggregates** (weight/cost totals): Computed via SQL on read, not stored on records.
|
||||
Reference in New Issue
Block a user