Files
supabase/apps/studio/CLAUDE.md
Alaister YoungandAlaister Young 2d5ec97df8 chore: split CLAUDE.md into root and studio-specific files (#48202)
Splits agent guidance into a lean monorepo-wide root file and a
studio-specific file that Claude Code lazy-loads when working under
`apps/studio/`. This keeps every session's baseline context small while
giving studio work much richer, enforceable guidance.

**Changed:**
- `.claude/CLAUDE.md` — now monorepo-wide only: corrected pnpm version
(10 → 11), expanded workspace table (design-system, ui-library,
lite-studio, ui-patterns, api-types, pg-meta, shared-data), commands
(`format`, `generate:types`, `api:codegen`), CI gates + never-hand-edit
generated files, monorepo-wide conventions (incl. the named-exports
rule, which lives in the shared eslint preset and applies to all six
apps), and monorepo-wide skill triggers. Studio detail is replaced by a
pointer to the nested file. Also corrects a long-standing error
inherited from the old file: the `_Shadcn_` convention was inverted —
`Button_Shadcn_` is the only suffixed export left and is rarely the
right choice; primitives are unsuffixed.
- `.claude/skills/studio-ui-patterns/SKILL.md` — removed the same stale
`_Shadcn_` claim from the forms section (this skill also feeds
CodeRabbit reviews).
- `apps/studio/components/README.md` — component template now uses a
named export, matching the lint-enforced convention (was the one doc
still showing `export default`).
- `apps/studio/TANSTACK_MIGRATION.md` — cleanup checklist gains an item
to remove the migration section from `apps/studio/CLAUDE.md` when the
migration finishes.
- `.gitignore` — removed the blanket `CLAUDE.md` ignore rule (added in
#40231 for personal local files, no longer used that way). Nested
`CLAUDE.md` files are now tracked by default, so shared guidance can't
silently fail to land. For *personal* notes, use `CLAUDE.local.md`
(Claude Code loads it automatically alongside `CLAUDE.md`, and it's now
gitignored here) — or `.git/info/exclude` if you prefer a different
filename.

**Added:**
- `apps/studio/CLAUDE.md` — studio guidance, loaded on demand: mandatory
skill routing (always load `studio-best-practices`, plus a task → skill
table), TanStack Start migration rules (pages/routes mirroring, when a
manual mirror is needed, never delete `pages/**` files),
data-layer/state orientation, a default-to-shipping-tests-with-changes
policy, and a "defaults that differ here" list (ESLint warning ratchet +
local `lint:ratchet` command, `copyToClipboard` await rule, `useParams`
from `common`, dayjs/sonner, `ui` vs `ui-patterns` import split,
`@tanstack/react-table` over `react-data-grid`, etc.).

## Accuracy

Every factual claim in both files (62 total) was verified against the
code by parallel review agents instructed to refute each one. Results:
54 correct as written, 2 wrong (the inherited `_Shadcn_` inversion, and
a fabricated `useExecuteSqlQuery` hook name — the real export is
`useExecuteSqlMutation`), 6 imprecise (e.g. dayjs plugins load in both
runtime entries, the ratchet counts occurrences regardless of severity).
All fixed in this PR.

## Context cost

| File | Size | When it loads | % of a 200k window |
|---|---|---|---|
| `.claude/CLAUDE.md` | 70 lines, ~1.2k est. tokens | every session |
~0.6% |
| `apps/studio/CLAUDE.md` | 53 lines, ~1.6k est. tokens | only when
touching studio files | ~0.8% |

The always-loaded footprint grew only ~0.2k est. tokens vs the old
45-line file — everything studio-heavy sits behind the lazy load, so
docs/www sessions pay nothing for it. Both files are well under Claude
Code's large-file warning threshold (~40k chars) and the <200-line
adherence guidance, with room to roughly double before it's worth
worrying about.

## To test

- Open a fresh Claude Code session from the repo root and read any file
under `apps/studio/` — `apps/studio/CLAUDE.md` should get pulled into
context automatically.
- `git check-ignore apps/studio/CLAUDE.md` exits 1 (not ignored); `git
check-ignore CLAUDE.local.md` exits 0 (ignored).
- Skim both files — every claim has been code-verified (see Accuracy
above), but a human sanity pass on the *judgment* calls (what's
included/omitted) is welcome.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Refreshed monorepo onboarding conventions with updated tooling
requirements, expanded inventory, standardized common scripts, and
clearer CI gating and checks.
* Added/updated Studio contributor guidance, including the TanStack
Start migration rules and Studio development/testing/UI conventions.
  * Updated Studio component documentation to use named exports.
* Refreshed the “Forms” UI pattern guidance and adjusted the referenced
UI primitives.
* **Chores**
* Updated ignore rules so the primary top-level onboarding document is
tracked.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-07-23 01:49:22 +08:00

54 lines
6.4 KiB
Markdown

# Supabase Studio
Next.js pages router + TanStack Start (mid-migration, see below), React 19. Dev server: `pnpm dev:studio` → http://localhost:8082.
## Skills — load before working
**Always load the `studio-best-practices` skill before writing or modifying any Studio code.** Then stack the area-specific skills:
| Task | Additional skills |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| Query/mutation hooks, query keys (`data/**`) | `studio-queries` |
| UI: pages, forms, tables, charts, sheets, empty states | `studio-ui-patterns` |
| Displaying API errors | `studio-error-handling` |
| Tests (deciding, writing, reviewing) | `studio-testing`, then `studio-mock-api-tests` (component/MSW) or `studio-e2e-tests` (Playwright) |
| PostHog event tracking | `telemetry-standards` |
| SQL against user databases | `safe-sql-execution` |
| Logs Explorer SQL, `data/logs` | `clickhouse-logs-queries` |
| Component API design, boolean-prop refactors | `vercel-composition-patterns` |
| User-facing copy | `copywriting` |
## TanStack Start migration
Studio is migrating from the Next.js pages router (`pages/**`) to TanStack Start (`routes/**`). Both runtimes ship side-by-side; the `STUDIO_FRAMEWORK` env var selects which one `pnpm dev`/`build` runs (default: `next`, resolved in `scripts/dispatch.js`). Full route map and strategy: `TANSTACK_MIGRATION.md`.
- **Never delete a page file.** Most `routes/**` files are thin wrappers re-exporting the default export of their `pages/**` counterpart, so the Next file is load-bearing for both runtimes until the final cleanup pass.
- Pure page-body edits propagate to the route automatically. Mirror a change by hand into the corresponding `routes/**` file only when it touches what the route duplicates: `getLayout`/layout wrapping, page titles or other `staticData` (incl. `skip*Layout` flags), `withAuth`, or redirect paths.
- A new page under `pages/**` needs a matching route under `routes/**` plus a checklist entry in `TANSTACK_MIGRATION.md`.
- New code uses native TanStack APIs — no `next/router` or `next/link`. The `compat/next/` shims exist only for legacy re-exported pages.
- `routeTree.gen.ts` is generated by the Vite plugin — never hand-edit.
## Orientation
- **Data layer** — all platform API calls go through `data/fetchers.ts` (`openapi-fetch`, typed by the generated `api-types` package) with `handleError`; never raw `fetch`. One folder per resource in `data/`, most with a `keys.ts` query-key factory.
- **State** — valtio for global state (`state/`), nuqs for URL state, react-hook-form + zod for forms.
- **Platform vs self-hosted** — `IS_PLATFORM` gates platform-only behavior; `withAuth` is a no-op when self-hosted.
- **Telemetry** — `useTrack()` from `lib/telemetry/track`; event types live in `packages/common/telemetry-constants.ts`.
- **Tests** — default to including relevant tests with any change: a couple of unit tests for extracted logic, component tests for UI behavior, E2E only when the scope demands it (`studio-testing` has the decision tree). Not every PR needs them, but "no tests" should be a considered choice, not the default. Tooling: vitest + MSW; component tests use `customRender` + `addAPIMock` from `tests/lib/`; unhandled network requests fail tests. Don't `vi.mock('@/data/...')`.
- **Shortcuts** — use the registry in `state/shortcuts/` and `components/ui/Shortcut*.tsx`; keep `G then …` chords for navigation; no one-off keyboard listeners.
- **Reuse first** — before writing a new hook or helper, search for an existing one (`hooks/`, `lib/`, `packages/common`, `packages/ui-patterns`). If you do need a new one, make it as reusable as possible: general naming, no page-specific coupling, placed where other callers can find it.
- Co-locate sub-components with their parent; avoid barrel re-export files.
## Defaults that differ here
- **ESLint warnings are ratcheted in CI**: the per-rule occurrence count must not increase, so a new `any`, unresolved `exhaustive-deps` warning, or default export fails the build even though it's "only a warning". Check locally with `pnpm --filter studio run lint:ratchet`.
- **Clipboard**: `copyToClipboard` from `'ui'`, and never `await` anything before calling it (Safari requires the write inside the user gesture; lint-enforced) — pass a Promise as the argument instead.
- **`useParams()` comes from `'common'`**, not `next/navigation` — it camelCases keys and returns `string | undefined`.
- **Permissions**: `useAsyncCheckPermissions` from `hooks/misc/useCheckPermissions` (returns `can: true` when self-hosted).
- **Gating**: `useIsFeatureEnabled` for product features, `useFlag` from `'common'` for feature flags — two different systems.
- **Dates**: `dayjs` (plugins pre-loaded at both entries, `pages/_app.tsx` and `routes/__root.tsx`), not `date-fns`. **Toasts**: `toast` from `'sonner'`.
- **Import split**: `'ui'` = primitives, `'ui-patterns'` = composed patterns (`ConfirmationModal`, …), `@ui/*` = alias into `packages/ui/src`. Icons come from `lucide-react`.
- **New tables** use `@tanstack/react-table`; `react-data-grid` is banned for new code.
- **Ad-hoc SQL** against the user's database goes through `executeSql` / `useExecuteSqlMutation` (`data/sql/execute-sql-mutation`).
- **Confirmations**: `ConfirmationModal` / `TextConfirmModal` from `ui-patterns`, never `window.confirm`. Disabled buttons needing an explanation use `ButtonTooltip`; inline warnings use `Admonition`.