For Claude / Cursor / future AI assistants
This manual is written for the AI that works on the SlabTrack codebase. Read this before making changes — it captures conventions, file ownership, recent decisions, and patterns that aren't obvious from reading code alone. A structured JSON sidecar at /docs/ai/index.json exposes the same content for programmatic fetching.
This page is your primer. The pages linked below are the deep references. index.json is the same content in machine-readable form — fetch it once, get every pattern + convention without making 6 separate file reads.
The three repos
- slabtrack at
~/OneDrive/Desktop/GitHub/slabtrack— Express 5 + React 19 (Vite) + Postgres. The operator brain. Branch:main. - thisorthat at
~/OneDrive/Desktop/GitHub/thisorthat— Next.js 16 + Postgres + Prisma. The marketplace. Branch:master. - slabtrack-storefront at
~/OneDrive/Desktop/GitHub/slabtrack-storefront— Next.js 16 + Postgres + Prisma. Multi-tenant shops. Branch:master.
Sub-pages
- Codebase Map — directory layout per repo, key files, what's where
- Conventions — commit messages, code style, security rules
- Patterns — how to add an endpoint, a Prisma field, a new page
- File Ownership — which files are authoritative for which features (so you know where to look when X breaks)
- Recent Decisions — significant architectural moves of the last 30 days
- index.json — structured version of all the above for programmatic fetch
Hard rules (read first, ALWAYS follow)
Never touch app code when only docs were requested
If the user asks for "docs" / "manual" / "reference guide" updates, work ONLY in /docs/ and /frontend/public/docs/. Don't refactor a route to align with new docs. Don't touch the app code unless explicitly asked.
Never commit secrets
No real Stripe keys, no real Shippo tokens, no real JWT_SECRET values in any file — including .env.example. The example files use sk_test_... placeholder format only.
Never skip pre-commit hooks
If a commit fails because of a hook, FIX the underlying issue. Don't pass --no-verify. Don't pass --no-gpg-sign. Don't bypass anything.
Always run type check before committing TS/TSX changes
Both thisorthat and slabtrack-storefront are TypeScript. Run npx tsc --noEmit -p . before committing. Catch type errors locally — Railway's silent build failures are painful.
Match the commit message style
See Conventions for the full pattern. Headlines: lowercase verb-first, scope-prefixed. Body: explain WHY, not WHAT. Co-authored-by trailer included.
Production-critical files (don't break these)
| File | Why critical |
|---|---|
thisorthat/src/app/api/webhook/ingest/route.ts | SlabTrack → ToT publish path. Breaking it means commits silently fail to surface listings. |
thisorthat/src/app/api/stripe/webhook/route.ts | Pull/Flip settlement + refunds + dispute auto-evidence. Breaking it loses payments. |
slabtrack-storefront/src/app/api/stripe/webhook/route.ts | Storefront order state. Breaking it leaves Orders pending forever after paid. |
slabtrack/backend/services/sale-lock-service.js | Cross-channel coordination. Breaking it allows double-sales. |
slabtrack/backend/routes/curator.routes.js | Strategist commits. 3000+ lines, lots of fan-out logic. |
slabtrack-storefront/src/lib/storefront-theme.ts | Theme resolver. Every theme studio change reads from here. |
Common mistakes I've seen (don't repeat)
Adding a new theme field but only updating Prisma schema
Theme fields require updates in 4 places: schema → resolver → API validator → ThemeStudio form. Skipping any of them = silent partial save. See Patterns → Adding a theme field.
Stripe API version drift
For ToT, use the singleton at src/lib/stripe.ts (exposes getStripe()). Don't inline new Stripe(...) in route files — version-drift incidents have happened before. Storefront uses src/lib/stripe.ts too.
Forgetting idempotency keys on Stripe creates
Every stripe.checkout.sessions.create, stripe.refunds.create, stripe.paymentIntents.create needs an idempotency key. Pattern: {action}-{stable-input-id} (e.g. refund-{orderId}).
Removing the SHIP_FROM_* fallback assumes blank-from is fine
Shippo will reject blank addresses. ToT's shipping route throws loud now (getOriginAddress()) — don't reintroduce a silent fallback.
Updating this manual when shipping a feature
When you add a substantial feature, update three things:
- The relevant page in
/frontend/public/docs/operator/(or seller / buyer / collector if buyer-facing) /frontend/public/docs/ai/recent-decisions.htmlwith a note + link to commit/frontend/public/docs/ai/index.jsonif the feature changes a pattern or conventions