Builds the main customer-facing flow: browse the Brand's menu, add items to a cart, and check out either as a guest (name + contact) or, if signed in, as the account customer — both call the existing placeOrder server function, which already distinguishes the two. On success, navigates to a new /orders/$orderId status page showing each Order Item's Preparation Steps, queue position, ETA, and (per the domain rules already established) a Cancel button while cancellable and a pickup-confirmation button once ready. Styled with SCSS Modules per CLAUDE.md; added the sass dependency and the src/styles/ structure it describes (globals.scss imported once in __root.tsx, alongside the existing Tailwind stylesheet the not-yet- mounted header-user.tsx component depends on). Verified end-to-end against a throwaway local Postgres: menu renders with seeded items, cart quantities update, guest checkout places a real order, and the status page reflects a real cancellation. Also fixes CLAUDE.md's Commands section, which documented pnpm even though this repo only has npm (package-lock.json, no pnpm installed). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.1 KiB
7.1 KiB
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
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.)
│ └── <domain>/ # 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.tsxis the root layout every route renders inside.routeTree.gen.tsis generated by TanStack Router — never edit it directly; it regenerates ondev/buildfrom the files inroutes/.- Use route
loaders for data fetching tied to a route, notuseEffect. - Keep server-only code (secrets, DB access) out of files that ship to the
client; be careful with
verbatimModuleSyntaxso server code doesn't leak into client bundles.
Styling (SCSS Modules)
- Every component that needs styles gets a co-located
Component.module.scssnext toComponent.tsx— not a shared stylesheet. - Import as
import styles from './Component.module.scss'and apply classes viaclassName={styles.foo}; never reference a module class by string outside that import. - Class names in
.module.scssfiles are camelCase (e.g..cardHeader, not.card-header) so they read naturally asstyles.cardHeader. - Shared tokens (colors, spacing, breakpoints) live in
src/styles/_variables.scssand are pulled in with@use '~/styles/variables' as *;— don't hardcode colors/spacing that already exist as a variable. src/styles/globals.scssis 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. useas constor a literal type instead of annotating). - Functional React components only, no class components.
- Use arrow functions everywhere (components, handlers, utilities) instead of
the
functionkeyword — e.g.const getUser = async (id: string) => {...}andexport const Button = (props: ButtonProps) => {...}. - [Naming conventions: PascalCase components, camelCase functions/vars, etc.]
- [Import order / path aliases, e.g.
~/or@/forsrc/] - Co-locate a component's test file next to it unless it's a shared
primitive in
components/ui/(see "Styling" for.module.scssplacement). - 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 insrc/db/index.tsand imported from there — don't instantiate new clients elsewhere. - Only import
db/*from server-only code (routeloaders/actions, 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: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 likepostgres.jsornode-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.tsor files underdb/migrations/. - Don't run destructive Drizzle commands (
drizzle-kit pushagainst a populated DB, or anything that drops columns/tables) without confirming first — prefergenerate+migrateso 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.jsonfor 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.