···11+# Backend Agent Guide (`@boombox/backend`)
22+33+This workspace is the Bun API + ingestion service built with **Elysia + Effect + Drizzle (SQLite)**.
44+55+If you haven’t yet, read the repo entrypoint first: `../AGENTS.md`.
66+77+## Commands (run from `backend/`)
88+99+- **Dev (watch)**: `bun run dev`
1010+ - Runs `bun run --watch ./src/index.ts`
1111+- **Build**: `bun run build`
1212+ - Builds `./src/index.ts` to `./dist` (`bun build --target=bun --bytecode`)
1313+- **Test**: `bun run test`
1414+ - Runs `vitest run`
1515+1616+### Single test execution
1717+1818+- **Single file**: `bun run test -- test/flac.test.ts`
1919+- **By name**: `bun run test -- -t "parseFile should parse flac just fine"`
2020+- **Watch mode (Vitest)**: `bunx vitest` or `bunx vitest --watch`
2121+2222+### Database
2323+2424+- **Migrate**: `bun run db:migrate`
2525+ - Runs `src/db/migrate.ts`
2626+- **Generate migration**: `bun run db:gen`
2727+ - Runs `drizzle-kit generate`
2828+2929+### Lint / format
3030+3131+- **Lint (oxlint)**: `bunx oxlint .`
3232+- **Format (oxfmt)**: `bunx oxfmt .`
3333+3434+## Entry points & folder map
3535+3636+- **`src/index.ts`**: runtime + layers + startup/shutdown + periodic sync loop
3737+- **`src/api.ts`**: Elysia server + Effect-powered handlers + typed API surface
3838+- **`src/db/`**:
3939+ - `schema.ts`: Drizzle schema & relations
4040+ - `index.ts`: Effect SQL/Drizzle service layer (`DatabaseLive`)
4141+ - `migrate.ts`: migration runner
4242+- **`src/file-parser.ts`**: stream-based directory scan + file parsing per extension
4343+- **`src/sync-library.ts`**: batching + inserts + relation wiring
4444+- **`src/flac/`, `src/m4a/`**: format-specific metadata readers (Effect services + errors)
4545+- **`test/`**: Vitest tests (some use `@effect/vitest`)
4646+- **`test-data/`**: fixture audio files
4747+4848+## Coding patterns (preferred)
4949+5050+### Effect services + layers
5151+5252+Use `Effect.Service` and compose layers rather than manually passing dependencies.
5353+5454+- Prefer:
5555+ - `class X extends Effect.Service<X>()("...", { dependencies: [...], accessors: true, effect: Effect.gen(...) }) {}`
5656+ - `Layer.merge / Layer.mergeAll / Layer.provideMerge` to assemble the app layer
5757+5858+### “Effect-first” function style
5959+6060+- Prefer `Effect.gen(function* () { ... })` for sequencing.
6161+- Use `Effect.fn("label")(function* (...) { ... })` for named effects (better tracing/logging).
6262+- Use `pipe(...)` only when it improves readability; don’t over-nest.
6363+6464+### Typed errors (no untyped throws in core logic)
6565+6666+- Define domain failures with `Data.TaggedError(...)` or `Schema.TaggedError(...)`.
6767+- When you need to change the error domain:
6868+ - `Effect.mapError((cause) => new MyDomainError({ ... }))`
6969+- When you need to handle a specific failure:
7070+ - `Effect.catchTag("MyDomainError", (e) => ...)`
7171+7272+Good examples already in the codebase:
7373+7474+- `src/api.ts`: `FileNotFoundError`, `AlbumNotFoundError` (tagged) and `Effect.catchTag(...)` in route handlers
7575+- `src/m4a/errors.ts`: schema-backed tagged errors for structured payloads
7676+7777+### Schema at boundaries (decode/transform)
7878+7979+Use `effect/Schema` for:
8080+8181+- Env/config validation (`src/utils/env.ts`)
8282+- DB row → API DTO transformations (`Schema.transformOrFail`, `Schema.decodeUnknown`)
8383+8484+If you’re returning data from DB queries, prefer:
8585+8686+- `Schema.decodeUnknown(...)` on the raw DB row(s)
8787+- then transform to your public response schema
8888+8989+## Elysia + Effect integration
9090+9191+### Handler rule of thumb
9292+9393+- **Inside handlers**: build an `Effect` value, then execute via `runtime.runPromise`.
9494+- **Error mapping**: don’t rely on “whatever runtime throws”:
9595+ - translate domain errors to HTTP status with `Effect.catchTag(...)` and return `elysia/status(...)`
9696+9797+`backend/ISSUES.md` calls out that error handling is currently inconsistent; if you touch `src/api.ts`, consider improving handler wrappers rather than adding more one-off mappings.
9898+9999+## Concurrency & SQLite notes
100100+101101+SQLite will lock under write-heavy concurrent load.
102102+103103+- In streams that write to DB, prefer `Stream.mapEffect(fn, { concurrency: 1 })` unless you’ve verified safe parallelism.
104104+- Batch inserts with `Stream.grouped(n)` (see `src/sync-library.ts`).
105105+106106+## Config & ports
107107+108108+- `DB_URL` and `FOLDER_PATH` are required env vars (see `src/utils/env.ts`).
109109+- The API currently listens on port `3003` in `src/api.ts` and `src/index.ts` logs that port.
110110+ - `backend/ISSUES.md` suggests making port configurable via `Config`.
111111+112112+## Testing conventions
113113+114114+This workspace uses Vitest, plus `@effect/vitest` in several tests.
115115+116116+- For Effect workflows, prefer `test.effect("name", () => Effect.gen(...))`.
117117+- Provide dependencies with `Effect.provide(SomeLayer)` (see `backend/test/*.test.ts`).
118118+- For plain Vitest `it(...)`, wrap effect execution with `ManagedRuntime.runPromise(...)` when needed.
···11+# Web Agent Guide (`web-tanstack`)
22+33+This workspace is a **Vite + TanStack Start (React)** app with Tailwind + shadcn/ui.
44+55+If you haven’t yet, read the repo entrypoint first: `../AGENTS.md`.
66+77+## Commands (run from `web/`)
88+99+- **Dev**: `bun run dev`
1010+ - Runs `vite dev --port 3000`
1111+- **Build**: `bun run build`
1212+ - Runs `vite build`
1313+- **Preview**: `bun run serve`
1414+ - Runs `vite preview`
1515+- **Test**: `bun run test`
1616+ - Runs `vitest run`
1717+- **Lint**: `bun run lint`
1818+ - Runs `eslint` (TanStack ESLint config)
1919+- **Format**: `bun run format`
2020+ - Runs `oxfmt .`
2121+- **Format + lint fix**: `bun run check`
2222+ - Runs `oxfmt . && eslint --fix`
2323+2424+### Single test execution (Vitest)
2525+2626+- **Single file**: `bun run test -- src/**/some.test.ts`
2727+- **By name**: `bun run test -- -t "renders"`
2828+- **Watch mode**: `bunx vitest`
2929+3030+## Project map
3131+3232+- **`src/routes/`**: file-based routing (TanStack Router)
3333+ - `__root.tsx`: root document shell (Head, Scripts, devtools, global UI like `AudioPlayer`)
3434+ - `index.tsx`: starter homepage (can be replaced)
3535+ - `album/*`: album pages
3636+- **`src/router.tsx`**: router creation + SSR query integration wrapper
3737+- **`src/integrations/tanstack-query/`**: query client/provider integration
3838+- **`src/components/`**: app components
3939+ - `components/ui/`: shadcn/ui components (do not hand-edit unless needed)
4040+ - `components/player/`: audio player UI
4141+- **`src/lib/`**: shared web utilities (API client, errors, utils)
4242+- **`src/store/`**: global state (currently Zustand)
4343+4444+## Imports, TypeScript, and formatting
4545+4646+### Imports
4747+4848+- Use the **`@/*`** alias for `src/*` (configured in `web/tsconfig.json`).
4949+- Prefer `import type { ... }` for type-only imports (important when importing backend types).
5050+- Avoid barrel files; import from the exact module.
5151+5252+### TypeScript expectations
5353+5454+- `"strict": true` and unused checks are enabled (`noUnusedLocals`, `noUnusedParameters`).
5555+- Prefer explicit return types for exported functions when it clarifies behavior.
5656+- Use `effect/Schema` when you need runtime validation on untrusted data.
5757+5858+### Formatting rules
5959+6060+Uses oxfmt (Oxc formatter):
6161+6262+- tabs, `tabWidth = 4`
6363+- `printWidth = 120`
6464+- semicolons enabled
6565+6666+## UI + styling rules
6767+6868+### Tailwind
6969+7070+- Tailwind is the primary styling system. Prefer utility classes over bespoke CSS.
7171+- Shared CSS entry is `src/styles.css`.
7272+7373+### shadcn/ui
7474+7575+- UI primitives are under `src/components/ui/` and are typically managed by the shadcn CLI.
7676+- Repo Cursor rule: `web/.cursorrules` says to add new components with:
7777+ - `pnpx shadcn@latest add <component>`
7878+7979+Even though the repo is Bun-first, follow that shadcn instruction when installing shadcn components (it matches shadcn’s documented workflow).
8080+8181+## Data fetching & API integration
8282+8383+### Typed backend client (Elysia Eden)
8484+8585+The web client is typed against the backend’s Elysia server type:
8686+8787+- `src/lib/api.ts` exports `client = treaty<ApiType>("localhost:3003")`
8888+8989+Guidelines:
9090+9191+- Keep backend type imports as `type` imports.
9292+- Don’t hardcode fetch URLs in multiple places; route everything through the `client` (or a small wrapper in `src/lib/`).
9393+- If you change backend routes/response shapes, update the web usage in the same PR.
9494+9595+### TanStack Query + Router integration
9696+9797+- Router is created in `src/router.tsx`.
9898+- Query integration lives in `src/integrations/tanstack-query/`.
9999+- Prefer loaders / query hooks where TanStack Start expects them; keep side effects inside effects/hooks.
100100+101101+## State management (Zustand)
102102+103103+The app currently uses Zustand (not Jotai) for global state:
104104+105105+- Example: `src/store/player.ts` uses `persist` middleware to store volume in localStorage.
106106+107107+Guidelines:
108108+109109+- Keep stores small and domain-focused (one store per concern).
110110+- Prefer derived selectors in components rather than storing redundant computed state.
111111+112112+## Error handling
113113+114114+### Prefer typed errors for domain failures
115115+116116+The web workspace already defines Effect tagged errors in `src/lib/errors.ts`.
117117+118118+- When modeling a failure that you intend to handle, prefer `Data.TaggedError("...")<{ ... }>`
119119+- When calling async functions, fail early with a typed error and surface it at the component boundary.
120120+121121+### UI surfacing
122122+123123+- For user-visible errors, prefer a clear empty state + retry action.
124124+- For dev-only errors, console logging is OK, but don’t ship noisy logs in hot paths.
125125+126126+## Testing guidance
127127+128128+Vitest is set up for the workspace.
129129+130130+- Prefer Testing Library for component tests (`@testing-library/react` is installed).
131131+- For pure utilities, write plain unit tests under `src/**/__tests__` or alongside the module.