# CLAUDE.md Guidance for Claude Code when working in this repository. ## Project overview [1-2 sentences: what this app does, who it's for] **Stack:** - TanStack Start (React, file-based routing via TanStack Router) - TypeScript (strict mode) - Vite - SCSS Modules - Drizzle ORM + PostgreSQL - Better Auth - npm ## Commands ```bash npm run dev # start dev server (http://localhost:3000) npm run build # production build npm run typecheck # tsc --noEmit npm run lint # eslint npm test # vitest run ``` Always run `typecheck` and `lint` before considering a task done. If `build` fails with TypeScript errors, run `typecheck` first to isolate them. ## Project structure ``` src/ ├── routes/ # file-based routes (TanStack Router) │ ├── __root.tsx # root layout, wraps every page │ └── index.tsx # home page ├── routeTree.gen.ts # AUTO-GENERATED — never edit by hand ├── router.tsx # router instance/config ├── components/ │ ├── ui/ # base primitives (buttons, inputs, etc.) │ └── / # feature-specific components, e.g. posts/, auth/ ├── lib/ # shared utilities, API clients, helpers ├── db/ │ ├── schema.ts # Drizzle schema definitions │ ├── index.ts # Drizzle client instance │ └── migrations/ # generated SQL migrations — never hand-edit ├── styles/ │ ├── globals.scss # global styles, resets │ └── _variables.scss # shared SCSS variables/mixins (partial) public/ # static assets drizzle.config.ts # Drizzle Kit config (schema path, out dir, dialect) ``` ### Routing conventions - Routes live under `src/routes/` and map to URLs by file name/path. - `__root.tsx` is the root layout every route renders inside. - `routeTree.gen.ts` is generated by TanStack Router — **never edit it directly**; it regenerates on `dev`/`build` from the files in `routes/`. - Use route `loader`s for data fetching tied to a route, not `useEffect`. - Keep server-only code (secrets, DB access) out of files that ship to the client; be careful with `verbatimModuleSyntax` so server code doesn't leak into client bundles. ## Styling (SCSS Modules) - Every component that needs styles gets a co-located `Component.module.scss` next to `Component.tsx` — not a shared stylesheet. - Import as `import styles from './Component.module.scss'` and apply classes via `className={styles.foo}`; never reference a module class by string outside that import. - Class names in `.module.scss` files are camelCase (e.g. `.cardHeader`, not `.card-header`) so they read naturally as `styles.cardHeader`. - Shared tokens (colors, spacing, breakpoints) live in `src/styles/_variables.scss` and are pulled in with `@use '~/styles/variables' as *;` — don't hardcode colors/spacing that already exist as a variable. - `src/styles/globals.scss` is for resets and truly global rules only (imported once in `__root.tsx`); component-specific styles always go in a module, never in globals. - Avoid deep nesting (max ~3 levels) and avoid `!important`. ## Code style - TypeScript strict mode; avoid `any`. Prefer inferred types everywhere possible — let TypeScript infer return types and variable types rather than annotating them. Only add explicit types where inference can't reach: function parameters (always type these), exported values whose inferred type would be unclear to a caller, or when inference produces something wider than intended (e.g. use `as const` or a literal type instead of annotating). - Functional React components only, no class components. - Use arrow functions everywhere (components, handlers, utilities) instead of the `function` keyword — e.g. `const getUser = async (id: string) => {...}` and `export const Button = (props: ButtonProps) => {...}`. - [Naming conventions: PascalCase components, camelCase functions/vars, etc.] - [Import order / path aliases, e.g. `~/` or `@/` for `src/`] - Co-locate a component's test file next to it unless it's a shared primitive in `components/ui/` (see "Styling" for `.module.scss` placement). - No comments unless they're unavoidable for understanding — e.g. explaining *why* a non-obvious workaround exists, documenting a constraint imposed by an external system, or flagging a case that genuinely can't be made self-evident through naming/structure. Never comment what the code already says; prefer clearer names and smaller functions over a comment explaining an unclear one. ## Data layer (Drizzle + Postgres) - Schema lives in `src/db/schema.ts`; the Drizzle client is created once in `src/db/index.ts` and imported from there — don't instantiate new clients elsewhere. - Only import `db/*` from server-only code (route `loader`s/`action`s, server functions) — never from client components, to avoid leaking DB credentials into the client bundle. - Query with Drizzle's query builder (`db.select()...`, `db.query.table...`) rather than raw SQL, unless a query genuinely needs it. - After changing `schema.ts`, generate a migration rather than editing the database by hand: ```bash pnpm drizzle-kit generate # create a migration from schema changes pnpm drizzle-kit migrate # apply pending migrations ``` - Never hand-edit files under `db/migrations/` — they're generated and should be treated as a history, not touched retroactively. - [Connection details: env var name for `DATABASE_URL`, whether using a connection pool like `postgres.js` or `node-postgres`, local dev DB setup e.g. Docker Compose] ## Testing - [Test runner and conventions, e.g. Vitest + Testing Library] - [Where tests live: colocated `*.test.ts(x)` vs a `__tests__` dir] - Run the relevant test file after changes, not just the full suite, unless asked to verify broadly. ## Things to avoid - Don't hand-edit `routeTree.gen.ts` or files under `db/migrations/`. - Don't run destructive Drizzle commands (`drizzle-kit push` against a populated DB, or anything that drops columns/tables) without confirming first — prefer `generate` + `migrate` so changes are reviewable. - Don't introduce a new state-management library without asking — prefer route loaders / TanStack Query cache / local state first. - Don't add new dependencies without checking `package.json` for an existing one that already covers the need. - [Any other project-specific guardrails] ## Git / PR conventions - [Commit message style, branch naming, whether Claude should commit automatically or leave changes staged for review] ## Agent skills ### Issue tracker Issues live as Gitea issues on the self-hosted instance at `git.lukas-harat.com` (`lukas/Ghost_Kitchen`), accessed via the REST API with curl (no `tea` CLI installed). See `docs/agents/issue-tracker.md`. ### Triage labels Default canonical label strings (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`) used as-is. See `docs/agents/triage-labels.md`. ### Domain docs Single-context: `CONTEXT.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`.