docs: record the shared auth form, its consent coupling, and the Node switch
Notes that sign-in now has one implementation shared by the auth routes and the cart prompt, and where to change it. Records the marketing consent wording as a cross-boundary duplication in the same class as TAG_COLORS, but with a sharper failure mode: the server stores its copy verbatim so the record says what the customer saw, and a drifted label defeats that silently rather than loudly. An end-to-end test now spans the two sides. Also records that switching the active Node version for a test run is fine provided it is switched back to 18.16.1 afterwards, and expands the modal-route entry to the full route list now that four auth routes use it.
This commit is contained in:
@@ -246,6 +246,8 @@ Neither failure mentions the Node version as the cause, and the first one reads
|
||||
export PATH="/c/Users/tlamb/AppData/Local/nvm/v24.13.1:$PATH"
|
||||
```
|
||||
|
||||
Thom is fine with switching the active version for a test run — `nvm use latest`, then **`nvm use 18.16.1` when finished**, which is not optional since the app's own tooling expects 18.
|
||||
|
||||
Unit tests and `tsc` run fine on 18, so a green `npm test` says nothing about whether the other two suites can even start.
|
||||
|
||||
### E2E constraints — the local database is never reset
|
||||
@@ -270,6 +272,7 @@ Integration tests truncate between cases (`resetDb()` in `tests/integration/setu
|
||||
- **Daily cart reminder emails** fire via `node-cron` inside the app process at 9am container-local time — if the container restarts frequently, reminders could silently stop firing with no alerting on that failure mode.
|
||||
- **Old single-item checkout route files** (`backend/src/routes/paypal.ts`, `backend/src/routes/demo.ts`) are dead code, unmounted but never deleted — safe cleanup opportunity.
|
||||
- **`backend/src/routes/shippingAddresses.ts` USPS OAuth token format** was implemented against the current (2026) USPS Addresses API docs at time of writing, using a JSON-body `client_credentials` request — if USPS changes their API again, this is the first place to check.
|
||||
- **The marketing consent wording is duplicated** between `MARKETING_CONSENT_TEXT` in `backend/src/utils.ts` and the constant of the same name in `frontend/src/customer/AuthForm.tsx`. The server stores its copy verbatim against the customer's consent record, so the whole point is that the record says what the customer actually saw — a label that drifts from the stored string quietly defeats that. This is not hypothetical: before the form was shared there were three wordings in play (the register page's, a shorter one in the cart prompt, and the stored string) and none matched. An e2e test now asserts the rendered label equals the stored wording, which is the only thing spanning the two sides.
|
||||
- **`TAG_COLORS` is duplicated** between `backend/src/utils.ts` and `frontend/src/admin/Tags.tsx`. The server validates against its copy, so editing one alone makes the admin colour picker offer values that get rejected with a `400`. There's no shared module between backend and frontend in this repo to put it in.
|
||||
- **The local e2e database accumulates junk indefinitely** — every Playwright run seeds categories, tags, and items that are never cleaned up, so the admin tables and filter drawer fill with `Furniture fmsxb…` noise over time. Harmless, but `npm run db:test:down` + `db:test:up` + `migrate:up` resets it when the clutter starts getting in the way. CI is unaffected (fresh service container per run).
|
||||
- **The storefront still lists sold items** and the price-range bounds are computed across all items regardless of status. Deliberately left as-is, and now load-bearing: the favorites filter (#35) shows sold favorites on purpose, since an item that just sold is often what the customer came back to look at after the #34 email. Anyone wanting only purchasable stock combines the favorites toggle with the status filter. Worth revisiting if sold stock ever outnumbers available stock — but changing the default would change what a favorites view means.
|
||||
@@ -282,7 +285,8 @@ 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 came out of #51 — 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 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: everything in `MODAL_ROUTES` (`/account`, `/login`, `/register`, `/forgot-password`, `/reset-password`) 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). The link that opens one must pass `state={{ background: location }}`, or closing goes to the fallback instead of where the customer was; steps *within* a flow navigate with `replace` so the whole detour stays one history entry. This is the pattern to copy for the remaining dead-end pages (#52) — it came out of #51 — 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 sign-in or registration → `frontend/src/customer/AuthForm.tsx`, which is the single implementation. It is rendered both by `AuthRouteModal` (the `/login` and `/register` routes) and by `AuthPromptModal` (the prompt shown when a signed-out visitor adds to the cart, favorites, or filters by favorites). Changing one caller's copy or validation without the other is the drift this deliberately removed.
|
||||
- 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`
|
||||
|
||||
Reference in New Issue
Block a user