diff --git a/.claude/project-context.md b/.claude/project-context.md index c33160f..4340af0 100644 --- a/.claude/project-context.md +++ b/.claude/project-context.md @@ -213,8 +213,12 @@ sudo docker exec -it redefined-designs-db-syn psql -U redefined -d redefined -c ## Conventions -- **Every commit message follows [Conventional Commits](https://www.conventionalcommits.org/)**: `feat:`, `fix:`, `chore:`, `docs:`, `test:`, `ci:`, `refactor:`, etc. -- **Never commit directly to `main`.** Always branch: `feature/` or `fix/`. Open a PR, merge, branch auto-deletes (repo setting is on). +- **Never commit directly to `main`.** Always branch, open a PR, merge; the branch auto-deletes (repo setting is on). +- **Branches follow [Conventional Branch](https://conventional-branch.github.io/), with the issue number carried for Gitea:** `/-`, e.g. `feature/48-my-account-modal`, `bugfix/57-cart-total-wrong`. Types are `feature`, `bugfix`, `hotfix`, `release`, `chore` — the same `feature/` prefix this repo has always used, so nothing in the existing history is wrong. Drop the number when there is no issue behind the work (`chore/tidy-dead-routes`). The type should agree with the Conventional Commit type of the work it carries. +- **Commits follow [Conventional Commits](https://www.conventionalcommits.org/)** — `feat:`, `fix:`, `chore:`, `docs:`, `test:`, `ci:`, `refactor:` — with the issue number appended to the subject: `feat(account): open My Account as a modal (#48)`. +- **Put `Closes #48` in the commit body**, on its own line, for the commit that completes the issue (`Refs #48` when it only contributes). This is what actually closes the issue on merge, independently of whether the PR description repeats it. +- **Be clear about which part does the linking.** Gitea creates the reference from a `#48` appearing in a *commit message or PR* — never from the branch name. The branch name is for humans reading `git branch`; the reference is what ties the work to the issue. Both are wanted, but only one of them links. +- **Commit bodies are unwrapped paragraphs** — no hard line breaks inside a paragraph. - Local dev/editing happens in **VS Code**, pushed via **PowerShell** `git` — the NAS-side `gitc` workflow is *only* for pulling already-merged code down to deploy, never for authoring changes. - **Thom does the pushing.** Commit locally and stop; don't `git push` on his behalf. - **When work comes from a Gitea issue, post every clarifying question and its answer back to that issue as a comment** — including the options considered and why the rejected ones were rejected. The issue is the durable record; decisions made in a chat session are invisible to anyone reading it later. Post each round as the answers come in rather than batching everything to the end. @@ -276,6 +280,7 @@ Integration tests truncate between cases (`resetDb()` in `tests/integration/setu - Change admin-configurable settings → `admin_settings` table + `backend/src/routes/adminSettings.ts` + `frontend/src/admin/Settings.tsx` - Add a new async route → wrap the handler in `asyncRoute()` from `backend/src/asyncRoute.ts`, or a failure will hang the request instead of returning 500 - Change what an item row returns → `backend/src/itemSelect.ts` (one place, used by both the public and admin routes) +- Change how a customer route is framed (modal vs page) → `frontend/src/main.tsx`. `AppRoutes` renders the route table against a *backdrop* location rather than the real one: `/account` is a modal over the page named in `location.state.background`, falling back to the storefront when there is none (a bookmark, an email link, a post-registration redirect). This is the pattern to copy for the sibling dead-end issues (#49, #50) — it keeps the URL real and linkable while making sure closing always lands somewhere. The link that opens it must pass `state={{ background: location }}`, or closing goes to the fallback instead of where the customer was. - Change storefront filtering → `backend/src/itemFilters.ts` (parsing + SQL), `backend/src/routes/filters.ts` (`/api/filters`, the drawer's single fetch), `frontend/src/filters.ts` (state, URL round-trip, tree building), `frontend/src/components/FilterDrawer.tsx`, `frontend/src/components/ActiveFilterChips.tsx` - Add a filter dimension that depends on who is asking → follow the favorites filter (#35). The identity comes from `req.customerId` (`attachCustomer` runs globally, so it is available on the public `/api/items` too) and is passed into `buildItemFilterSql` as an explicit argument — never parsed from the query string, or a hand-edited URL could name another customer. Each route decides what to do when it cannot satisfy the filter: the storefront answers 401, the admin inventory 400, and the builder throws rather than silently dropping the clause and returning everything. - Change category/tag management → `backend/src/routes/adminCategories.ts`, `backend/src/routes/adminTags.ts`, `frontend/src/admin/Categories.tsx`, `frontend/src/admin/Tags.tsx`