Compare commits
2
Commits
9dee2a4013
...
e532a95f0b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e532a95f0b | ||
|
|
d2806818d2 |
@@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
.env.local
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
# 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
|
||||||
|
- [Auth: Better Auth / Clerk / custom / none yet]
|
||||||
|
- [Package manager: pnpm / npm / bun]
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm dev # start dev server (http://localhost:3000)
|
||||||
|
pnpm build # production build
|
||||||
|
pnpm typecheck # tsc --noEmit
|
||||||
|
pnpm lint # eslint
|
||||||
|
pnpm test # [test runner, e.g. vitest]
|
||||||
|
```
|
||||||
|
|
||||||
|
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.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`.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Domain Docs
|
||||||
|
|
||||||
|
How the engineering skills should consume this repo's domain documentation when exploring the codebase.
|
||||||
|
|
||||||
|
## Before exploring, read these
|
||||||
|
|
||||||
|
- **`CONTEXT.md`** at the repo root, or
|
||||||
|
- **`CONTEXT-MAP.md`** at the repo root if it exists: it points at one `CONTEXT.md` per context. Read each one relevant to the topic.
|
||||||
|
- **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
|
||||||
|
|
||||||
|
If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
This repo is single-context:
|
||||||
|
|
||||||
|
```
|
||||||
|
/
|
||||||
|
├── CONTEXT.md
|
||||||
|
└── docs/adr/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use the glossary's vocabulary
|
||||||
|
|
||||||
|
When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.
|
||||||
|
|
||||||
|
If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).
|
||||||
|
|
||||||
|
## Flag ADR conflicts
|
||||||
|
|
||||||
|
If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
|
||||||
|
|
||||||
|
> _Contradicts ADR-0007 (event-sourced orders), but worth reopening because…_
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Issue tracker: Gitea (self-hosted)
|
||||||
|
|
||||||
|
Issues and specs for this repo live as issues on the self-hosted Gitea instance at `https://git.lukas-harat.com`, repo `lukas/Ghost_Kitchen`. There's no CLI (`tea` isn't installed here), so all operations go through Gitea's REST API (`/api/v1`) via `curl`, authenticated with a personal access token read from the `GITEA_TOKEN` environment variable.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
Base URL: `https://git.lukas-harat.com/api/v1/repos/lukas/Ghost_Kitchen`
|
||||||
|
Auth header on every request: `-H "Authorization: token $GITEA_TOKEN"`
|
||||||
|
|
||||||
|
- **Create an issue**: `POST /issues` with JSON body `{"title": "...", "body": "..."}`. Note: Gitea's create-issue endpoint only accepts label **IDs** (not names) in its `labels` field — create the issue first, then add labels by name (below).
|
||||||
|
- **Read an issue**: `GET /issues/{index}`. Comments separately via `GET /issues/{index}/comments`.
|
||||||
|
- **List issues**: `GET /issues?state=open&type=issues`. Filter by label client-side (via `jq`) since query-string label filtering wants label IDs, not names.
|
||||||
|
- **Comment on an issue**: `POST /issues/{index}/comments` with `{"body": "..."}`.
|
||||||
|
- **Apply labels**: `POST /issues/{index}/labels` with `{"labels": ["needs-triage"]}` — this endpoint accepts label **names** directly, unlike issue creation.
|
||||||
|
- **Remove a label**: `DELETE /issues/{index}/labels/{id}` — this one needs the numeric label ID; look it up via `GET /labels` and `jq` on `name`.
|
||||||
|
- **Close**: `PATCH /issues/{index}` with `{"state": "closed"}`. Post the closing comment first (`POST .../comments`), then close — this call has no comment field.
|
||||||
|
- **Ensure labels exist**: `GET /labels` to check; `POST /labels` with `{"name": "...", "color": "#hex"}` to create any of the five canonical labels that are missing before first use.
|
||||||
|
|
||||||
|
## Pull requests as a triage surface
|
||||||
|
|
||||||
|
**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_
|
||||||
|
|
||||||
|
When set to `yes`, use the `/pulls` endpoints in place of `/issues` (`GET /pulls`, `GET /pulls/{index}`; the comment/label/close calls above are shared between issues and PRs in Gitea's API). Determine "external" by comparing the PR author against `GET /repos/lukas/Ghost_Kitchen/collaborators` — an author who isn't a collaborator or the repo owner is external.
|
||||||
|
|
||||||
|
Gitea numbers issues and PRs from one shared counter per repo (like GitHub), so a bare `#42` may be either; resolve with `GET /issues/42` and fall back to `GET /pulls/42` (or vice versa).
|
||||||
|
|
||||||
|
## When a skill says "publish to the issue tracker"
|
||||||
|
|
||||||
|
Create a Gitea issue via `POST /issues`.
|
||||||
|
|
||||||
|
## When a skill says "fetch the relevant ticket"
|
||||||
|
|
||||||
|
`GET /issues/{index}` plus `GET /issues/{index}/comments`.
|
||||||
|
|
||||||
|
## Wayfinding operations
|
||||||
|
|
||||||
|
Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.
|
||||||
|
|
||||||
|
- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body.
|
||||||
|
- **Child ticket**: an issue carrying `Part of #<map>` at the top of its body and label `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`) — this Gitea version (1.27.2) has no native sub-issue link, so the task-list/text-reference fallback is the only option here. Once claimed, assign the driving dev (`PATCH /issues/{index}` with `{"assignees": ["<username>"]}`).
|
||||||
|
- **Blocking**: Gitea's **native issue dependencies** — the canonical representation (confirmed available on this instance via its swagger spec). Add one with `POST /issues/{child}/dependencies` body `{"index": <blocker-index>, "owner": "lukas", "repo": "Ghost_Kitchen"}` — this makes the child depend on (i.e. be blocked by) the blocker. List with `GET /issues/{index}/dependencies`. A ticket is unblocked when every listed dependency is closed.
|
||||||
|
- **Frontier query**: list the map's open children, drop any with an open (not-closed) entry in `GET /issues/{index}/dependencies` or an assignee; first in map order wins.
|
||||||
|
- **Claim**: `PATCH /issues/{index}` with `{"assignees": ["<username>"]}`, the session's first write.
|
||||||
|
- **Resolve**: `POST /issues/{index}/comments` with the answer, then `PATCH /issues/{index}` with `{"state": "closed"}`, then append a context pointer (gist + link) to the map's Decisions-so-far.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Triage Labels
|
||||||
|
|
||||||
|
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
|
||||||
|
|
||||||
|
| Label in mattpocock/skills | Label in our tracker | Meaning |
|
||||||
|
| --------------------------- | --------------------- | ----------------------------------------- |
|
||||||
|
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
|
||||||
|
| `needs-info` | `needs-info` | Waiting on reporter for more information |
|
||||||
|
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
|
||||||
|
| `ready-for-human` | `ready-for-human` | Requires human implementation |
|
||||||
|
| `wontfix` | `wontfix` | Will not be actioned |
|
||||||
|
|
||||||
|
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
|
||||||
|
|
||||||
|
These labels may not exist yet in the Gitea repo — see the "Ensure labels exist" step in `issue-tracker.md` to create any that are missing before first use.
|
||||||
Reference in New Issue
Block a user