# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Tech Stack - SvelteKit 5 + TypeScript + Bun + Tailwind v4 + better-sqlite3 - Auth via Synology SSO Server (OIDC) using Auth.js ## Development Commands ```bash bun run dev # Start dev server bun run build # Production build bun run check # TypeScript type-check bun run lint # ESLint (must pass with 0 errors) bun run format # Prettier formatting bun run test # Run unit tests (must all pass) bun run test:watch # Run tests in watch mode bun run test:coverage # Run tests with coverage report ``` ## Code Quality ### Linting and tests must pass before considering any task complete After making changes, always verify: 1. `bun run lint` — must exit with 0 errors (warnings are acceptable) 2. `bun run test` — all tests must pass For user-facing feature work, also add/update e2e coverage and validate it: 3. `bunx playwright test ` When work maps to a Gitea issue, upload an e2e run video to the issue: - Generate one-off video artifacts with: - `PW_VIDEO_MODE=on PW_TRACE_MODE=on bunx playwright test ` - Prefer comment-level attachments: create a comment first, then attach video to that comment. - `tea comment -l -r / ""` - Upload with `curl` (the current `tea api` build here does not send multipart/form-data correctly for attachments): - `TOKEN=$(awk '/- name: cloud.campbellwireless.net/{f=1} f && $1=="token:"{print $2; exit}' "$HOME/Library/Application Support/tea/config.yml")` - `curl -fsS -X POST "https://cloud.campbellwireless.net/git/api/v1/repos/{owner}/{repo}/issues/comments/{comment_id}/assets" -H "Authorization: token $TOKEN" -F "name=" -F "attachment=@"` ### Write unit tests after every major feature When adding or significantly modifying server-side business logic (files under `src/lib/server/`), write corresponding unit tests in a `.test.ts` file alongside the module (e.g. `src/lib/server/lodgings.test.ts`). Tests use Vitest with an in-memory SQLite database. Use the `setupTestDb()` helper from `src/tests/helpers.ts` to get a fresh DB per test: ```ts import { setupTestDb } from '../../tests/helpers.js'; import type { Database } from './db/types.js'; let db: Database; beforeEach(() => { db = setupTestDb(); }); afterEach(() => { db.close(); }); ``` Test coverage should include the happy path, optional fields, ownership/authorisation checks, and any relationship linking (e.g. guests, travellers). ### ESLint notes - `svelte/require-each-key` is set to `warn` — keyless `{#each}` blocks are acceptable where keys are not meaningful - `@typescript-eslint/no-unused-expressions` is off — the `value;` reactivity-tracking pattern used in Svelte 5 `$effect` blocks is intentional - Prefix unused variables/args/catch bindings with `_` to satisfy the no-unused-vars rule - Use `// eslint-disable-next-line svelte/prefer-svelte-reactivity` for `new URLSearchParams()` used as local temporaries (not reactive state) ## DB / Testing Architecture All server modules import `db` from `$lib/server/db/index.ts`. In tests, `_setDb()` is used to inject an in-memory SQLite instance, bypassing the `$env/dynamic/private` SvelteKit virtual module entirely. Never call `_setDb` in production code. SvelteKit virtual modules (`$env/dynamic/private`, `$app/paths`) are stubbed via path aliases in `vitest.config.ts`.