mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(skills): move Write the docs skills into the monorepo — DO NOT REVIEW YET (#48914)
## I have read the CONTRIBUTING.md file. YES ## What kind of change does this PR introduce? Adds four AI agent skills that support docs contributors across the authoring lifecycle, intended to lower the barrier to entry for contributing to our docs. Closes DOCS-1287. ## What is the current behavior? Our process for writing docs is somewhat undefined beyond some general guidance in CONTRIBUTING.md and we don't make as easy to contribute to our docs as we could. As a result, content often needs additional changes during PR reviews or requires further revisions after merging. The four AI agent skills in this PR already existed in a private repo where I've been testing them but they were not previously available for general use until now. ## What is the new behavior? - Four skills added under `.agents/skills/`, symlinked from `.claude/skills/` and `.cursor/skills/` (same pattern as the existing `vitest` skill). - `ask-the-docs`: answers architecture and design questions about apps/docs (MDX pipeline, content components, federated docs) and checks whether a proposed change fits existing docs app patterns. - `write-the-docs`: drafts net-new or substantially rewritten docs content for a feature or launch, grounded in the Linear ticket, the actual code, and the docs style guide. - `review-the-docs`: runs a local, PR-type-specific review checklist against any open supabase/supabase docs PR (markdown pipeline, MDX content, tutorials, examples, Studio links) and produces a consolidated report. - `pm-the-docs`: supports "Write the docs" authoring process across the different phases. - `apps/docs/CONTRIBUTING.md` gets a new "AI agent skills for docs authoring" section mapping each skill to its checklist stage - Cross-references to skills that stay in `docs-agent-skills` (`work-linear-issue`, `audit-docs-ia`, `create-pull-request`, `proof-it-works`, `pm-the-docs-full`) now point there via absolute GitHub links instead of relative paths ## Additional context - Companion PR: [supabase/docs-agent-skills#28](https://github.com/supabase/docs-agent-skills/pull/28). Removes the three moved skills, renames `pm-the-docs` to `pm-the-docs-full`, and fixes now-dangling inbound links. - Worktree: `~/GitHub/supabase/supabase-worktrees/nikrichers/docs-1287-move-skills-mentioned-in-write-the-docs-from-docs-agent` - Opened as draft: this is a docs-authoring-tooling change with no runtime/build surface. Flip to ready once you've sanity-checked the skill content. ### Test plan - [ ] `ls -la .claude/skills/{ask-the-docs,pm-the-docs,write-the-docs,review-the-docs}` resolves to `.agents/skills/...` - [ ] Open a fresh Claude Code session with cwd in this repo and confirm `/ask-the-docs`, `/pm-the-docs`, `/write-the-docs`, `/review-the-docs` are available - [ ] Read the new section in [`apps/docs/CONTRIBUTING.md`](apps/docs/CONTRIBUTING.md) in context - [ ] Spot-check `.agents/skills/pm-the-docs/reference/write-the-docs-checklist.md` has no `linear.app` links and carries the snapshot disclaimer --------- Co-authored-by: Nik Richers <nik@validmind.ai>
This commit is contained in:
1 parent
8baaa517d0
commit
cf36ad9e52
27 files changed
+2494
No files matched your search
@@ -0,0 +1,134 @@
|
||||
---
|
||||
name: ask-the-docs
|
||||
description: >-
|
||||
Answer questions about the Supabase docs app (apps/docs) using
|
||||
documented architecture, build pipeline, and review-pattern notes, and
|
||||
apply feature-design principles (codebase reuse, coding minimalism)
|
||||
when proposing or critiquing changes. Use when the user asks "how does
|
||||
X work in the docs app?", "where does Y live?", "is this approach OK
|
||||
for the docs app?", or before writing non-trivial changes under
|
||||
apps/docs/ — especially anything touching the MDX pipeline, markdown
|
||||
generation, content components, federated docs, or contributor-facing
|
||||
authoring patterns. Can answer architecture questions with Mermaid
|
||||
diagrams when helpful.
|
||||
---
|
||||
|
||||
# Ask the docs-app librarian
|
||||
|
||||
A reference for `apps/docs` knowledge — architecture, build pipeline,
|
||||
federated docs, known fragilities — plus the feature-design principles
|
||||
the codebase rewards: **understand and reuse the existing code before
|
||||
writing new code**, and **practice coding minimalism** to keep the
|
||||
surface area small.
|
||||
|
||||
Two jobs:
|
||||
|
||||
1. **Look up what's already documented** about the docs app —
|
||||
architecture, tradeoffs, gotchas, prior decisions — instead of
|
||||
re-deriving from cold reads.
|
||||
2. **Pre-empt review feedback** by applying the codebase-reuse /
|
||||
minimalism principles before opening a PR. Catches the "fix it in the
|
||||
next round" comments early.
|
||||
|
||||
## When to invoke
|
||||
|
||||
- User asks about `apps/docs` architecture, conventions, or behavior
|
||||
("how does the markdown pipeline work?", "where do listings data files
|
||||
go?", "why does Troubleshooting have a `.mjs` utils file?").
|
||||
- User asks about LLM/agent consumption (`llms.txt`, markdown negotiation,
|
||||
`searchDocs`, bulk exports, agent onboarding guides, humans vs agents vs
|
||||
crawlers, AI prompt blocks in quickstarts).
|
||||
- About to write code under `apps/docs/` that touches: MDX components,
|
||||
`internals/markdown-schema/`, `generate-guides-markdown.ts`, content
|
||||
data modules, the lint pipeline, telemetry events, contributor-facing
|
||||
snippets, federated routes, reference codegen, or Management API /
|
||||
OpenAPI reference pages.
|
||||
- Reviewing a docs-app PR and want a sanity check against the documented
|
||||
principles.
|
||||
|
||||
**Not for:** general Supabase docs _content_ questions (use
|
||||
`work-linear-issue`, `audit-quickstarts`, etc.), or app-level work outside
|
||||
`apps/docs/`.
|
||||
|
||||
## Answering with diagrams
|
||||
|
||||
Architecture and pipeline questions are often clearer with a diagram
|
||||
than with prose. Default to including a **Mermaid diagram** in answers
|
||||
about:
|
||||
|
||||
- The MDX runtime vs markdown-export pipeline split.
|
||||
- Build flow (Turbo → pnpm `prebuild` / `build` / `postbuild` → Vercel).
|
||||
- LLM/agent consumption surface (`llms.txt`, negotiation, bulk exports).
|
||||
- Federated docs fetch flow.
|
||||
- CI / PR flow.
|
||||
- Component / data-registry relationships.
|
||||
- Management API OpenAPI → codegen → reference page flow.
|
||||
|
||||
Mermaid fences (`` ```mermaid `````) render natively on GitHub, Cursor,
|
||||
and most Markdown previewers. Several reference files already embed
|
||||
Mermaid; reuse or adapt them rather than re-deriving.
|
||||
|
||||
Keep diagrams **small and one-topic**. If a diagram needs more than a
|
||||
dozen nodes, split it.
|
||||
|
||||
## Reference files
|
||||
|
||||
Short, focused docs under `reference/`. Read whichever apply to the task
|
||||
at hand — they cite each other where context matters.
|
||||
|
||||
| File | What's inside |
|
||||
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`reference/adding-features.md`](./reference/adding-features.md) | Best-practices guidance for adding features to `apps/docs`. Inventory existing code first, pick the smallest viable shape, reuse pipelines. |
|
||||
| [`reference/docs-app-direction.md`](./reference/docs-app-direction.md) | Refactoring vision and working norms — what new work should align with. |
|
||||
| [`reference/known-issues.md`](./reference/known-issues.md) | Living list of broken, fragile, or in-flux systems. Check before depending on anything (federated docs, search, Sentry, reference-page architecture). |
|
||||
| [`reference/app-map.md`](./reference/app-map.md) | Architecture cheat sheet — directories, the two-pipeline (MDX runtime + markdown export) model, heading/typography contract, telemetry, lint entries. |
|
||||
| [`reference/build-pipeline.md`](./reference/build-pipeline.md) | Turborepo + pnpm lifecycle steps for building `apps/docs` — codegen, prebuild, postbuild, Vercel deploy. Mermaid diagram included. |
|
||||
| [`reference/llm-agent-surface.md`](./reference/llm-agent-surface.md) | Audience routing, `llms.txt`, content negotiation, bulk exports. |
|
||||
| [`reference/llm-agent-parity.md`](./reference/llm-agent-parity.md) | HTML↔markdown fidelity (e.g. AI prompts), search caveat, agent onboarding guides, in-flux wiring. |
|
||||
| [`reference/federated-docs.md`](./reference/federated-docs.md) | How docs pulls markdown from external repos at build time. Routes, `pageMap`, remark/rehype plugins, link transforms, known failure modes. |
|
||||
| [`reference/ci-and-lint.md`](./reference/ci-and-lint.md) | GitHub Actions on every PR — `docs_lint`, `Docs Tests`, typecheck, prettier, Vercel preview gate. Where to add a check before creating a new one. |
|
||||
| [`reference/management-api-reference.md`](./reference/management-api-reference.md) | Management API OpenAPI download → Redocly bundle → codegen → `ApiEndpointSection`; why not to swap in Scalar/Redoc. |
|
||||
| [`reference/gotchas.md`](./reference/gotchas.md) | Specific traps to watch for. One-liner per item. |
|
||||
|
||||
## How to use during a chat
|
||||
|
||||
1. **Start by reading** `adding-features.md` and `app-map.md` if the
|
||||
question touches design choices or unfamiliar code paths. They're
|
||||
small on purpose — read both, don't skim.
|
||||
2. **Verify before recommending.** Reference content may lag behind the
|
||||
live code. Confirm with the actual files (`apps/docs/...`) before
|
||||
acting on remembered claims about file paths, function names, or
|
||||
behavior.
|
||||
3. **Cite the principle**, not just the rule. "Per `adding-features.md`
|
||||
§ 'Reuse pipelines, don't fork them', this routes through the
|
||||
existing markdown-schema handler rather than introducing a side
|
||||
path."
|
||||
4. **Reach for Mermaid** when explaining architecture, flows, or
|
||||
relationships — see [Answering with diagrams](#answering-with-diagrams).
|
||||
|
||||
## Updating the librarian
|
||||
|
||||
This skill lives in `.agents/skills/ask-the-docs/` in `supabase/supabase`.
|
||||
When something in `apps/docs` changes in a way that makes a reference
|
||||
file inaccurate, or a generally-applicable lesson emerges from a PR
|
||||
review, open a pull request against this repo to update the relevant
|
||||
file, same as any other in-repo change.
|
||||
|
||||
Keep each canonical file under ~250 lines; split before they bloat.
|
||||
Capture only what a future contributor would benefit from knowing — if
|
||||
a fact is already obvious from a quick read of the live code, don't
|
||||
write it down.
|
||||
|
||||
## Related skills
|
||||
|
||||
- [`pm-the-docs`](../pm-the-docs/SKILL.md) — audience, stage, and
|
||||
cross-cutting scope calls (Frame stage of the "Write the docs" checklist,
|
||||
mirrored in `pm-the-docs`'s reference file).
|
||||
- [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md) — implementing
|
||||
assigned DOCS-\* tickets.
|
||||
- [`review-the-docs`](../review-the-docs/SKILL.md) — reviewing open docs
|
||||
PRs with type-specific verification.
|
||||
- [`audit-content-listings`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/audit-content-listings/SKILL.md) — batch
|
||||
conversion of overview pages to content listings.
|
||||
- [`create-pull-request`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/create-pull-request/SKILL.md) — opening or
|
||||
updating a docs PR.
|
||||
@@ -0,0 +1,206 @@
|
||||
# Adding features to `apps/docs`
|
||||
|
||||
Best-practices guidance for adding features to the docs app. Read this
|
||||
**before** writing code — most "fix it in the next round" review comments
|
||||
trace back to skipping one of these steps.
|
||||
|
||||
The premise: `apps/docs` has accumulated significant surface area already.
|
||||
Any new file, build step, lint job, or content shape is a permanent
|
||||
maintenance cost. The goal is to deliver the feature with the smallest
|
||||
durable footprint by **understanding the existing code first** and
|
||||
**reusing what's already there**.
|
||||
|
||||
## The cost lens
|
||||
|
||||
Every change adds one of two things:
|
||||
|
||||
- **Reach** — the feature now does more (user-visible value).
|
||||
- **Surface** — there is now more code, configuration, or vocabulary to
|
||||
maintain (recurring cost).
|
||||
|
||||
A good change maximizes reach per unit of surface. When a design discussion
|
||||
stalls, re-frame as: _"Does the user-visible improvement justify the
|
||||
maintenance cost?"_ If you cannot answer yes confidently, cut scope before
|
||||
defending the design.
|
||||
|
||||
See [`docs-app-direction.md`](./docs-app-direction.md) for the broader
|
||||
context — the docs app already carries known tech debt, and the maintainer's
|
||||
stated direction is to reduce surface, not extend it.
|
||||
|
||||
## Step 1 — Inventory before you write
|
||||
|
||||
Before adding a file, search for what's already there. The docs app has
|
||||
existing systems for almost every common job; using them is faster than
|
||||
building parallel ones.
|
||||
|
||||
| Need | Look first at |
|
||||
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| Rendering MDX with a custom component | The MDX component map in `features/docs/MdxBase.shared.tsx` |
|
||||
| Markdown export of a component | The schema registry in `internals/generate-guides-markdown.ts` and handlers in `internals/markdown-schema/` |
|
||||
| Reusable content blocks | `<$Partial path="..." />` and `content/_partials/` |
|
||||
| Headings / typography | `<Heading>` from `MdxBase.shared.tsx`; prose / `not-prose` classes |
|
||||
| Visual primitives (cards, panels, callouts) | `ui-patterns/GlassPanel`, `ui-patterns/IconPanel`, `ui/Admonition`, etc. |
|
||||
| Internal vs external link logic | `withDocsBasePath` / `addBaseUrlPrefix` in `lib/internal-links.ts` |
|
||||
| Telemetry | `useSendTelemetryEvent` + `packages/common/telemetry-constants.ts` |
|
||||
| Validation / schemas | `zod` schemas under `apps/docs/lib/` |
|
||||
| Code samples in MDX | `$CodeSample` directive |
|
||||
| Build steps | `prebuild` / `postbuild` chain in `apps/docs/package.json` |
|
||||
| CI checks | Existing workflows under `.github/workflows/`. See [`ci-and-lint.md`](./ci-and-lint.md). |
|
||||
| Lint rules for MDX content | `supa-mdx-lint` configuration — extend it, don't add a new lint job |
|
||||
|
||||
If something close to what you need already exists, **the default is to
|
||||
extend it**, not to build alongside.
|
||||
|
||||
## Step 2 — Pick the smallest viable shape
|
||||
|
||||
For most feature requests, the shapes in descending order of preference are:
|
||||
|
||||
1. **Pure content change** — MDX edit, partial, or data file. No new code.
|
||||
2. **Configuration of an existing component** — pass a new prop to an
|
||||
existing primitive; extend a config object.
|
||||
3. **A new data shape consumed by existing components** — a typed
|
||||
`*.data.ts` module read by an already-registered MDX component.
|
||||
4. **A thin component that composes existing primitives** — a small file
|
||||
that orchestrates `<Link>`, `<GlassPanel>`, `<Heading>`, etc. Adds an
|
||||
MDX component-map entry but no new visual primitives.
|
||||
5. **A new primitive in the design system** — last resort. Justify against
|
||||
`packages/ui` / `ui-patterns`.
|
||||
|
||||
Move down the list only when the option above genuinely cannot express the
|
||||
feature. The further down you go, the more you should write down why.
|
||||
|
||||
## Step 3 — Reuse pipelines, don't fork them
|
||||
|
||||
If a feature has to render in more than one place (HTML + markdown export,
|
||||
runtime + build, etc.), wire both consumers through a **single shared
|
||||
shape** — a data registry, a schema, a constant map — instead of
|
||||
maintaining parallel implementations.
|
||||
|
||||
Pattern that works well in this codebase:
|
||||
|
||||
- The MDX component reads from a data registry keyed by an `id`.
|
||||
- The markdown-export handler reads from the _same_ registry, using the
|
||||
same `id` carried as a JSX prop.
|
||||
- The data shape (zod schema) is the single source of truth.
|
||||
|
||||
Antipatterns to avoid:
|
||||
|
||||
- Two extraction paths that serialize the same content differently.
|
||||
- A bespoke link-wrapper component when `<Link>` + `<GlassPanel>` already
|
||||
covers the pattern — compose at the call site instead.
|
||||
- New custom build steps that run alongside the existing `prebuild` /
|
||||
`postbuild` chain when a hook already exists.
|
||||
- A new CI workflow when `docs_lint`, `Docs Tests`, or the existing
|
||||
typecheck/prettier jobs could absorb the check. See
|
||||
[`ci-and-lint.md`](./ci-and-lint.md).
|
||||
- A new content vocabulary (custom front-matter block, novel MDX directive,
|
||||
new YAML schema) when a React component + partial would express the same
|
||||
thing.
|
||||
|
||||
## Step 4 — Conventions that keep the diff small
|
||||
|
||||
These are the patterns most often called out in PR review. None of them
|
||||
matter individually; together they keep the surface tight.
|
||||
|
||||
### File naming
|
||||
|
||||
A file's name matches what it exports. If the file exports `Foo`, it's
|
||||
`Foo.ts(x)`. The directory listing should answer "what's in here?" without
|
||||
opening the file. Same for handler files in `internals/markdown-schema/` —
|
||||
the file name is the JSX element name.
|
||||
|
||||
### Import aliases
|
||||
|
||||
`import { Foo as Bar }` is reserved for genuine name collisions. Aliasing
|
||||
for "clarity" or "consistency with old naming" adds friction.
|
||||
|
||||
### Single-use helpers stay inline
|
||||
|
||||
A helper used in one place lives in that place. New files are for shared
|
||||
code. Wandering helpers in unrelated folders make code hard to find.
|
||||
|
||||
### Pure helpers live in `*.utils.ts`
|
||||
|
||||
Schema files hold schemas. Data / constant files hold data. Helpers —
|
||||
including lookups like `getXById` over a constant map — live in
|
||||
`X.utils.ts`. Predictable location beats "logical grouping by concept."
|
||||
|
||||
### Don't override the design system
|
||||
|
||||
Use shared primitives (`<Heading>`, `<GlassPanel>`, prose classes) and let
|
||||
them carry typography and spacing. Adding `text-xl` or `font-semibold` to
|
||||
a new component is the wrong escape hatch.
|
||||
|
||||
### Keep `internals/` out of client and MDX code
|
||||
|
||||
`apps/docs/internals/` is for build-time markdown generation. Client
|
||||
components and the MDX runtime should not import from it. If a function is
|
||||
needed on both sides, it belongs in `lib/`.
|
||||
|
||||
### Markup follows semantics, not visuals
|
||||
|
||||
A collection of links is a `<ul>`, regardless of whether it visually
|
||||
renders as a list or a grid. CSS handles layout; markup handles semantics.
|
||||
|
||||
### Collapse near-duplicates with discriminator props
|
||||
|
||||
When two components share structure and differ only in classes or markup
|
||||
details, collapse them. Extract the differences into class-name constants
|
||||
keyed by the discriminator (`type: 'grid' | 'list'`). Don't ship two
|
||||
components that are 90% identical.
|
||||
|
||||
### Use maps / lookups over arithmetic on known sets
|
||||
|
||||
If the input domain is `'h2' | 'h3' | 'h4'`, a `Map` (or `Record<Literal, T>`)
|
||||
keyed by those literals is clearer than slicing strings and synthesizing
|
||||
output. Exhaustiveness checking comes along for free.
|
||||
|
||||
### Avoid render-time closure churn
|
||||
|
||||
Hooks should return _stable_ callbacks (`useCallback`) that consumers
|
||||
invoke, not curried builders that create a new closure per item per render.
|
||||
Inline arrow functions at the call site are fine; building closures in a
|
||||
loop during render is not.
|
||||
|
||||
### Be robust on URL / string parsing
|
||||
|
||||
`/^https?:\/\//i` is incomplete. Protocol-relative (`//host`), `mailto:`,
|
||||
`tel:`, and bare schemes are all external. Prefer `new URL(href, base)` or
|
||||
a regex that covers `^(?:[a-z][a-z0-9+\-.]*:|\/\/)`.
|
||||
|
||||
### Keep diffs minimal
|
||||
|
||||
Import reordering, prettier reflows, or unrelated whitespace edits in a
|
||||
feature PR muddy the review. If a file isn't conceptually part of the
|
||||
change, revert it. Auto-formatter ran on a file you didn't touch? Reset
|
||||
it.
|
||||
|
||||
## Step 5 — Pre-flight before opening the PR
|
||||
|
||||
Run through this checklist before pushing:
|
||||
|
||||
- [ ] Searched the inventory in Step 1 for existing primitives / pipelines.
|
||||
- [ ] Picked the smallest shape that delivers the feature (Step 2).
|
||||
- [ ] Renders consistently across pipelines that share content (Step 3).
|
||||
- [ ] File and export names match (Step 4 — file naming).
|
||||
- [ ] No unnecessary helpers, imports, files, or aliases.
|
||||
- [ ] Typography defers to shared primitives.
|
||||
- [ ] No `internals/` imports from client / MDX code.
|
||||
- [ ] Diff contains only changes relevant to the feature.
|
||||
- [ ] `pnpm format`, `pnpm typecheck`, and the relevant lint job pass.
|
||||
|
||||
Replies on review threads move faster when they point to a specific commit
|
||||
("done in abc1234") than when they explain the reasoning at length.
|
||||
Expect review to come in **passes** that go progressively deeper — that is
|
||||
the path to a minimum-surface design, not nitpicking.
|
||||
|
||||
## Related
|
||||
|
||||
- [`docs-app-direction.md`](./docs-app-direction.md) — broader context on
|
||||
the docs app's tech debt and refactoring direction.
|
||||
- [`app-map.md`](./app-map.md) — where each existing seam lives.
|
||||
- [`build-pipeline.md`](./build-pipeline.md) — the build steps you should
|
||||
consider extending before adding a new one.
|
||||
- [`ci-and-lint.md`](./ci-and-lint.md) — the CI checks you should consider
|
||||
extending before adding a new workflow.
|
||||
- [`gotchas.md`](./gotchas.md) — specific traps known to bite.
|
||||
@@ -0,0 +1,242 @@
|
||||
# `apps/docs` architecture map
|
||||
|
||||
What lives where, and what depends on what. **Verify against the live tree
|
||||
before acting** — paths drift. Cross-references the per-topic deep dives in
|
||||
this folder.
|
||||
|
||||
## High-level architecture
|
||||
|
||||
`apps/docs` is a **Next.js 15 App Router** site served at **`/docs`**
|
||||
(`basePath` in `next.config.mjs`). It combines hand-written MDX guides,
|
||||
machine-generated reference docs, troubleshooting content, federated content
|
||||
from external repos, and shared monorepo packages (`ui`, `common`,
|
||||
`ui-patterns`, etc.).
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph routes ["app/ — Next.js routes"]
|
||||
guides["/guides/*"]
|
||||
reference["/reference/*"]
|
||||
api["/api/*"]
|
||||
end
|
||||
|
||||
subgraph content ["Content sources"]
|
||||
mdx["content/guides/*.mdx"]
|
||||
trouble["content/troubleshooting/*.mdx"]
|
||||
spec["spec/*.yml, *.json"]
|
||||
generated["features/docs/generated/**"]
|
||||
refmdx["docs/ref/*.mdx"]
|
||||
fed["External repos<br/>(federated)"]
|
||||
end
|
||||
|
||||
subgraph render ["Rendering layer"]
|
||||
features["features/docs/"]
|
||||
components["components/"]
|
||||
layouts["layouts/"]
|
||||
end
|
||||
|
||||
guides --> mdx
|
||||
guides --> trouble
|
||||
guides --> fed
|
||||
reference --> spec
|
||||
reference --> generated
|
||||
reference --> refmdx
|
||||
guides --> features
|
||||
reference --> features
|
||||
features --> components
|
||||
features --> layouts
|
||||
```
|
||||
|
||||
## Top-level directory layout
|
||||
|
||||
| Path | Purpose | Notes |
|
||||
| -------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `app/` | Next.js App Router — thin route files that delegate to feature modules | Slug-based catch-alls per section, e.g. `guides/auth/[[...slug]]/page.tsx` |
|
||||
| `apps/docs/content/guides/` | Source MDX for `/docs/guides/...` pages | One file per page; `_partials/` for shared blocks |
|
||||
| `apps/docs/content/_partials/` | Reusable MDX snippets included via `<$Partial path="..." />` | Recursion supported |
|
||||
| `apps/docs/content/troubleshooting/` | Troubleshooting articles | Some synced from GitHub issues via `Troubleshooting.script.mjs` |
|
||||
| `apps/docs/components/` | React components used inside MDX | One folder per component or component family |
|
||||
| `apps/docs/data/` | Typed data modules consumed by components | `.data.ts` suffix; lookup helpers live in `.utils.ts`, not here |
|
||||
| `apps/docs/lib/` | Pure library code shared across pipelines | Schemas (zod), helpers (`.utils.ts`), tests |
|
||||
| `apps/docs/features/docs/` | Page-level skeletons and the MDX renderer (`MdxBase`) | Shared `<Heading>` lives in `MdxBase.shared.tsx` |
|
||||
| `apps/docs/features/` | Domain logic — docs rendering, auth, search/command menu, telemetry, app providers | `app.providers.tsx` wires React Query, theme, dev toolbar, command menu |
|
||||
| `apps/docs/spec/` | Source-of-truth specs for reference generation | OpenAPI, SDK YAML, CLI config |
|
||||
| `apps/docs/generator/` | Codegen templates for reference docs | |
|
||||
| `apps/docs/resources/` | Data loaders (guide, reference, search, errors) | |
|
||||
| `apps/docs/internals/` | Build-time markdown generation | **Do not import from runtime/client code** |
|
||||
| `apps/docs/internals/markdown-schema/` | Per-component handlers: JSX → markdown string | File name matches the component name |
|
||||
| `apps/docs/public/markdown/guides/` | Generated `.md` output; served via `/docs/guides/<path>.md` or `Accept: text/markdown` | Built by `generate-guides-markdown.ts`; see [`llm-agent-surface.md`](./llm-agent-surface.md) |
|
||||
| `apps/docs/public/markdown/reference/` | Generated reference `.md` files | Built by `generate-reference-markdown.ts` |
|
||||
| `apps/docs/middleware.ts` | Content negotiation for guides; bot rewrite for reference deep links | Uses `packages/common/markdown-negotiation.ts` |
|
||||
| `apps/docs/app/api/guides-md/` | Serves pre-generated guide markdown to agents | Rewritten from `/docs/guides/<path>.md` |
|
||||
| `apps/docs/examples/` | Copied from repo root `examples/` at build time | `codegen:examples` |
|
||||
| `apps/docs/scripts/` | Build-time scripts (sitemap, markdown export, embeddings) | |
|
||||
|
||||
Published guide sections: `ai`, `api`, `auth`, `cron`, `database`, `deployment`,
|
||||
`functions`, `getting-started`, `integrations`, `local-development`, `platform`,
|
||||
`queues`, `realtime`, `resources`, `security`, `self-hosting`, `storage`,
|
||||
`telemetry`. Each has its own `layout.tsx` for sidebar navigation.
|
||||
|
||||
## Content types
|
||||
|
||||
| Type | Location | Notes |
|
||||
| ---------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Guides / tutorials** | `content/guides/` | Hand-written MDX; goal-oriented |
|
||||
| **Troubleshooting** | `content/troubleshooting/` | Partly synced from GitHub issues |
|
||||
| **Reference** | Generated from `spec/` → `features/docs/generated/**` | Spec-driven (OpenAPI, SDKSpec, ConfigSpec, CLISpec). Reference pages do **not** use the standard MDX path — see [`docs-app-direction.md`](./docs-app-direction.md) for why. Management API OpenAPI path: [`management-api-reference.md`](./management-api-reference.md). |
|
||||
| **Federated** | External repos at build time | Pulled via GitHub App. See [`federated-docs.md`](./federated-docs.md) |
|
||||
|
||||
## Routing model
|
||||
|
||||
Routes stay **thin**; rendering lives in **`features/docs/`**.
|
||||
|
||||
```tsx
|
||||
// app/guides/getting-started/[[...slug]]/page.tsx
|
||||
const slug = ['getting-started', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
return <GuideTemplate {...data!} />
|
||||
```
|
||||
|
||||
`getGuidesMarkdown()` (in `features/docs/GuidesMdx.utils.tsx`) loads the file,
|
||||
validates frontmatter, checks navigation enablement, and returns data for
|
||||
`GuideTemplate`.
|
||||
|
||||
`slug` is just the Next.js param name. `[[...slug]]` is an optional catch-all
|
||||
(can match zero or more segments); `[...slug]` is required. The page handler
|
||||
prepends the section name and joins segments to find content on disk.
|
||||
|
||||
For reference, `parseReferencePath(slug)` in `features/docs/Reference.utils.ts`
|
||||
interprets segments like `javascript`, `v2`, `auth-signin` to pick SDK,
|
||||
version, and section.
|
||||
|
||||
## The two pipelines (and why they share data)
|
||||
|
||||
The same content has to render twice:
|
||||
|
||||
1. **MDX runtime** — React components render `<MyComponent id="..." />`,
|
||||
read data via a data registry, output HTML.
|
||||
2. **Markdown export** — `internals/markdown-schema/<MyComponent>.ts`
|
||||
handlers convert the same JSX into plain markdown for
|
||||
`public/markdown/guides/`.
|
||||
|
||||
**Load-bearing rule:** both pipelines dereference the _same_ data
|
||||
registry (typically `apps/docs/data/<topic>/index.ts` exporting an
|
||||
ID-keyed map and a `getById` lookup). The component reads it; the
|
||||
handler reads it. The JSX prop is just an `id`. This keeps the two
|
||||
outputs in sync without a parallel data shape.
|
||||
|
||||
**Reference implementation: `ContentListings`** — the ID-keyed two-pipeline
|
||||
pattern in production:
|
||||
|
||||
| Layer | Path |
|
||||
| ----- | ---- |
|
||||
| Data registry | `apps/docs/data/content-listings/` (`.data.ts` per topic + `index.ts`) |
|
||||
| Runtime component | `apps/docs/components/ContentListings/` |
|
||||
| Markdown handler | `apps/docs/internals/markdown-schema/ContentListings.ts` |
|
||||
| MDX registration | `apps/docs/features/docs/MdxBase.shared.tsx` |
|
||||
|
||||
MDX usage: `<ContentListings id="storage-get-started" />`. For batch
|
||||
overview-page migration, see the `audit-content-listings` skill in
|
||||
[`docs-agent-skills`](https://github.com/supabase/docs-agent-skills).
|
||||
|
||||
When adding a new component that has a markdown representation:
|
||||
|
||||
1. Write the React component under `apps/docs/components/`.
|
||||
2. Add a handler under `apps/docs/internals/markdown-schema/<SameName>.ts`.
|
||||
3. Register the handler in `apps/docs/internals/generate-guides-markdown.ts`
|
||||
(the `SCHEMA` object).
|
||||
4. If a component is purely visual and should be **dropped** from markdown,
|
||||
omit the handler — `generate-guides-markdown.ts` unwraps unknown JSX to its
|
||||
children automatically.
|
||||
|
||||
For the full build flow (Turbo + pnpm lifecycle), see
|
||||
[`build-pipeline.md`](./build-pipeline.md).
|
||||
|
||||
For how agents and LLMs consume exported markdown (negotiation, bulk
|
||||
downloads, `llms.txt`), see [`llm-agent-surface.md`](./llm-agent-surface.md).
|
||||
|
||||
## The markdown export in 30 seconds
|
||||
|
||||
`generate-guides-markdown.ts` walks `content/guides/**/*.mdx`:
|
||||
|
||||
1. Parse MDX → mdast (mdx + gfm extensions).
|
||||
2. Inline `<$Partial path="..." />` recursively.
|
||||
3. `addBaseUrlPrefix(tree)` — prefixes internal links with `/docs/`.
|
||||
4. `applySchema(tree, SCHEMA)` — bottom-up: serializes children first, then
|
||||
replaces each JSX node with the result of its handler (or unwraps it).
|
||||
5. Serialize mdast back to markdown.
|
||||
6. Prepend front-matter-derived header (`# title`, subtitle, description).
|
||||
7. Write to `public/markdown/guides/<same-path>.md`.
|
||||
|
||||
Each `SCHEMA` entry receives `{ props, children, node }` and returns the
|
||||
markdown string to substitute.
|
||||
|
||||
## `<Heading>` and the prose typography contract
|
||||
|
||||
- `<Heading>` from `MdxBase.shared.tsx` is the canonical heading component
|
||||
for MDX. It handles tag-from-level mapping and anchor IDs.
|
||||
- The MDX wrapper applies prose styles to everything inside `.prose` (default
|
||||
for guide pages). Inside `.not-prose` blocks, typography is opt-in.
|
||||
- Pattern for new components with headings: render `<Heading>` _outside_
|
||||
`not-prose`, render the structured layout _inside_ `not-prose`. The heading
|
||||
inherits prose styles; the layout owns its own classes.
|
||||
|
||||
## Telemetry conventions
|
||||
|
||||
- Event names live in `packages/common/telemetry-constants.ts` (snake*case,
|
||||
`docs*\*` prefix for docs events).
|
||||
- Components call `useSendTelemetryEvent()` from `~/lib/telemetry`.
|
||||
- Properties: prefer flat, ID-prefixed keys. Avoid optional spread tricks
|
||||
unless a property is genuinely optional in the schema.
|
||||
|
||||
## Linting and verification entry points
|
||||
|
||||
See [`ci-and-lint.md`](./ci-and-lint.md) for the full CI surface. Local
|
||||
commands:
|
||||
|
||||
| Tool | Where | What it catches |
|
||||
| ------------------------------------------- | ----------- | --------------------------------------------------------- |
|
||||
| `pnpm test:local <path>` (from `apps/docs`) | per-test | Vitest suite for `lib/` and `data/` schemas |
|
||||
| `pnpm format` | repo root | Prettier — run before opening a PR |
|
||||
| `pnpm lint --filter=docs` | repo root | ESLint over `apps/docs` |
|
||||
| `pnpm typecheck` | repo root | TS across packages |
|
||||
| `pnpm build --filter=docs` | repo root | Includes markdown generation; failures here block release |
|
||||
| `pnpm run supa-mdx-lint` | `apps/docs` | MDX content lint |
|
||||
|
||||
Before adding a custom lint job, check whether the existing one can absorb
|
||||
the check (see [`adding-features.md`](./adding-features.md) "Reuse
|
||||
pipelines").
|
||||
|
||||
## Providers (`features/app.providers.tsx`)
|
||||
|
||||
Wraps the app with:
|
||||
|
||||
- `QueryClientProvider` (React Query)
|
||||
- `FeatureFlagProvider`, `ThemeProvider` from `common`
|
||||
- `TooltipProvider` from `ui`
|
||||
- `DevToolbar` from `dev-tools`
|
||||
- `DocsCommandProvider` / `DocsCommandMenu`
|
||||
- `SiteLayout` from `layouts/`
|
||||
|
||||
## Troubleshooting page subtree
|
||||
|
||||
- `features/docs/Troubleshooting.page.tsx` — entry-level page renderer.
|
||||
- `features/docs/Troubleshooting.utils.ts` — TS utils.
|
||||
- `features/docs/Troubleshooting.utils.common.mjs` — `.mjs` because it's
|
||||
consumed by both the Next.js build _and_ a Node sync script with import
|
||||
resolution quirks. **Don't convert to `.ts`** without checking the sync
|
||||
script.
|
||||
- Topics enum in `TroubleshootingSchema` (the `topics` field) is the source
|
||||
of truth for product tag values.
|
||||
|
||||
## Known integrations
|
||||
|
||||
- **Studio** (`apps/studio`) links to docs URLs — check link consistency when
|
||||
changing URL shapes.
|
||||
- **www** (`apps/www`) sometimes embeds docs sections.
|
||||
- **PostHog** receives `docs_*` events for analytics.
|
||||
- **`docs-agent-skills`** repo (https://github.com/supabase/docs-agent-skills)
|
||||
holds batch audit/conversion skills that drive multi-PR docs migrations.
|
||||
- **Federated upstream repos** — see [`federated-docs.md`](./federated-docs.md)
|
||||
for the full list (pg_graphql, vecs, wrappers, terraform-provider, setup-cli,
|
||||
splinter, agent-skills).
|
||||
@@ -0,0 +1,167 @@
|
||||
# Docs build pipeline
|
||||
|
||||
How `apps/docs` is built through Turborepo and pnpm lifecycle hooks.
|
||||
Verify against the current `apps/docs/turbo.jsonc` and
|
||||
`apps/docs/package.json` if behavior surprises you.
|
||||
|
||||
## Build flow
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph turbo["Turborepo — apps/docs/turbo.jsonc"]
|
||||
direction TB
|
||||
WP["^build — workspace deps<br/>(common, ui, config, icons, …)"]
|
||||
CE["codegen:examples<br/>copy ../../examples → apps/docs/examples"]
|
||||
CR["codegen:references<br/>→ features/docs/generated/**"]
|
||||
WP --> DOC["docs#build"]
|
||||
CE --> DOC
|
||||
CR --> DOC
|
||||
end
|
||||
|
||||
subgraph npm["pnpm — apps/docs/package.json"]
|
||||
direction TB
|
||||
PRE["prebuild"]
|
||||
NB["build — next build"]
|
||||
POST["postbuild"]
|
||||
PRE --> NB --> POST
|
||||
end
|
||||
|
||||
DOC --> PRE
|
||||
|
||||
subgraph pre["prebuild steps"]
|
||||
direction LR
|
||||
GQL["codegen:graphql"]
|
||||
REF["codegen:references"]
|
||||
EX["codegen:examples"]
|
||||
GM["build:markdown<br/>(guides + reference)"]
|
||||
GZ["build:gz-archive"]
|
||||
end
|
||||
|
||||
PRE --> GQL
|
||||
PRE --> REF
|
||||
PRE --> EX
|
||||
PRE --> GM
|
||||
PRE --> GZ
|
||||
|
||||
subgraph post["postbuild steps"]
|
||||
direction LR
|
||||
SM["build:sitemap"]
|
||||
CDN["upload-static-assets.sh<br/>(R2, production-style deploys)"]
|
||||
end
|
||||
|
||||
POST --> SM
|
||||
POST --> CDN
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
From the repo root:
|
||||
|
||||
- **Full graph:** `pnpm build` → `turbo run build` (builds every package/app
|
||||
in dependency order).
|
||||
- **Docs only:** `pnpm build:docs` → `turbo run build --filter=docs`.
|
||||
|
||||
```json
|
||||
"build:docs": "turbo run build --filter=docs"
|
||||
```
|
||||
|
||||
## What Turbo does
|
||||
|
||||
Root `turbo.jsonc` defines `build` with `dependsOn: ["^build"]`, so
|
||||
**workspace dependencies** of `docs` (e.g. `common`, `ui`, `config`, …) are
|
||||
built before `docs`.
|
||||
|
||||
`apps/docs/turbo.jsonc` **extends** that and tightens the docs task:
|
||||
|
||||
- **`build` also depends on** `codegen:examples` and `codegen:references`
|
||||
(with explicit inputs/outputs so Turbo can cache them).
|
||||
- It lists **env vars** that affect caching for the docs app.
|
||||
- **`codegen:examples`** copies `../../examples` into `apps/docs/examples`;
|
||||
**`codegen:references`** writes under `features/docs/generated/**`.
|
||||
|
||||
Pipeline Turbo orchestrates for docs: **dependency packages → example /
|
||||
reference codegen → Next build**.
|
||||
|
||||
## What the `docs` package runs (pnpm lifecycle)
|
||||
|
||||
```json
|
||||
"prebuild": "pnpm run codegen:graphql && pnpm run codegen:references && pnpm run codegen:examples && pnpm run build:markdown && pnpm run build:gz-archive",
|
||||
"postbuild": "pnpm run build:sitemap && ./../../scripts/upload-static-assets.sh"
|
||||
```
|
||||
|
||||
1. **`prebuild`** — GraphQL codegen, reference codegen, copy examples,
|
||||
generate guides + reference markdown (`build:markdown`), then tarball
|
||||
(`build:gz-archive`).
|
||||
2. **`build`** — `next build`.
|
||||
3. **`postbuild`** — sitemap, then `upload-static-assets.sh` (R2 CDN
|
||||
upload on production-style deploys).
|
||||
|
||||
Same monorepo pattern as Studio / www (pnpm workspaces + Turbo `^build`),
|
||||
with **extra codegen** wired as Turbo tasks and npm `pre`/`post` hooks around
|
||||
`next build`.
|
||||
|
||||
## Codegen scripts
|
||||
|
||||
- **`codegen:graphql`** — generates GraphQL types from schema.
|
||||
- **`codegen:examples`** — copies `examples/` from monorepo root into
|
||||
`apps/docs/examples` for `$CodeSample` directive resolution.
|
||||
- **`codegen:references:legacy`** — `features/docs/Reference.generated.script.ts`
|
||||
(includes Management API: merge OpenAPI v1+v2 → `api.latest.*` JSON).
|
||||
Spec download/bundle lives in `apps/docs/spec/Makefile` (Redocly);
|
||||
see [`management-api-reference.md`](./management-api-reference.md).
|
||||
- **`codegen:references:new`** — `scripts/build-reference-content.ts` (from
|
||||
TSDoc JSON under `spec/reference/`). Output lands in
|
||||
`features/docs/generated/**`.
|
||||
- **`build:guides-markdown`** — runs `internals/generate-guides-markdown.ts`
|
||||
over `content/guides/**/*.mdx`. Produces `public/markdown/guides/**.md`.
|
||||
- **`build:reference-markdown`** — runs `internals/generate-reference-markdown.ts`.
|
||||
Produces `public/markdown/reference/**.md`.
|
||||
- **`build:markdown`** — shorthand for guides + reference markdown.
|
||||
- **`build:gz-archive`** — runs `internals/generate-gz-archive.ts`.
|
||||
Produces `public/docs.tar.gz` (tarball of all `public/markdown/`).
|
||||
|
||||
For how agents consume these outputs, see
|
||||
[`llm-agent-surface.md`](./llm-agent-surface.md).
|
||||
|
||||
## Deploy vs CI
|
||||
|
||||
- **Production build** for the site is **Vercel**; `apps/docs/vercel.json`
|
||||
sets `buildCommand` to `pnpm build` (the docs app's script chain above).
|
||||
- **GitHub Actions** mostly run **tests** (`test:docs` → Turbo), **lint**,
|
||||
**sync** jobs, and **smoke** tests — not a separate full production build
|
||||
graph in the way Turbo does locally. See [`ci-and-lint.md`](./ci-and-lint.md).
|
||||
|
||||
## Local development
|
||||
|
||||
From `apps/docs`:
|
||||
|
||||
```bash
|
||||
pnpm dev # http://localhost:3001/docs
|
||||
```
|
||||
|
||||
- **`predev`** runs GraphQL and reference codegen plus example copy.
|
||||
- A concurrent watcher syncs troubleshooting content
|
||||
(`dev:watch:troubleshooting`).
|
||||
- Community contributors: set `NEXT_PUBLIC_IS_PLATFORM=false` in `.env`.
|
||||
- Supabase employees: `pnpm run dev:secrets:pull` for internal env vars
|
||||
(AWS profile + `scripts/getSecrets.js`).
|
||||
- In dev mode, the app **only builds routes upon request** rather than
|
||||
pre-rendering — preview and production environments statically generate
|
||||
routes during build for speed.
|
||||
|
||||
## Why this shape matters for changes
|
||||
|
||||
- Adding a new build step? See [`adding-features.md`](./adding-features.md)
|
||||
"Reuse pipelines, don't fork them" and check if `prebuild` or `postbuild`
|
||||
already has a hook that fits.
|
||||
- New env var? Add it to `apps/docs/turbo.jsonc`'s `env` so Turbo doesn't
|
||||
cache stale.
|
||||
- Touching the markdown export? Read [`app-map.md`](./app-map.md) "The two
|
||||
pipelines" first — runtime and export share data, not code paths.
|
||||
|
||||
## Related
|
||||
|
||||
- [`app-map.md`](./app-map.md) — directory layout and runtime / export split.
|
||||
- [`ci-and-lint.md`](./ci-and-lint.md) — GitHub Actions workflow surface.
|
||||
- [`federated-docs.md`](./federated-docs.md) — external content fetched
|
||||
during build.
|
||||
@@ -0,0 +1,131 @@
|
||||
# Docs CI and lint surface
|
||||
|
||||
GitHub Actions running on every PR touching `supabase/supabase`, plus
|
||||
the deploy path. Confirm against the current `.github/workflows/` if
|
||||
behavior surprises you.
|
||||
|
||||
Before adding a new lint job or CI check, **scan this list first** — see
|
||||
[`adding-features.md`](./adding-features.md) "Reuse pipelines, don't fork them."
|
||||
|
||||
## PR flow
|
||||
|
||||
```
|
||||
PR opened / updated
|
||||
│
|
||||
├── docs_lint (MDX/content linting; required)
|
||||
├── docs_lint_comment_external (posts results as PR comments for external PRs)
|
||||
├── Docs Tests (pnpm test:docs on .ts* file changes)
|
||||
├── TypeScript & Lint (tsc + eslint)
|
||||
├── Prettier (format check)
|
||||
├── reviewdog (inline annotations)
|
||||
├── Validate pull request (PR metadata)
|
||||
└── Authorize Vercel Deploys → Vercel builds preview deploy → Preview on CDN
|
||||
|
||||
Merge to master
|
||||
└── Vercel → next build (with prebuild markdown generation) → deploy
|
||||
```
|
||||
|
||||
## On every pull request
|
||||
|
||||
Workflows run in parallel against any PR touching the repo:
|
||||
|
||||
### 1. `docs_lint`
|
||||
|
||||
Primary docs-specific CI check. MDX/content linting for the docs. **Required
|
||||
check before merging.** Backed by `supa-mdx-lint`.
|
||||
|
||||
### 2. Docs Tests (`docs-tests.yml`)
|
||||
|
||||
Triggered on PRs to master when files matching `apps/docs/**/*.ts*` or
|
||||
`apps/docs/spec/**/*.json` change. Runs on a Blacksmith 4-vCPU Ubuntu runner
|
||||
with concurrency controls to cancel stale builds.
|
||||
|
||||
- Sparse checkout of `apps/docs`, `examples`, `packages`, `supabase`, and
|
||||
`patches`.
|
||||
- Install pnpm (pinned hash).
|
||||
- Set up Node.js from `.nvmrc`.
|
||||
- `pnpm install --frozen-lockfile`.
|
||||
- Run `pnpm run test:docs` (with dummy GitHub OAuth env vars to prevent local
|
||||
Supabase startup errors).
|
||||
|
||||
### 3. TypeScript & Lint (`typecheck.yml`)
|
||||
|
||||
TypeScript type checking and ESLint across the monorepo.
|
||||
|
||||
### 4. Prettier (`prettier.yml`)
|
||||
|
||||
Format checking across the whole repo including `apps/docs`.
|
||||
|
||||
### 5. `docs_lint_comment_external`
|
||||
|
||||
Companion to `docs_lint` that posts lint results as PR comments for external
|
||||
contributors.
|
||||
|
||||
### 6. Authorize Vercel Deploys
|
||||
|
||||
Gates Vercel preview deployment on a GitHub-side check first. Prevents
|
||||
arbitrary forks from triggering Vercel builds.
|
||||
|
||||
### 7. reviewdog
|
||||
|
||||
Inline code review annotations via reviewdog.
|
||||
|
||||
### 8. Validate pull request
|
||||
|
||||
PR metadata validation (title format, labels, etc.).
|
||||
|
||||
## Deployment (on merge to master)
|
||||
|
||||
Production deployment is handled by **Vercel**. Supabase employees branch the
|
||||
repo directly rather than fork it, so CI checks auto-run and Vercel deploys
|
||||
can be authorized without the external PR security gate.
|
||||
|
||||
Key deployment detail: the project generates markdown files for each page
|
||||
under `/docs/guides/..` as a **prebuild task**. This lets Vercel bundle these
|
||||
files with middleware and functions at build time.
|
||||
|
||||
The **Authorize Vercel Deploys** workflow is the glue between GitHub Actions
|
||||
and Vercel: it runs first to approve the deploy, then Vercel picks it up and
|
||||
builds/deploys the Next.js site to their CDN.
|
||||
|
||||
## Notable design choices
|
||||
|
||||
- **Sparse checkout** keeps CI fast by only pulling the relevant workspace
|
||||
packages.
|
||||
- **Blacksmith runners** are used instead of standard GitHub-hosted runners
|
||||
for speed.
|
||||
- All workflow steps use **pinned action hashes** rather than floating tags
|
||||
for supply chain security.
|
||||
|
||||
## Where to add a new check
|
||||
|
||||
Before adding a new GitHub Actions workflow:
|
||||
|
||||
1. **Can `docs_lint` absorb it?** — most MDX/content checks belong inside
|
||||
`supa-mdx-lint` configuration, not as a new workflow.
|
||||
2. **Can `Docs Tests` absorb it?** — TypeScript / vitest checks for new
|
||||
functionality fit here.
|
||||
3. **Is it cross-cutting?** — typecheck, prettier, and reviewdog already
|
||||
cover the cross-cutting cases.
|
||||
4. **Last resort** — a new workflow file. Use a Blacksmith runner, sparse
|
||||
checkout, pinned action hashes, and a concurrency group. Add a clear
|
||||
trigger filter so it doesn't run on unrelated PRs.
|
||||
|
||||
## Vale and prose linting (future)
|
||||
|
||||
Chris Ward's wishlist (source: hiring conversations, not yet in the repo):
|
||||
|
||||
- Vale linting MCP server.
|
||||
- Vale extension for VS Code.
|
||||
- More async automation that doesn't block PR merges.
|
||||
|
||||
If adding prose linting, prefer async (commenting) checks over blocking ones
|
||||
to keep merge cadence high.
|
||||
|
||||
## Related
|
||||
|
||||
- [`app-map.md`](./app-map.md) — what `pnpm test:docs` actually runs.
|
||||
- [`build-pipeline.md`](./build-pipeline.md) — `prebuild` step that ships
|
||||
markdown to Vercel.
|
||||
- [`adding-features.md`](./adding-features.md) — reuse existing pipelines
|
||||
before adding new ones.
|
||||
@@ -0,0 +1,63 @@
|
||||
# `apps/docs` direction and vision
|
||||
|
||||
Where the docs app is heading and what new work should align with. For
|
||||
the _current_ state of broken or fragile systems, see
|
||||
[`known-issues.md`](./known-issues.md). For feature-design best
|
||||
practices, see [`adding-features.md`](./adding-features.md).
|
||||
|
||||
## Refactoring vision
|
||||
|
||||
- **Docs-only project.** The long-term goal is for the documentation
|
||||
project to handle _only_ documentation. Other functionalities (specific
|
||||
APIs, etc.) should migrate to sub-projects.
|
||||
- **Ongoing surface reduction.** A substantial portion of legacy
|
||||
critical code has already been refactored, and remaining work
|
||||
continues to reduce surface area rather than add to it.
|
||||
- **One-to-one markdown fidelity.** Improvements to
|
||||
`generate-guides-markdown` aim for exact correspondence between the
|
||||
rendered guide and the LLM-oriented markdown export. New components
|
||||
that render in MDX should serialize to markdown with the same
|
||||
semantics.
|
||||
|
||||
## Working norms
|
||||
|
||||
- **Work inside `apps/docs/`, not the repo root.** Simpler terminal
|
||||
commands, clearer debugging scope. Most docs commands assume you've
|
||||
`cd`'d into the app.
|
||||
- **AI use is encouraged** for explaining complex or legacy sections of
|
||||
the codebase. Considered effective for mechanical, non-creative tasks.
|
||||
- **Historical context.** For decisions older than the current
|
||||
refactoring wave, check with longer-tenured maintainers — most
|
||||
current code has clearer provenance.
|
||||
|
||||
## What this means for new work
|
||||
|
||||
When proposing changes that touch `apps/docs`:
|
||||
|
||||
1. **Reuse existing seams before adding new ones.** Markdown export, MDX
|
||||
pipeline, lint, codegen, and federated fetch are all places where
|
||||
new surface area gets challenged. See
|
||||
[`adding-features.md`](./adding-features.md) "Inventory before you
|
||||
write."
|
||||
2. **Keep markdown fidelity in mind.** Anything that changes how a
|
||||
guide renders should also change how it serializes to markdown — or
|
||||
have a clear reason it doesn't.
|
||||
3. **Don't build against the broken parts.** See
|
||||
[`known-issues.md`](./known-issues.md). Search, Sentry
|
||||
instrumentation, and federated link handling are all in flux. New
|
||||
features should not depend on their current shape.
|
||||
4. **Don't extend tech debt.** Component scatter, parallel pipelines,
|
||||
and bespoke render paths are existing problems — don't add to them.
|
||||
5. **Refactor only what the feature requires.** Bundling unrelated
|
||||
cleanup into a feature PR muddies review and gets cut anyway. Open a
|
||||
separate refactor PR if the cleanup matters.
|
||||
|
||||
## Related
|
||||
|
||||
- [`adding-features.md`](./adding-features.md) — feature-design best
|
||||
practices.
|
||||
- [`known-issues.md`](./known-issues.md) — what's currently broken or
|
||||
fragile.
|
||||
- [`app-map.md`](./app-map.md) — where the existing seams are now.
|
||||
- [`federated-docs.md`](./federated-docs.md) — mechanics of one of the
|
||||
known liabilities.
|
||||
@@ -0,0 +1,227 @@
|
||||
# Federated docs
|
||||
|
||||
`apps/docs` can pull **markdown (and other files) from external GitHub repos**
|
||||
at **build or request time**, then render them inside the normal docs shell.
|
||||
Content lives in ecosystem repos (client libs, extensions, tooling) without
|
||||
duplicating into `apps/docs/content`.
|
||||
|
||||
Documented upstream in root **`DEVELOPERS.md`** → "Federated docs."
|
||||
|
||||
> **The maintainers treat this as a known liability.** See
|
||||
> [`docs-app-direction.md`](./docs-app-direction.md) for the full context
|
||||
> (lack of editorial oversight, brittle builds, quality drift). Treat
|
||||
> federated content as a liability when reviewing or debugging.
|
||||
|
||||
## Why federate
|
||||
|
||||
- **No duplication** — e.g. `supabase/vecs` docs stay in the vecs repo.
|
||||
- **Automatic sync** — fetched during the docs build (or on cached
|
||||
revalidation), not hand-copied.
|
||||
- **Native feel** — same `GuideTemplate`, nav, typography, and search surface
|
||||
as first-party guides.
|
||||
- **Flexible placement** — can embed external docs at nearly any path under
|
||||
`/guides/`.
|
||||
|
||||
Trade-off: **integration is manual and brittle**. Each federated section
|
||||
needs its own route file, `pageMap`, link transform, and often custom remark
|
||||
plugins.
|
||||
|
||||
## Build-time flow
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph upstream ["External repos"]
|
||||
PG["supabase/pg_graphql"]
|
||||
VECS["supabase/vecs"]
|
||||
WRAP["supabase/wrappers"]
|
||||
TF["supabase/terraform-provider-supabase"]
|
||||
CI["supabase/setup-cli"]
|
||||
SPL["supabase/splinter"]
|
||||
SKILLS["supabase/agent-skills"]
|
||||
end
|
||||
|
||||
subgraph fetch ["Fetch layer — lib/octokit.ts"]
|
||||
APP["GitHub App auth<br/>DOCS_GITHUB_APP_*"]
|
||||
API["getGitHubFileContents()"]
|
||||
CACHE["fetchRevalidatePerDay<br/>(Next.js cache, retry up to 5x)"]
|
||||
APP --> API --> CACHE
|
||||
end
|
||||
|
||||
subgraph route ["Per-section route — app/guides/.../page.tsx"]
|
||||
MAP["pageMap<br/>(slug → remoteFile + meta)"]
|
||||
GET["getContent()"]
|
||||
MAP --> GET
|
||||
end
|
||||
|
||||
subgraph transform ["MDX pipeline"]
|
||||
RM["remark plugins<br/>Admonition, Tabs, removeTitle"]
|
||||
RH["rehype plugins<br/>linkTransform + rehypeSlug"]
|
||||
RM --> RH
|
||||
end
|
||||
|
||||
subgraph render ["Render"]
|
||||
GT["GuideTemplate / GuideMdxContent"]
|
||||
OUT["/docs/guides/..."]
|
||||
GT --> OUT
|
||||
end
|
||||
|
||||
upstream --> API
|
||||
GET --> RM
|
||||
RH --> GT
|
||||
```
|
||||
|
||||
### Step-by-step
|
||||
|
||||
1. **Route file** defines `org`, `repo`, `branch` (or tag), `docsDir`, and a
|
||||
**`pageMap`** — each entry maps a local slug to a remote markdown file
|
||||
plus page metadata.
|
||||
2. **`getGitHubFileContents()`** fetches file content via a **GitHub App**
|
||||
(`DOCS_GITHUB_APP_ID`, `DOCS_GITHUB_APP_INSTALLATION_ID`,
|
||||
`DOCS_GITHUB_APP_PRIVATE_KEY`). Uses **once-per-day revalidation** by
|
||||
default (`fetchRevalidatePerDay`).
|
||||
3. Raw markdown is passed through **remark/rehype plugins** to bridge dialect
|
||||
gaps.
|
||||
4. **`linkTransform` + custom `urlTransform`** rewrite relative links from
|
||||
the source repo into `/docs/guides/...` paths (or fall back to the upstream
|
||||
docs site / GitHub).
|
||||
5. Output is rendered with **`GuideTemplate`** so federated pages look like
|
||||
native guides. **Edit on GitHub** links point at the source repo file.
|
||||
|
||||
> Note: `DEVELOPERS.md` still mentions `getStaticProps()` — the current App
|
||||
> Router implementation uses async server components + `generateStaticParams`
|
||||
> instead, but the idea is the same: fetch remote markdown at build time.
|
||||
|
||||
## Federated sources (inventory)
|
||||
|
||||
| Local path | Source repo | Ref / branch | Pattern |
|
||||
| ---------------------------------------- | -------------------------------------- | ------------------------------ | ------------------------------------------------- |
|
||||
| `/guides/graphql/*` | `supabase/pg_graphql` | `master` | Fully federated; `pageMap` per page |
|
||||
| `/guides/ai/python/*` | `supabase/vecs` | `main` | Fully federated |
|
||||
| `/guides/deployment/ci/*` | `supabase/setup-cli` | `gh-pages` | Fully federated |
|
||||
| `/guides/deployment/terraform/*` | `supabase/terraform-provider-supabase` | branch in `terraformConstants` | Federated prose pages |
|
||||
| `/guides/deployment/terraform/reference` | same | same | Federated **JSON schema** (not MDX) |
|
||||
| `/guides/database/extensions/wrappers/*` | `supabase/wrappers` | **release tag** `docs_v*.*.*` | **Hybrid** — local MDX + federated catalog |
|
||||
| `/guides/database/database-advisors` | `supabase/splinter` | `main` | **Dynamic listing** — all `docs/*.md` files |
|
||||
| AI Skills index | `supabase/agent-skills` | `main` | Lists `skills/*/SKILL.md` at runtime |
|
||||
| `$CodeSample` directive | various | commit SHA only | Snippets via `getGitHubFileContentsImmutableOnly` |
|
||||
|
||||
### Related patterns (not quite "federated docs")
|
||||
|
||||
| Pattern | Source | Mechanism |
|
||||
| -------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **AI prompts** | `examples/prompts/*.md` | Copied into `apps/docs/examples` at build (`codegen:examples`); nav injected in getting-started layout |
|
||||
| **Integrations nav** | Supabase `partners` table | `integrations/layout.tsx` fetches approved partners (external URLs) |
|
||||
| **Reference docs** | `apps/docs/spec/` | Generated locally, not fetched from GitHub — see [`build-pipeline.md`](./build-pipeline.md) |
|
||||
|
||||
## How to spot a federated page in the repo
|
||||
|
||||
- Look for a **dynamic route** (`[[...slug]]/page.tsx`, `[slug]/page.tsx`)
|
||||
instead of content-only routing.
|
||||
- Search for **`// We fetch these docs at build time from an external repo`**
|
||||
or **`getGitHubFileContents`**.
|
||||
- Check for a local **`pageMap`** array mapping slugs to `remoteFile` names.
|
||||
- GraphQL is listed in `PUBLISHED_SECTIONS` comments as _"technically
|
||||
published, but completely federated"_ — no MDX under `content/guides/graphql/`.
|
||||
|
||||
Canonical starter example:
|
||||
`apps/docs/app/guides/ai/python/[slug]/page.tsx` (vecs).
|
||||
|
||||
## Link and markdown transforms
|
||||
|
||||
External repos often use **MkDocs Material** or similar dialects. Supabase
|
||||
docs do not understand those natively.
|
||||
|
||||
### Remark plugins (`lib/mdx/plugins/`)
|
||||
|
||||
| Plugin | Purpose |
|
||||
| ------------------- | ----------------------------------------------- |
|
||||
| `remarkAdmonition` | `!!! note` / `!!! warning` → `<Admonition>` |
|
||||
| `remarkTabs` | pymdownx tab syntax → Supabase tabs |
|
||||
| `remarkRemoveTitle` | Strip duplicate H1 when title comes from `meta` |
|
||||
|
||||
New upstream syntax may need a **new remark plugin** — called out explicitly
|
||||
in `DEVELOPERS.md`.
|
||||
|
||||
### Link transform (`rehypeLinkTransform.ts`)
|
||||
|
||||
Each federated route defines its own **`urlTransform`** function:
|
||||
|
||||
- **Relative `.md` links** → mapped via `pageMap` to `/docs/guides/...` (or
|
||||
section-relative slug).
|
||||
- **Unmapped relative links** → fall back to upstream site (e.g.
|
||||
`https://supabase.github.io/vecs/...`) or raw GitHub blob URL (terraform).
|
||||
- **Absolute URLs** → passed through unchanged.
|
||||
|
||||
Wrappers additionally rewrites **`../assets/`** image paths to
|
||||
`raw.githubusercontent.com` URLs tied to the docs release tag.
|
||||
|
||||
## Known failure modes
|
||||
|
||||
Federated docs are a frequent source of **content quality issues** and
|
||||
**broken links**.
|
||||
|
||||
### Broken or wrong links
|
||||
|
||||
- **`pageMap` is manual** — upstream rename/remove → broken link until
|
||||
someone updates the route file in `supabase/supabase`.
|
||||
- **`urlTransform` is per-section** — logic differs between graphql, vecs,
|
||||
terraform, wrappers, etc.
|
||||
- **Unmapped pages fall back externally** — users leave the docs site or land
|
||||
on a GitHub pages URL that may not match the embedded path structure.
|
||||
- **Absolute links in upstream** pass through untouched — may point at old
|
||||
domains or anchors that moved.
|
||||
- **Cross-links between federated and native guides** are not automatic;
|
||||
upstream authors don't know Supabase URL shapes.
|
||||
|
||||
### Content quality
|
||||
|
||||
- **No editorial gate in `apps/docs/content`** — upstream tone, structure,
|
||||
and freshness vary.
|
||||
- **Dialect mismatches** — unsupported mkdocs extensions render as raw text
|
||||
or fail MDX compile until a plugin is added.
|
||||
- **Duplicate titles** — mitigated by `removeTitle` / `removeRedundantH1`,
|
||||
but layout can still look off.
|
||||
- **Stale content** — daily GitHub cache means upstream fixes may not appear
|
||||
until revalidation; wrappers pin to **release tags** which can lag further.
|
||||
|
||||
### Operational / dev failures
|
||||
|
||||
- **GitHub App credentials required** — without `DOCS_GITHUB_APP_*`, fetches
|
||||
fail. `$CodeSample` with external repos shows a **local dev warning** and
|
||||
does not render real content.
|
||||
- **GitHub API timeouts** — `database-advisors` catches fetch errors and
|
||||
shows a degraded view with a link to GitHub; build may still succeed with
|
||||
partial content.
|
||||
- **Wrappers tag resolution** — `getLatestDocsTag()` queries `docs_v*.*.*`
|
||||
tags; if tagging breaks, federated wrapper pages throw at build time.
|
||||
- **Dev mode gaps** — some federated routes return **empty
|
||||
`generateStaticParams` in dev** (`IS_DEV`), so pages may 404 locally unless
|
||||
you hit them via production build or adjust params.
|
||||
|
||||
### Navigation drift
|
||||
|
||||
- Sidebar entries for federated sections are often **hard-coded** in
|
||||
`NavigationMenu.constants.ts` plus optional **`additionalNavItems`**
|
||||
injection (prompts, integrations).
|
||||
- New upstream pages do not appear in nav until a maintainer adds them to
|
||||
`pageMap` **and** navigation config.
|
||||
|
||||
## When to federate vs copy into `content/`
|
||||
|
||||
Federate when:
|
||||
|
||||
- The canonical docs live in another repo and change frequently.
|
||||
- Maintainers of that repo own the content lifecycle.
|
||||
|
||||
Prefer `content/guides/` when:
|
||||
|
||||
- Editorial control, consistent voice, and link stability matter.
|
||||
- Content is tightly coupled to Supabase product UI and cross-links.
|
||||
|
||||
## Related
|
||||
|
||||
- [`app-map.md`](./app-map.md) — runtime + markdown export pipelines.
|
||||
- [`build-pipeline.md`](./build-pipeline.md) — where federated fetches sit
|
||||
in the overall build.
|
||||
- [`docs-app-direction.md`](./docs-app-direction.md) — context on the
|
||||
federated-docs liability and long-term direction.
|
||||
@@ -0,0 +1,139 @@
|
||||
# `apps/docs` gotchas
|
||||
|
||||
Specific traps to watch for. One-liner per item.
|
||||
|
||||
## Markdown pipeline
|
||||
|
||||
- **JSX with no schema handler is unwrapped, not dropped.** Children pass
|
||||
through as plain markdown. If a component should disappear entirely from
|
||||
`.md` output, its handler must return `''`.
|
||||
- **Handlers run bottom-up.** Children are already-serialized markdown
|
||||
strings by the time the parent handler sees them. Don't try to inspect
|
||||
child JSX from a parent handler — use `node.children` only for structure
|
||||
decisions.
|
||||
- **`mdxFlowExpression` / `mdxTextExpression` / `mdxjsEsm` are skipped.**
|
||||
Anything wrapped in `{...}` won't appear in markdown output.
|
||||
- **`AiPrompt` prompts must be a `prompt={...}` prop, not children.** The
|
||||
schema handler decodes the raw JS string literal from `propsFrom()`
|
||||
(Prettier may emit single-quoted multiline forms). See
|
||||
`internals/markdown-schema/AiPrompt.ts`.
|
||||
- **`<$Partial>` recursion is silent.** A missing or unreadable partial is
|
||||
dropped without error. Check `partials/` paths when content seems missing
|
||||
from generated `.md`.
|
||||
- **`$Partial` `variables` are runtime-only unless wired in markdown export.**
|
||||
`partialsRemark` substitutes `{{ .key }}` placeholders; `inlinePartials`
|
||||
in `generate-guides-markdown.ts` must do the same or nested partials like
|
||||
`path="{{ .prompt }}"` fail silently (file not found).
|
||||
- **`GlassPanel` / `IconPanel` markdown handlers must include children.**
|
||||
A handler that returns only `props.title` drops nested content. See
|
||||
`internals/markdown-schema/Panel.ts`.
|
||||
|
||||
## Markdown handler authoring
|
||||
|
||||
- Handler files in `internals/markdown-schema/` must be named after the
|
||||
component (`ContentListings.ts`, not `Listings.ts`). The registry key in
|
||||
`generate-guides-markdown.ts` is the JSX element name.
|
||||
- Use the existing `withDocsBasePath` / `addBaseUrlPrefix` from
|
||||
`internal-links.ts` for URL prefixing — don't roll your own.
|
||||
- If a handler needs data, the **JSX prop carries an `id`** and the handler
|
||||
looks the data up from the same registry the runtime component uses. Don't
|
||||
serialize data into JSX props.
|
||||
- Push a blank line right after each exported block (heading, description,
|
||||
list). Keeps handler logic linear and avoids redundant trailing-empty-line
|
||||
branches.
|
||||
|
||||
## React / MDX components
|
||||
|
||||
- `not-prose` is the canonical opt-out from the surrounding `.prose`
|
||||
typography. Wrap structural layout in `not-prose`; keep headings outside so
|
||||
they inherit prose styles.
|
||||
- `<Heading>` from `MdxBase.shared.tsx` is the canonical heading. Don't roll
|
||||
your own `<h2>` / `<h3>` markup in MDX components — typography drifts.
|
||||
- `<Link>` from `next/link` works with `target="_blank"` for external
|
||||
destinations. Don't construct `<a>` directly.
|
||||
- A `useSendTelemetryEvent()` call inside a render path returns a function;
|
||||
don't invoke it directly inside the JSX, build a callback first.
|
||||
|
||||
## Data modules
|
||||
|
||||
- Shared zod schemas for MDX components should use HTML heading levels
|
||||
(`'h2'|'h3'|'h4'`), not markdown marker strings (`'##'`). Markdown markers
|
||||
belong only in `internals/markdown-schema/` handlers (via a `Record`/`Map`
|
||||
lookup).
|
||||
- `getXById(id)` lookups belong in `*.utils.ts`, not in the data file or the
|
||||
schema file. Schema files hold schemas; data files hold data; utils hold
|
||||
functions.
|
||||
- Each `.data.ts` exports named groups; the topic `index.ts` aggregates them
|
||||
into a `Record<id, group>` map. The aggregation file is the single source
|
||||
of truth for "all valid IDs."
|
||||
|
||||
## URL handling
|
||||
|
||||
- External-link detection is **not** just `/^https?:\/\//`. Protocol-relative
|
||||
(`//host`), `mailto:`, `tel:`, custom schemes — all external. Prefer
|
||||
`new URL(href, base)` or a broader regex.
|
||||
- `withDocsBasePath('/guides/foo')` → `/docs/guides/foo`. Already-prefixed
|
||||
URLs are passed through. Use it consistently in markdown output to avoid
|
||||
broken links.
|
||||
|
||||
## Troubleshooting subtree
|
||||
|
||||
- `Troubleshooting.utils.common.mjs` is `.mjs` because the troubleshooting
|
||||
sync script can't resolve `.ts` imports cleanly. Don't convert it.
|
||||
- Rebasing can resurrect a **stale** version of this file when you reset
|
||||
unrelated changes — verify against current `master` after
|
||||
`git checkout master -- <path>`.
|
||||
- The `topics` enum in `TroubleshootingSchema` is hand-maintained. Adding a
|
||||
new product means updating that enum.
|
||||
|
||||
## Build / CI
|
||||
|
||||
- `pnpm build --filter=docs` runs markdown generation. A failure in
|
||||
`generate-guides-markdown.ts` blocks the build — read its console output
|
||||
rather than the cryptic CI error.
|
||||
- `pnpm format` from the repo root catches most prettier drift. Run it
|
||||
before opening a PR; CI is unforgiving.
|
||||
- Auto-import sorting can silently shuffle imports across files you didn't
|
||||
touch. Reset those files (`git checkout master -- <path>`) before pushing.
|
||||
|
||||
## Federated docs
|
||||
|
||||
See [`federated-docs.md`](./federated-docs.md) for the full surface — the
|
||||
short version:
|
||||
|
||||
- **No GitHub App credentials in dev** = `$CodeSample` shows a warning, not
|
||||
real content. Don't assume the page is broken.
|
||||
- **`pageMap` is manual.** Upstream renames break links until a maintainer
|
||||
updates the route file.
|
||||
- **Wrappers pin to release tags** (`docs_v*.*.*`). If tagging breaks
|
||||
upstream, build fails.
|
||||
- **Search and federated content interact poorly** — search infrastructure
|
||||
is currently decoupled from the markdown generation. See
|
||||
[`docs-app-direction.md`](./docs-app-direction.md).
|
||||
|
||||
## Reference pages
|
||||
|
||||
- SDK and CLI reference pages **don't go through the standard MDX path** —
|
||||
they're too long for the AST parser in preview environments. Generated
|
||||
from `spec/` instead, output to `features/docs/generated/**`.
|
||||
- Reference page length is a known UX/LLM problem. Long-term plan: split
|
||||
into smaller modular pages. Management API is already one endpoint per
|
||||
page (DOCS-1268); see [`management-api-reference.md`](./management-api-reference.md).
|
||||
- Management API Redocly bundle **omits `--dereferenced`** because of a
|
||||
circular `$ref`. Don't "fix" that by adding `--dereferenced` without
|
||||
checking codegen's cycle-safe `resolveRefs`.
|
||||
- Don't propose Scalar/Redoc/Elements as the Management API page UI
|
||||
without covering markdown export, search, and `x-*` extension fields.
|
||||
|
||||
## PR hygiene
|
||||
|
||||
- No incidental import reorders or whitespace edits in a feature PR. Reset
|
||||
files that are conceptually unchanged.
|
||||
- When resetting unrelated files (`git checkout master -- <path>`), verify the
|
||||
result matches current `master` — rebases can resurrect stale file versions.
|
||||
- File names must match the primary export. Rename rather than aliasing on
|
||||
import.
|
||||
- Single-use helpers stay in the consuming file. Don't add new files in
|
||||
unrelated folders for one-shot utilities.
|
||||
- Two components with the same JSX shape and different classes → collapse
|
||||
with a discriminator prop. Don't ship near-duplicates.
|
||||
@@ -0,0 +1,140 @@
|
||||
# `apps/docs` known issues
|
||||
|
||||
What's currently broken, fragile, or intentionally being avoided. Read
|
||||
this before depending on a piece of infrastructure for new work — if it's
|
||||
listed here, expect it to change or fail in surprising ways.
|
||||
|
||||
Living document — update when a new fragility shows up in a PR or
|
||||
incident.
|
||||
|
||||
## Federated documentation pipeline
|
||||
|
||||
**Severity:** load-bearing fragility. Affects daily builds.
|
||||
|
||||
The docs site fetches markdown from external repos at build/request time
|
||||
(pg_graphql, vecs, wrappers, terraform-provider, setup-cli, splinter,
|
||||
agent-skills). Treat as a liability:
|
||||
|
||||
- **Lack of oversight.** Quality control, linting, and formatting can't
|
||||
be enforced because the source code isn't owned.
|
||||
- **Quality drift.** Inconsistent formatting, missing semicolons,
|
||||
structural differences between federated and in-house content.
|
||||
- **Build brittleness.** Upstream fetches fail intermittently — retry
|
||||
logic (up to 5x) is in place to mitigate. Builds can still degrade or
|
||||
partially succeed.
|
||||
- **Manual `pageMap`.** Upstream rename/remove → broken links until a
|
||||
maintainer updates the route file in `supabase/supabase`.
|
||||
- **Wrappers pins to release tags** (`docs_v*.*.*`). If tagging breaks
|
||||
upstream, federated wrapper pages throw at build time.
|
||||
- **Dev mode gaps.** Some federated routes return empty
|
||||
`generateStaticParams` in dev — pages may 404 locally unless hit via
|
||||
production build.
|
||||
|
||||
See [`federated-docs.md`](./federated-docs.md) for the full mechanics and
|
||||
failure modes. Implication: **don't add new federated sources** without
|
||||
strong justification; **don't extend federated patterns** to new content
|
||||
types.
|
||||
|
||||
## Troubleshooting guides currently live in an external repo
|
||||
|
||||
**Severity:** ongoing sync issues.
|
||||
|
||||
This causes synchronization problems between the docs site and the source
|
||||
of truth. Proposed direction: bring them in-house and require support
|
||||
teams to contribute directly to `supabase/supabase` to ensure accuracy.
|
||||
|
||||
## Reference pages can't go through standard MDX
|
||||
|
||||
**Severity:** architectural constraint.
|
||||
|
||||
SDK & CLI reference pages (e.g. JavaScript SDK, CLI) use a different
|
||||
rendering path than guides. Attempts to migrate them to MDX **failed
|
||||
because their length exceeded memory limits for the AST parser in
|
||||
preview environments.** They are generated from `spec/` instead, output
|
||||
to `features/docs/generated/**`.
|
||||
|
||||
Implication: don't propose "unify everything under MDX" for reference
|
||||
pages without addressing the memory ceiling first.
|
||||
|
||||
## Reference page length
|
||||
|
||||
**Severity:** UX and LLM usability issue.
|
||||
|
||||
Current reference pages are far too long, making them difficult for
|
||||
human users to navigate and inefficient for LLMs to process. Long-term
|
||||
goal: break them into specialized, modular pages for better readability
|
||||
and performance.
|
||||
|
||||
Implication: new reference content should default to smaller, modular
|
||||
pages.
|
||||
|
||||
## Search infrastructure is decoupled and considered broken
|
||||
|
||||
**Severity:** functional, but not trustworthy for new features.
|
||||
|
||||
Search relies on separate scripts and embeddings rather than the
|
||||
consolidated markdown files (`build:guides-markdown` output). It is
|
||||
decoupled from the main markdown-generation pipeline.
|
||||
|
||||
Implication: **don't build new features against the current search
|
||||
infrastructure** assuming it's stable. Expect it to be reworked as part
|
||||
of the refactoring direction.
|
||||
|
||||
## Error tracking and Sentry signal quality
|
||||
|
||||
**Severity:** noise-to-signal issue.
|
||||
|
||||
Sentry errors for slugs / 404s are often caused by:
|
||||
|
||||
- Bots scanning paths.
|
||||
- Legacy URLs that no longer exist.
|
||||
- Broken inbound links from external sites.
|
||||
|
||||
Error tracking and instrumentation are relatively new and
|
||||
underdeveloped. Implication: **don't trust noisy Sentry signals as proof
|
||||
of a real bug** without corroboration (reproduce locally, check the
|
||||
referrer, etc.).
|
||||
|
||||
## Component dispersion
|
||||
|
||||
**Severity:** tech debt — accumulating cost, not a runtime failure.
|
||||
|
||||
React components for the docs app are inconsistently scattered across
|
||||
multiple folders (`components/`, `features/docs/`, `features/ui/`,
|
||||
`layouts/`, etc.). No canonical place for "this is a docs component."
|
||||
|
||||
Implication:
|
||||
|
||||
- Don't try to refactor the scatter as a side-quest in a feature PR.
|
||||
- Place new components by following the closest existing analogue, not
|
||||
by inventing a new location.
|
||||
- Prioritize understanding the immediate task over mastering the whole
|
||||
codebase.
|
||||
|
||||
## "One-to-one" markdown fidelity is aspirational, not enforced
|
||||
|
||||
**Severity:** ongoing improvement target.
|
||||
|
||||
The stated direction is one-to-one fidelity between rendered guides and
|
||||
the markdown export produced by `generate-guides-markdown`. In practice,
|
||||
gaps exist:
|
||||
|
||||
- Any MDX component without a `markdown-schema` handler is unwrapped to
|
||||
its children, which may not match the rendered output.
|
||||
- `$Partial` recursion is silent — missing partials are dropped.
|
||||
- Some components (interactive, JSX-expression-heavy) inherently can't
|
||||
serialize to markdown faithfully.
|
||||
|
||||
Implication: when adding a component that should appear in markdown
|
||||
output, **always add a handler** in `internals/markdown-schema/` and
|
||||
register it in `generate-guides-markdown.ts`. See
|
||||
[`app-map.md`](./app-map.md) "The two pipelines."
|
||||
|
||||
## Related
|
||||
|
||||
- [`docs-app-direction.md`](./docs-app-direction.md) — where the
|
||||
refactoring is headed; what these issues are being driven toward.
|
||||
- [`federated-docs.md`](./federated-docs.md) — full mechanics of the
|
||||
federation pipeline.
|
||||
- [`gotchas.md`](./gotchas.md) — smaller per-change traps; this file
|
||||
is for load-bearing systemic issues.
|
||||
@@ -0,0 +1,97 @@
|
||||
# LLM / agent content parity and onboarding
|
||||
|
||||
Companion to [`llm-agent-surface.md`](./llm-agent-surface.md) (routing and
|
||||
discovery). This file covers HTML↔markdown fidelity, search caveats, agent
|
||||
onboarding guides, and known stale wiring.
|
||||
|
||||
**Verify against live code** before depending on any path here.
|
||||
|
||||
## Two-pipeline parity for embedded content
|
||||
|
||||
Content that renders on the HTML page is **not** automatically present
|
||||
in the `.md` export. Both pipelines must implement the same semantics.
|
||||
|
||||
Example: framework quickstart **AI prompt blocks** (see
|
||||
supabase/supabase#47543). Each quickstart includes a bare partial:
|
||||
|
||||
```mdx
|
||||
<$Partial path="ai/quickstart_prompt_nextjs.mdx" />
|
||||
```
|
||||
|
||||
The partial is a self-closing `<AiPrompt>` with the prompt as a **prop**
|
||||
(not children — expression children are skipped by the guides markdown
|
||||
pipeline):
|
||||
|
||||
```mdx
|
||||
<AiPrompt
|
||||
prompt={
|
||||
'Help me add Supabase to my Next.js project. Create a Supabase project at\ndatabase.new and run the instruments table SQL. Then:\n1. …'
|
||||
}
|
||||
/>
|
||||
```
|
||||
|
||||
| Pipeline | Path |
|
||||
| ------------ | ------------------------------------------------------------ |
|
||||
| **HTML** | `features/ui/AiPrompt.tsx` → `PromptPanel` (copy + expand) |
|
||||
| **Markdown** | `internals/markdown-schema/AiPrompt.ts` reads `props.prompt` |
|
||||
|
||||
`propsFrom()` stores the raw JS expression source. Prettier formats the
|
||||
prop as a multiline **single-quoted** string; the schema handler must
|
||||
decode that literal (trim + escapes), not only `JSON.parse` double-quoted
|
||||
JSON. Symptom if decoding is wrong: generated `.md` keeps surrounding
|
||||
quotes and literal `\n`.
|
||||
|
||||
`$Partial` variable substitution (`lib/partials.utils.ts`, wired in both
|
||||
`partialsRemark` and `inlinePartials`) remains required for other nested
|
||||
partials — it is no longer the AI-prompt path.
|
||||
|
||||
When adding content aimed at both humans and agents, always verify:
|
||||
|
||||
```bash
|
||||
cd apps/docs && pnpm build:guides-markdown
|
||||
# then inspect public/markdown/guides/<same-path>.md for **AI Prompt**
|
||||
```
|
||||
|
||||
## Programmatic search
|
||||
|
||||
`/docs/api/graphql` exposes `searchDocs`, backed by embeddings generated
|
||||
offline via `scripts/search/generate-embeddings.ts`. Agents can request
|
||||
full `content` in results.
|
||||
|
||||
**Caveat:** search infrastructure is decoupled from the markdown export
|
||||
pipeline and is considered fragile. See
|
||||
[`known-issues.md`](./known-issues.md) "Search infrastructure is
|
||||
decoupled and considered broken" before building features on top of it.
|
||||
|
||||
## Agent onboarding content
|
||||
|
||||
First-party guides under `content/guides/ai-tools/`:
|
||||
|
||||
| Page | Purpose |
|
||||
| ---------------- | --------------------------------- |
|
||||
| `mcp.mdx` | Supabase MCP server setup |
|
||||
| `plugins.mdx` | One-click MCP + skills bundle |
|
||||
| `byo-mcp.mdx` | Build your own MCP server |
|
||||
| `ai-skills.mdx` | Index of installable agent skills |
|
||||
| `ai-prompts.mdx` | Curated IDE prompts |
|
||||
|
||||
The skills index is **federated** from `supabase/agent-skills` at
|
||||
runtime (`AiSkills.utils.ts`). See [`federated-docs.md`](./federated-docs.md).
|
||||
|
||||
## In-flux / stale wiring
|
||||
|
||||
- `apps/docs/.gitignore` lists `public/llms/` as generated by
|
||||
`build:llms`, but **`build:llms` is not in `package.json`** today.
|
||||
Per-source `llms/*.txt` links in `/llms.txt` may point at assets whose
|
||||
generation path is unclear — verify before depending on them.
|
||||
- `llms-full.txt` fetches reference markdown from
|
||||
`${NEXT_PUBLIC_DOCS_URL}/markdown/reference/<slug>.md` at runtime.
|
||||
|
||||
## Related
|
||||
|
||||
- [`llm-agent-surface.md`](./llm-agent-surface.md) — routing, negotiation,
|
||||
entry points, bulk vs per-page retrieval.
|
||||
- [`app-map.md`](./app-map.md) — two-pipeline model, directory layout.
|
||||
- [`federated-docs.md`](./federated-docs.md) — agent-skills federation.
|
||||
- [`known-issues.md`](./known-issues.md) — search fragility, reference
|
||||
page length.
|
||||
@@ -0,0 +1,181 @@
|
||||
# LLM and agent consumption surface
|
||||
|
||||
How `apps/docs` exposes machine-readable content and how that relates to
|
||||
`apps/www`. For markdown export fidelity and agent onboarding pages, see
|
||||
[`llm-agent-parity.md`](./llm-agent-parity.md). For the markdown export
|
||||
pipeline itself, see [`app-map.md`](./app-map.md) "The two pipelines."
|
||||
|
||||
**Verify against live code** — several pieces here span two apps and
|
||||
change independently.
|
||||
|
||||
## Scope boundary
|
||||
|
||||
| App | Role |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`apps/docs`** | Produces markdown exports, serves per-guide `.md`, reference static files, GraphQL search, agent onboarding guides |
|
||||
| **`apps/www`** | Serves discovery indexes (`/llms.txt`, `/llms-full.txt`) and product-page `.md` negotiation |
|
||||
|
||||
`llms.txt` is **not** a route in `apps/docs`. It is assembled at runtime
|
||||
by `apps/www/app/llms.txt/route.ts`, reading guide directory names from
|
||||
`apps/docs/content/guides/` and linking to docs + reference exports.
|
||||
There is no static `llms.txt` file in the repo — the www route handler
|
||||
builds it on each request.
|
||||
|
||||
### Key source files
|
||||
|
||||
| What | Monorepo path | Public URL (prod) |
|
||||
| --------------------- | ------------------------------------------------ | ------------------------------------------------- |
|
||||
| `llms.txt` route | `apps/www/app/llms.txt/route.ts` | `https://supabase.com/llms.txt` |
|
||||
| `llms-full.txt` route | `apps/www/app/llms-full.txt/route.ts` | `https://supabase.com/llms-full.txt` |
|
||||
| Guide middleware | `apps/docs/middleware.ts` | — (lines ~16–38: negotiate, rewrite to guides-md) |
|
||||
| WWW middleware | `apps/www/middleware.ts` | Product-page markdown negotiation |
|
||||
| Negotiation logic | `packages/common/markdown-negotiation.ts` | Shared by both middleware files |
|
||||
| Guides markdown API | `apps/docs/app/api/guides-md/[...slug]/route.ts` | Reads `public/markdown/guides/` at runtime |
|
||||
| Markdown manifest | `apps/docs/public/markdown/manifest.json` | Slugs eligible for `.md` negotiation |
|
||||
|
||||
## Build outputs → serving paths
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph docsApp ["apps/docs prebuild"]
|
||||
GM["build:guides-markdown"]
|
||||
RM["build:reference-markdown"]
|
||||
GZ["build:gz-archive"]
|
||||
GM --> outGuides["public/markdown/guides/"]
|
||||
RM --> outRef["public/markdown/reference/"]
|
||||
GZ --> tarball["public/docs.tar.gz"]
|
||||
end
|
||||
|
||||
subgraph docsServe ["apps/docs runtime"]
|
||||
mw["middleware.ts"]
|
||||
guidesMd["api/guides-md"]
|
||||
crawlers["api/crawlers"]
|
||||
gql["api/graphql searchDocs"]
|
||||
mw --> guidesMd
|
||||
end
|
||||
|
||||
subgraph wwwApp ["apps/www"]
|
||||
llmsTxt["/llms.txt"]
|
||||
llmsFull["/llms-full.txt"]
|
||||
end
|
||||
|
||||
outGuides --> guidesMd
|
||||
outGuides --> llmsFull
|
||||
outRef --> llmsFull
|
||||
outGuides --> llmsTxt
|
||||
gql --> guidesMd
|
||||
```
|
||||
|
||||
## Entry points
|
||||
|
||||
| URL | Owner | Source |
|
||||
| ---------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- |
|
||||
| `/llms.txt` | `apps/www` | `app/llms.txt/route.ts` — index of guide sections + reference links |
|
||||
| `/llms-full.txt` | `apps/www` | `app/llms-full.txt/route.ts` — concatenated guides + reference + product overviews |
|
||||
| `/docs/guides/<path>.md` | `apps/docs` | Middleware → `app/api/guides-md/[...slug]/route.ts` reads `public/markdown/guides/` |
|
||||
| `/docs/markdown/reference/<lib>.md` | `apps/docs` | Static file from `public/markdown/reference/` (build output) |
|
||||
| `/docs/docs.tar.gz` | `apps/docs` | `internals/generate-gz-archive.ts` tarballs all of `public/markdown/` |
|
||||
| `/docs/api/graphql` (`searchDocs`) | `apps/docs` | Vector search over embedded doc sections — see [`llm-agent-parity.md`](./llm-agent-parity.md) |
|
||||
| `/docs/reference/<sdk>/<section>` (bots) | `apps/docs` | `isbot()` → `app/api/crawlers/route.ts` (simplified HTML, not markdown) |
|
||||
|
||||
Homepage alternate link points agents at the full dump:
|
||||
`https://supabase.com/llms-full.txt` (`apps/docs/app/page.tsx`).
|
||||
|
||||
## Audience routing (humans vs agents vs crawlers)
|
||||
|
||||
Every guide exists in two forms from the same MDX source:
|
||||
|
||||
| Form | Produced by | Served to |
|
||||
| ------------ | -------------------------------------------------------------------- | ------------------------------------ |
|
||||
| **HTML** | Live MDX render (`partialsRemark`, React components) | Humans in a browser |
|
||||
| **Markdown** | Prebuild (`generate-guides-markdown.ts` → `public/markdown/guides/`) | Live-fetch agents and bulk downloads |
|
||||
|
||||
`apps/docs/middleware.ts` is the bouncer for guide requests. It calls
|
||||
`negotiateMarkdown()` from `packages/common/markdown-negotiation.ts` and
|
||||
checks `public/markdown/manifest.json` before serving markdown.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
req[Guide request] --> mdSuffix{URL ends in .md?}
|
||||
mdSuffix -->|yes| markdown[Serve markdown]
|
||||
mdSuffix -->|no| agentUA{Live-fetch agent UA?}
|
||||
agentUA -->|yes| markdown
|
||||
agentUA -->|no| accept{Accept prefers markdown?}
|
||||
accept -->|yes| markdown
|
||||
accept -->|no| html[Serve HTML page]
|
||||
markdown --> rewrite["Rewrite to /api/guides-md/..."]
|
||||
rewrite --> file["Read public/markdown/guides/..."]
|
||||
```
|
||||
|
||||
### Who gets what
|
||||
|
||||
| Audience | Typical request | Format | Notes |
|
||||
| ---------------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------ |
|
||||
| **Human (browser)** | `/docs/guides/.../nextjs` | HTML | Default — no special headers |
|
||||
| **Live-fetch agent** | Same URL with `Claude-User`, `ChatGPT-User`, `PerplexityBot`, or `Claude-Web` UA | Markdown | Auto-negotiated even without `.md` suffix |
|
||||
| **Live-fetch agent** | `/docs/guides/.../nextjs.md` or `Accept: text/markdown` | Markdown | Explicit request |
|
||||
| **SEO bot** (Googlebot) | Guide URL | HTML | Same page humans see; `isbot()` markdown rewrite applies only to **reference** pages |
|
||||
| **Training crawler** (GPTBot, ClaudeBot) | Guide URL | HTML | Allowed by `robots.txt` but **not** given alternate markdown — avoids cloaking |
|
||||
| **Bulk ingest** | `/llms-full.txt`, `/docs/docs.tar.gz` | Markdown | Reads prebuilt `public/markdown/` files |
|
||||
|
||||
Humans see interactive UI (copy buttons, styled panels). Agents and bulk
|
||||
tools read the pre-generated `.md` transcript — not the live HTML DOM.
|
||||
|
||||
### Agent discovery
|
||||
|
||||
Agents that don't know a specific URL can start from:
|
||||
|
||||
- `/llms.txt` — section index with links to `.md` paths
|
||||
- `/llms-full.txt` — concatenated guides + reference + product overviews
|
||||
- `rel="alternate" type="text/markdown"` on each guide page
|
||||
(`GuidesMdx.utils.tsx` → `${BASE_PATH}${pathname}.md`)
|
||||
- Docs homepage alternate → `https://supabase.com/llms-full.txt`
|
||||
|
||||
## Content negotiation
|
||||
|
||||
Shared logic lives in `packages/common/markdown-negotiation.ts`, used by
|
||||
both `apps/docs/middleware.ts` and `apps/www/middleware.ts`.
|
||||
|
||||
Markdown is served when:
|
||||
|
||||
- The URL ends in `.md`
|
||||
- `Accept: text/markdown` wins over HTML (q-value comparison)
|
||||
- The user-agent matches **live-fetch agents**: `Claude-User`,
|
||||
`Claude-Web`, `ChatGPT-User`, `PerplexityBot`
|
||||
|
||||
Training crawlers (`GPTBot`, `ClaudeBot`, etc.) are **not** given
|
||||
alternate markdown — they are governed by `robots.txt` to avoid
|
||||
cloaking penalties.
|
||||
|
||||
On guides, negotiated requests rewrite to `/api/guides-md/<slug>`.
|
||||
Each guide page advertises its markdown alternate in metadata via
|
||||
`GuidesMdx.utils.tsx` (`text/markdown` → `${BASE_PATH}${pathname}.md`).
|
||||
|
||||
404 responses from `guides-md` are also markdown and include
|
||||
`searchDocs` suggestions — useful when an agent fetches a stale URL.
|
||||
|
||||
## Bulk vs per-page retrieval
|
||||
|
||||
| Strategy | Best for |
|
||||
| ----------------------------------- | ------------------------------------------------- |
|
||||
| `/llms.txt` | Discovering available sections and reference libs |
|
||||
| `/llms-full.txt` | One-shot full ingest |
|
||||
| `/docs/docs.tar.gz` | Offline/batch ingest of all generated markdown |
|
||||
| `/docs/guides/<path>.md` | Single guide page |
|
||||
| `/docs/markdown/reference/<lib>.md` | Single reference lib export |
|
||||
|
||||
Reference pages do **not** use the same `Accept: text/markdown`
|
||||
negotiation as guides. Reference markdown comes from the static export
|
||||
and `llms-full.txt`, not from middleware negotiation.
|
||||
|
||||
## Related
|
||||
|
||||
- [`llm-agent-parity.md`](./llm-agent-parity.md) — two-pipeline fidelity,
|
||||
search caveat, agent onboarding pages, in-flux wiring.
|
||||
- [`app-map.md`](./app-map.md) — two-pipeline model, directory layout.
|
||||
- [`build-pipeline.md`](./build-pipeline.md) — prebuild steps that
|
||||
produce markdown exports and the tarball.
|
||||
- [`docs-app-direction.md`](./docs-app-direction.md) — one-to-one
|
||||
markdown fidelity goal.
|
||||
- [`known-issues.md`](./known-issues.md) — reference page length,
|
||||
search fragility.
|
||||
@@ -0,0 +1,103 @@
|
||||
# Management API reference generation
|
||||
|
||||
How `/docs/reference/api/*` is built from the live Management API OpenAPI
|
||||
spec. Verify against `apps/docs/spec/Makefile` and
|
||||
`features/docs/Reference.generated.script.ts` before acting — paths drift.
|
||||
|
||||
## Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
live["api.supabase.com<br/>/api/v1-json + v2-json"]
|
||||
raw["spec/api_v{1,2}_openapi.json"]
|
||||
redocly["Redocly bundle<br/>(no --dereferenced)"]
|
||||
bundled["spec/transforms/<br/>api_v*_openapi_deparsed.json"]
|
||||
sections["common-api-sections.json"]
|
||||
codegen["codegen:references:legacy"]
|
||||
gen["features/docs/generated/<br/>api.latest.*.json"]
|
||||
page["ApiReferencePage →<br/>ApiEndpointSection"]
|
||||
md["public/markdown/reference/api.md"]
|
||||
|
||||
live --> raw --> redocly --> bundled
|
||||
bundled --> sections
|
||||
bundled --> codegen
|
||||
sections --> codegen
|
||||
codegen --> gen --> page
|
||||
gen --> md
|
||||
```
|
||||
|
||||
1. **Download** — `make download.api.v1` in `apps/docs/spec/` curls the
|
||||
live OpenAPI into `api_v1_openapi.json` / `api_v2_openapi.json`.
|
||||
2. **Bundle** — `make dereference.api.v1` runs Redocly CLI
|
||||
(`@redocly/cli`) `bundle` into `transforms/*_deparsed.json`.
|
||||
Management API deliberately omits `--dereferenced` (circular `$ref` in
|
||||
`APIErrorObject.issues`). `$refs` are resolved later in codegen with a
|
||||
cycle guard.
|
||||
3. **Nav sections** — `sections/generateMgmtApiSections.cts` walks
|
||||
operations/tags into `common-api-sections.json`.
|
||||
4. **Codegen** — `codegen:references:legacy`
|
||||
(`Reference.generated.script.ts`) merges v1+v2, resolves refs, writes
|
||||
`api.latest.endpointsById.json`, `sections.json`, `flat.json`,
|
||||
`bySlug.json` under `features/docs/generated/`.
|
||||
5. **Runtime** — `/reference/api/[operation]` via `ApiReferencePage` →
|
||||
`SectionSwitch` → `ApiEndpointSection` (custom React, not MDX). One
|
||||
endpoint per page (DOCS-1268). Hand-written intro MDX lives under
|
||||
`docs/ref/api/`.
|
||||
6. **Agents** — `generate-reference-markdown.ts` exports the same data to
|
||||
`public/markdown/reference/api.md`.
|
||||
|
||||
Legacy EJS (`generator/api.ts` + `ApiTemplate.ts`) is not the live path.
|
||||
|
||||
## Redocly today (bundle / lint)
|
||||
|
||||
| Job | Where | Notes |
|
||||
| ------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| Bundle | `make dereference.api.v1` (and sibling targets for auth/storage/analytics) | Invoked via `npx --package=@redocly/cli redocly bundle` |
|
||||
| Lint | `make validate.analytics.v0` only | `redocly lint --extends=minimal`. Management API has no lint target |
|
||||
|
||||
Redocly is the OpenAPI **toolchain** (bundle/lint), not the page renderer.
|
||||
|
||||
## Rendering: keep the custom path
|
||||
|
||||
Pages render via custom React (`ApiEndpointSection`), not Scalar / Redoc /
|
||||
Stoplight Elements. Reasons (see also [`adding-features.md`](./adding-features.md)
|
||||
and [`known-issues.md`](./known-issues.md)):
|
||||
|
||||
- **Two pipelines** — HTML + markdown export + GraphQL search share one
|
||||
`IApiEndPoint` / generated-JSON shape. A third-party viewer forks that.
|
||||
- **Custom extensions** — `x-oauth-scope`, `x-allowed-plans`,
|
||||
`x-fga-permissions` need first-class rendering.
|
||||
- **Modular pages** — DOCS-1268 already split the monolithic API page;
|
||||
embedding a full-spec viewer would reverse that.
|
||||
- **Surface** — new dep + theming + parity work fights docs-app direction
|
||||
(reduce surface, don't add parallel renderers).
|
||||
|
||||
Prefer improving `ApiEndpointSection` / schema helpers, or deepening
|
||||
Redocly lint on download/transform. Do not propose swapping the renderer
|
||||
for an OpenAPI UI kit without addressing markdown/search/`x-*` parity.
|
||||
|
||||
Closest CLI substitutes if Redocly were unavailable: `@apidevtools/swagger-parser`
|
||||
or `swagger-cli` for bundle; Spectral for lint. Switching buys little while
|
||||
the custom cycle-safe resolve remains required.
|
||||
|
||||
## Key files
|
||||
|
||||
| Path | Role |
|
||||
| ------------------------------------------------------- | -------------------------------------------- |
|
||||
| `apps/docs/spec/Makefile` | download / Redocly bundle / section generate |
|
||||
| `apps/docs/spec/sections/generateMgmtApiSections.cts` | OpenAPI → `common-api-sections.json` |
|
||||
| `apps/docs/features/docs/Reference.generated.script.ts` | merge, resolve refs, write `api.latest.*` |
|
||||
| `apps/docs/features/docs/Reference.api.utils.ts` | `IApiEndPoint` + schema display helpers |
|
||||
| `apps/docs/features/docs/Reference.apiPage.tsx` | route → one operation page |
|
||||
| `apps/docs/features/docs/Reference.sections.tsx` | `ApiEndpointSection` UI |
|
||||
| `apps/docs/internals/generate-reference-markdown.ts` | agent markdown export |
|
||||
|
||||
## Related
|
||||
|
||||
- [`build-pipeline.md`](./build-pipeline.md) — where `codegen:references`
|
||||
sits in prebuild.
|
||||
- [`app-map.md`](./app-map.md) — reference vs guides routing.
|
||||
- [`known-issues.md`](./known-issues.md) — reference pages avoid standard
|
||||
MDX; length / modularization direction.
|
||||
- [`llm-agent-surface.md`](./llm-agent-surface.md) — markdown export
|
||||
consumption.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: pm-the-docs
|
||||
description: >-
|
||||
Docs-PM decision support for the "Write the docs" authoring process —
|
||||
makes audience, stage, and cross-cutting scope calls during the Frame
|
||||
and Shape stages, and helps decide when a docs question needs to
|
||||
self-serve vs. escalate to a docs PM. Use when framing a new docs page
|
||||
or launch, deciding what product stage or audience a feature targets,
|
||||
or judging whether a docs question needs PM sign-off.
|
||||
---
|
||||
|
||||
# PM the docs
|
||||
|
||||
Backs the Frame and Shape stages of the "Write the docs" checklist (mirrored in [reference/write-the-docs-checklist.md](reference/write-the-docs-checklist.md)) — the audience, product-stage, and cross-cutting scope calls a docs PM would normally make before drafting starts.
|
||||
|
||||
## When to invoke
|
||||
|
||||
- Starting a new docs page or launch and need to state the product stage, audience, and "why" before drafting (Frame).
|
||||
- Deciding content type, IA placement, or prerequisites for a page (Shape).
|
||||
- Unsure whether a docs question is self-serve or needs a docs PM's sign-off.
|
||||
|
||||
**Not for** drafting content itself (see [`write-the-docs`](../write-the-docs/SKILL.md)) or docs-app architecture/IA placement mechanics (see [`ask-the-docs`](../ask-the-docs/SKILL.md)).
|
||||
|
||||
## Answering a scope/stage/audience question
|
||||
|
||||
1. Read the relevant stage in [reference/write-the-docs-checklist.md](reference/write-the-docs-checklist.md) — its checkboxes state exactly what needs deciding.
|
||||
2. Read whatever context exists for the feature: the linked issue/project, the PRD, the shipped code or PR. When code and PRD disagree, the code wins for behavior claims.
|
||||
3. Answer the checklist's questions directly: product stage, audience and job-to-be-done, the one-line "why," content type, IA placement, prerequisites.
|
||||
4. Distinguish **confirmed fact** (stated in the ticket/PRD/code) from **inference** (your best read) — flag inference explicitly rather than presenting it as settled.
|
||||
5. If a decision is genuinely open at the org level (not a docs-content call), say so and name who should decide instead of inventing an answer to look complete.
|
||||
|
||||
## Self-serve vs. escalate
|
||||
|
||||
Self-serve when the checklist is clear, standards exist, and you already know the stage and audience.
|
||||
|
||||
Escalate to your docs team's PM when scope or stage is unclear, you need a review path, the bar is ambiguous, or the launch touches cross-cutting surfaces (quickstarts, API keys, tutorials, onboarding, platform concepts) — see the full "Ask the Docs PM" section in the checklist mirror.
|
||||
|
||||
## Related skills
|
||||
|
||||
- [`ask-the-docs`](../ask-the-docs/SKILL.md) — IA placement and docs-app architecture (Shape stage)
|
||||
- [`write-the-docs`](../write-the-docs/SKILL.md) — drafting once Frame/Shape are settled
|
||||
- [`review-the-docs`](../review-the-docs/SKILL.md) — self-review and PR review stages
|
||||
@@ -0,0 +1,77 @@
|
||||
# Write the docs
|
||||
|
||||
> Mirrors Supabase's proposed "Write the docs" process as of 2026-08-10. Process specifics may still evolve.
|
||||
|
||||
A practical six-stage checklist and quality standard for planning, drafting, and reviewing product documentation.
|
||||
|
||||
## What good looks like
|
||||
|
||||
- The **why** is explicit: a reader learns what problem this solves and when to reach for it, not only the steps.
|
||||
- The **content type is deliberate** and consistent within the page.
|
||||
- **Audience and prerequisites** are stated up front.
|
||||
- At least one **example is runnable and has been run** (commands, code, expected result).
|
||||
- **Correct stage** is stated; limitations are named honestly.
|
||||
- The page **lives in the right place** in the IA and links to and from related pages.
|
||||
- Terminology and formatting match existing docs (defer to the style guide once one lands).
|
||||
|
||||
## 1. Frame
|
||||
|
||||
_Skills:_ `/ask-the-docs` to see how the surface works today; `/pm-the-docs` for audience, stage, and cross-cutting scope calls.
|
||||
|
||||
- [ ] P: State the product stage (private/public alpha, beta, GA)
|
||||
- [ ] P: Name the audience and the job they are trying to do
|
||||
- [ ] P: Write one line on _why_ the feature exists (the problem it solves), not only what it does
|
||||
|
||||
## 2. Shape
|
||||
|
||||
_Skill:_ `/ask-the-docs` for IA placement, architecture, and where content lives.
|
||||
|
||||
- [ ] P: Pick the content type(s): tutorial (learning), how-to (a task), reference (lookup), explanation (the why). Do not mix types on one page (refer to [Diátaxis](https://diataxis.fr/))
|
||||
- [ ] P: Decide where the page lives in the existing IA and what links in and out (avoid orphan pages)
|
||||
- [ ] P: List prerequisites and assumed knowledge up front
|
||||
|
||||
## 3. Draft
|
||||
|
||||
_Skill:_ `/write-the-docs` to draft net-new content grounded in Linear and the code.
|
||||
|
||||
- [ ] P: Lead with the why and the outcome, then the how/what (product story first)
|
||||
- [ ] P: Include at least one runnable, copy-pasteable example that you have actually run
|
||||
- [ ] E: Contribute technical depth and verify accuracy (APIs, limits, edge cases)
|
||||
- [ ] P: Call out the current stage inline and any known limitations
|
||||
|
||||
## 4. Self-review against the bar
|
||||
|
||||
_Skill:_ `/review-the-docs` — [Local self-review](../review-the-docs/SKILL.md#local-self-review-no-open-pr) on your own branch before opening the PR.
|
||||
|
||||
- [ ] P/E: Check the draft against "What good looks like" above before opening the PR
|
||||
- [ ] P/E: Follow authoring-experience standards and tooling when available
|
||||
|
||||
## 5. PR review
|
||||
|
||||
_Skill:_ `/review-the-docs` to triage, classify, verify the build, and report.
|
||||
|
||||
- [ ] P/E: Open the PR and request review per the rules of engagement
|
||||
- [ ] Docs: Review against the published bar
|
||||
|
||||
## 6. Keep it honest
|
||||
|
||||
- [ ] P: Keep the product launch checklist's "start on day 1" docs gate honest through ship (update as stage or behavior changes)
|
||||
|
||||
## Ask the Docs PM
|
||||
|
||||
**Self-serve when:** the checklist above is clear, standards exist, and you know the product stage and audience.
|
||||
|
||||
**Ask when:** scope or stage is unclear, you need a review path, the bar is ambiguous, or the launch docs touch cross-cutting surfaces (quickstarts, API keys, tutorials, onboarding, platform concepts).
|
||||
|
||||
**What to expect:** the docs PM is the point of contact for questions and review against the bar.
|
||||
|
||||
**Where to ping:** your team's PR-review channel and current docs PM — check your contributor guide for who that is today.
|
||||
|
||||
## Reference
|
||||
|
||||
Role prefixes:
|
||||
|
||||
- **P** = Product. The product lead / area PM who writes the docs.
|
||||
- **E** = Engineering. Contributes technical depth and verifies accuracy.
|
||||
- **P/E** = Product and Engineering together.
|
||||
- **Docs** = Docs team, the reviewer.
|
||||
@@ -0,0 +1,404 @@
|
||||
---
|
||||
name: review-the-docs
|
||||
description: >-
|
||||
Review Supabase docs changes locally in ~/GitHub/supabase/supabase —
|
||||
either an open PR (triage, classify, verify) or your own branch before
|
||||
opening a PR (local self-review). Covers markdown pipeline, MDX content,
|
||||
tutorials, examples, Studio links, and docs tooling. Use when asked to
|
||||
review docs PRs, self-review a draft branch, check who has approved,
|
||||
verify build output, or evaluate supabase/supabase documentation changes.
|
||||
---
|
||||
|
||||
# Review docs PRs
|
||||
|
||||
Local review workflow for `supabase/supabase` docs changes. Classify first, then follow the matching checklist.
|
||||
|
||||
Two modes:
|
||||
|
||||
- **Open PR review** (default) — triage via `gh`, checkout, verify, report. Start at [Phase 1](#phase-1--triage-read-only).
|
||||
- **Local self-review** — no open PR yet; verify the current branch before opening one. Start at [Local self-review](#local-self-review-no-open-pr).
|
||||
|
||||
For **implementing** docs fixes (Linear tickets, worktrees, platform E2E), use [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md) instead.
|
||||
|
||||
## Core rules
|
||||
|
||||
1. **Classify before reviewing** — path patterns determine which checklist applies.
|
||||
2. **Review stacked PRs bottom-up** — each PR may base on the previous branch.
|
||||
3. **Run verification locally** — do not approve from diff alone.
|
||||
4. **Compare against `master`** when the PR claims to fix missing or broken output.
|
||||
5. **One report per batch** — sequential review, consolidated output at the end.
|
||||
6. **Separate blockers from nits** — type/style notes are suggestions unless output breaks.
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | Purpose |
|
||||
| -------------------------------------- | --------------------------------------------------------- |
|
||||
| `~/GitHub/supabase/supabase` | Main clone for review checkouts |
|
||||
| `apps/docs/content/guides/` | Source MDX |
|
||||
| `apps/docs/internals/` | Markdown pipeline (`generate-guides-markdown.ts`, etc.) |
|
||||
| `apps/docs/internals/markdown-schema/` | Component handlers → plain markdown strings |
|
||||
| `apps/docs/public/markdown/guides/` | Generated output (produced by build) |
|
||||
| `apps/docs/components/` | React MDX components |
|
||||
| `examples/` | Tutorial/quickstart apps referenced via `$CodeSample` |
|
||||
| `apps/studio/` | Dashboard UI; may link to hosted docs |
|
||||
| `.agents/skills/` | In-repo agent skills (symlinked from `.claude`/`.cursor`) |
|
||||
|
||||
## Local self-review (no open PR)
|
||||
|
||||
Use this on your own branch **before** opening a PR (checklist Stage 4). No `gh pr` required.
|
||||
|
||||
```bash
|
||||
cd ~/GitHub/supabase/supabase
|
||||
# Ensure you're on the feature branch, not master
|
||||
git branch --show-current
|
||||
git diff --name-only master...HEAD
|
||||
```
|
||||
|
||||
1. **Classify** from `git diff --name-only master...HEAD` using the [Phase 2](#phase-2--classify-pr-type) table.
|
||||
2. **Walk the bar** in [`pm-the-docs`'s checklist](../pm-the-docs/reference/write-the-docs-checklist.md) — "What good looks like" and the Self-review checkboxes.
|
||||
3. **Run type-specific checks** from the matching sections below on the current branch (no checkout step). Typical commands:
|
||||
|
||||
```bash
|
||||
# Content / tutorial MDX
|
||||
cd apps/docs && pnpm lint:mdx -- <changed-paths>
|
||||
|
||||
# Pipeline / schema handler
|
||||
cd apps/docs && pnpm build:guides-markdown
|
||||
# inspect public/markdown/guides/ for affected pages
|
||||
pnpm build:reference-markdown # when reference pipeline changed
|
||||
```
|
||||
|
||||
4. Spot-check frontmatter, internal links, and nav wiring for content changes.
|
||||
5. Write a short **self-review note** (blockers vs nits) suitable to paste into the future PR body under a "Self-review" heading.
|
||||
|
||||
Then open the PR and continue with open-PR review if a second pass is needed.
|
||||
|
||||
## Phase 1 — Triage (read-only)
|
||||
|
||||
### List PRs
|
||||
|
||||
Filter by author, label, or list all open docs PRs:
|
||||
|
||||
```bash
|
||||
# By author
|
||||
gh pr list --repo supabase/supabase --author <github-user> --state open \
|
||||
--json number,title,url,reviewDecision,latestReviews,changedFiles,additions,deletions,labels
|
||||
|
||||
# All open docs-labeled PRs
|
||||
gh pr list --repo supabase/supabase --state open --label documentation \
|
||||
--json number,title,url,reviewDecision,latestReviews,author,changedFiles
|
||||
```
|
||||
|
||||
PRs with empty `reviewDecision` and no `APPROVED` review need approval.
|
||||
|
||||
### Map the stack
|
||||
|
||||
```bash
|
||||
gh pr view <number> --repo supabase/supabase \
|
||||
--json number,title,baseRefName,headRefName,body,files
|
||||
```
|
||||
|
||||
Stacked series: `master → PR A → PR B → PR C`. Review and merge bottom-up.
|
||||
|
||||
## Phase 2 — Classify PR type
|
||||
|
||||
Inspect changed files from `gh pr view` or:
|
||||
|
||||
```bash
|
||||
gh pr diff <number> --repo supabase/supabase --name-only
|
||||
```
|
||||
|
||||
| PR type | Path signals | Primary skill section |
|
||||
| --------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
||||
| **Markdown-schema handler** | `apps/docs/internals/markdown-schema/`, `generate-guides-markdown.ts` | [Schema handler review](#schema-handler-review) |
|
||||
| **Pipeline / internals** | `apps/docs/internals/` (not just one new handler) | [Pipeline review](#pipeline-review) |
|
||||
| **Content-only MDX** | `apps/docs/content/**` only | [Content review](#content-review) |
|
||||
| **Tutorial / quickstart** | `apps/docs/content/guides/**/tutorials/`, `quickstarts/`, plus `examples/` | [Tutorial review](#tutorial-review) → also `work-linear-issue` |
|
||||
| **Example app only** | `examples/**` without matching MDX | [Example review](#example-review) |
|
||||
| **Studio ↔ docs links** | `apps/studio/**` | [Studio review](#studio-review) |
|
||||
| **Docs UI / components** | `apps/docs/components/`, `apps/docs/features/` (no pipeline) | [Component review](#component-review) |
|
||||
| **Docs tooling** | `.agents/skills/`, `.claude/skills/`, `.cursor/skills/`, `apps/docs/CONTRIBUTING.md`, `apps/docs/DEVELOPERS.md` | [Docs tooling review](#docs-tooling-review) |
|
||||
| **Mixed** | Multiple path groups above | Run each applicable section; note overlap |
|
||||
|
||||
When a PR spans types (e.g. schema handler + component refactor), run **all** matching sections.
|
||||
|
||||
## Phase 3 — Sequential local review
|
||||
|
||||
Repeat for **each PR** (bottom of stack first).
|
||||
|
||||
### Common steps (all PR types)
|
||||
|
||||
**Checkout and install:**
|
||||
|
||||
```bash
|
||||
cd ~/GitHub/supabase/supabase
|
||||
gh pr checkout <number> --repo supabase/supabase
|
||||
pnpm install --filter docs... # when node_modules missing or deps changed
|
||||
```
|
||||
|
||||
**CI spot-check:**
|
||||
|
||||
```bash
|
||||
gh pr checks <number> --repo supabase/supabase
|
||||
```
|
||||
|
||||
**Baseline on master** (when PR fixes missing/broken output):
|
||||
|
||||
```bash
|
||||
git checkout master
|
||||
# run type-specific verify command (see sections below)
|
||||
git checkout - # return to PR branch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Schema handler review
|
||||
|
||||
For PRs adding static markdown fallbacks for React MDX components.
|
||||
|
||||
**Code checks** — each handler in `apps/docs/internals/markdown-schema/`:
|
||||
|
||||
| Check | What to verify |
|
||||
| ---------------- | ------------------------------------------------------------------------ |
|
||||
| Data source | Same data/constants as the React component — no duplicated config |
|
||||
| CJS interop | `shared-data` via `createRequire(import.meta.url)` (see `SharedData.ts`) |
|
||||
| Local JSON | Direct imports fine for `apps/docs/data/` |
|
||||
| Link prefix | Links use `withDocsBasePath` |
|
||||
| SCHEMA wiring | Registered in `SCHEMA` in `generate-guides-markdown.ts` |
|
||||
| Props / shapes | All MDX usages covered — flat arrays and `{ items: [...] }` sections |
|
||||
| Silent fallbacks | `''` for unknown props OK if consistent with existing handlers |
|
||||
|
||||
Find usages: `rg '<ComponentName' apps/docs/content/`
|
||||
|
||||
**Build and inspect:**
|
||||
|
||||
```bash
|
||||
cd apps/docs && pnpm build:guides-markdown
|
||||
# Expect: Generated 546 markdown files under public/markdown/guides/
|
||||
```
|
||||
|
||||
Inspect `public/markdown/guides/` for affected pages:
|
||||
|
||||
- Previously blank sections now have lists, tables, or links
|
||||
- All MDX pages using the component are covered, not just the one in the PR description
|
||||
- Link format: `/docs/guides/...` locally; absolute URLs when `VERCEL_ENV=production`
|
||||
|
||||
---
|
||||
|
||||
### Pipeline review
|
||||
|
||||
For AST refactors, link rewriting, reference markdown generation, etc.
|
||||
|
||||
```bash
|
||||
cd apps/docs
|
||||
pnpm build:guides-markdown
|
||||
pnpm build:reference-markdown # when reference pipeline changed
|
||||
pnpm test internals/internal-links.test.ts # when link handling changed
|
||||
```
|
||||
|
||||
Verify both guides and reference output when `generate-reference-markdown.ts` or `internal-links.ts` changed.
|
||||
|
||||
---
|
||||
|
||||
### Content review
|
||||
|
||||
MDX prose, partials, navigation — no pipeline or example changes.
|
||||
|
||||
```bash
|
||||
cd apps/docs
|
||||
pnpm lint:mdx -- <changed-paths> # or monorepo equivalent on changed files
|
||||
```
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] Frontmatter valid (`title`, `description` where required)
|
||||
- [ ] Internal links resolve (`/docs/guides/...`, not broken anchors)
|
||||
- [ ] `$CodeSample` paths match existing example directories
|
||||
- [ ] Admonitions, tabs, and partial includes render sensibly in PR preview
|
||||
- [ ] No accidental whitespace-only or empty sections where components were removed
|
||||
|
||||
Compare PR preview URL (from Vercel/deployment comment) against production for visual regressions when layout components are involved.
|
||||
|
||||
---
|
||||
|
||||
### Tutorial review
|
||||
|
||||
Tutorial MDX plus matching example app. **Read [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md)** for full platform E2E — review is not complete without it when auth flows are involved.
|
||||
|
||||
```bash
|
||||
# MDX lint
|
||||
cd apps/docs && pnpm lint:mdx -- content/guides/getting-started/tutorials/<path>
|
||||
|
||||
# Example build (from work-linear-issue)
|
||||
cd examples/<example-dir>
|
||||
npm install && npm run build
|
||||
```
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] MDX steps match example code after `pnpm codegen:examples` (if `$CodeSample` used)
|
||||
- [ ] Env var names and Supabase client setup match current `@supabase/ssr` patterns
|
||||
- [ ] Example pins catalog versions — no `"latest"` for in-repo packages
|
||||
- [ ] **Platform E2E** (when auth involved): SQL migration applied, auth flow walked, profiles verified — see `work-linear-issue` Phase 3
|
||||
|
||||
---
|
||||
|
||||
### Example review
|
||||
|
||||
Example-only PRs (or example portion of a tutorial PR).
|
||||
|
||||
```bash
|
||||
cd examples/<example-dir>
|
||||
npm install && npm run build
|
||||
```
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] Build passes with no type errors
|
||||
- [ ] `.env.example` documents required vars (no secrets committed)
|
||||
- [ ] If docs reference this example, `$CodeSample` paths still valid
|
||||
|
||||
---
|
||||
|
||||
### Studio review
|
||||
|
||||
Dashboard changes linking to docs.
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] Links point to hosted docs anchors (e.g. `/guides/auth/auth-email-templates#terminology`)
|
||||
- [ ] Local-dev-only doc paths not used as the sole link target
|
||||
- [ ] Link text matches the destination section
|
||||
|
||||
---
|
||||
|
||||
### Component review
|
||||
|
||||
React component changes under `apps/docs/components/` without a new schema handler.
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] No browser-only APIs leaked into build-script imports
|
||||
- [ ] Shared constants extracted cleanly when also consumed by markdown handlers
|
||||
- [ ] Visual behavior unchanged or intentionally improved — check PR screenshots
|
||||
- [ ] If component is used in MDX exported to markdown, confirm a schema handler exists or file an follow-up
|
||||
|
||||
---
|
||||
|
||||
### Docs tooling review
|
||||
|
||||
Agent skills, contributor docs, or skill symlink wiring — no MDX/pipeline changes required.
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] Symlinks under `.claude/skills/` and `.cursor/skills/` resolve to `.agents/skills/...` (same pattern as `vitest`)
|
||||
- [ ] Cross-skill links resolve: relative for in-repo skills; absolute `docs-agent-skills` URLs only for skills that remain in that private repo
|
||||
- [ ] No personal vault paths, Obsidian references, or private-process-only instructions
|
||||
- [ ] `apps/docs/CONTRIBUTING.md` / `DEVELOPERS.md` pointers match skill names and checklist stages
|
||||
- [ ] Reference files under a skill stay near the ~250-line guideline (split if bloated)
|
||||
|
||||
```bash
|
||||
# Symlink smoke check
|
||||
ls -la .claude/skills/<skill-name> .cursor/skills/<skill-name>
|
||||
test -f .claude/skills/<skill-name>/SKILL.md
|
||||
|
||||
# Leftover internal refs
|
||||
rg -n 'Obsidian|pm-the-docs-full|Priorities/' .agents/skills
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Review report
|
||||
|
||||
One consolidated report after all PRs are reviewed.
|
||||
|
||||
### Report template
|
||||
|
||||
```markdown
|
||||
# PR review report — <author, label, or topic>
|
||||
|
||||
Reviewed locally at `~/GitHub/supabase/supabase`.
|
||||
|
||||
**Stack order:** master → #NNN → … (if applicable)
|
||||
|
||||
---
|
||||
|
||||
## [#NNN — Title](https://github.com/supabase/supabase/pull/NNN)
|
||||
|
||||
**Type:** schema handler | pipeline | content | tutorial | example | studio | component | docs tooling | mixed
|
||||
|
||||
**Verdict:** Approve | Approve with nits | Request changes
|
||||
|
||||
| Check | Result |
|
||||
| ------------------ | ------ |
|
||||
| PR type checks | … |
|
||||
| Build / lint | … |
|
||||
| Baseline vs master | … |
|
||||
| CI | … |
|
||||
|
||||
**Verified:**
|
||||
|
||||
- …
|
||||
|
||||
**Notes:**
|
||||
|
||||
- …
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| PR | Type | Recommendation | Blockers |
|
||||
| ---- | ---- | -------------- | -------- |
|
||||
| #NNN | … | … | … |
|
||||
|
||||
**Merge order:** bottom-up after approval (if stacked).
|
||||
```
|
||||
|
||||
### Verdict guidance
|
||||
|
||||
| Verdict | When |
|
||||
| --------------------- | ------------------------------------------------------------------------------------ |
|
||||
| **Approve** | All type-specific checks pass; output correct |
|
||||
| **Approve with nits** | Works correctly; minor type/style/docs nits only |
|
||||
| **Request changes** | Build/lint fails, broken links, wrong data, missing coverage, or failed platform E2E |
|
||||
|
||||
## Inline review comments
|
||||
|
||||
```text
|
||||
https://github.com/supabase/supabase/pull/<number>/files#diff-<blob-sha>R<line>
|
||||
```
|
||||
|
||||
```bash
|
||||
gh api repos/supabase/supabase/pulls/<number>/files \
|
||||
--jq '.[] | select(.filename | endswith("<file>")) | .sha'
|
||||
```
|
||||
|
||||
Include concrete evidence — JSON line numbers, before/after output snippets, failing command output.
|
||||
|
||||
## Handler pattern reference
|
||||
|
||||
```typescript
|
||||
// apps/docs/internals/markdown-schema/Example.ts
|
||||
import { withDocsBasePath } from '../internal-links'
|
||||
|
||||
export const Example = ({ props }: { props: Record<string, unknown> }): string => {
|
||||
// Same data source as React component → plain markdown string
|
||||
}
|
||||
```
|
||||
|
||||
## Parallel work
|
||||
|
||||
Independent PRs: subagents can review in separate worktrees. **Stacked** series: review sequentially on one clone, bottom-up.
|
||||
|
||||
## Output checklist
|
||||
|
||||
- [ ] Approval status fetched for all requested PRs
|
||||
- [ ] Each PR classified by type
|
||||
- [ ] Stack order documented (if applicable)
|
||||
- [ ] Type-specific verification run locally (not just schema handler defaults)
|
||||
- [ ] Master baseline compared when PR fixes missing output
|
||||
- [ ] Platform E2E noted for tutorial/auth PRs (or deferred with reason)
|
||||
- [ ] Verdict and blockers stated per PR
|
||||
- [ ] Merge order recommended
|
||||
- [ ] Inline comment links provided for nits
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: write-the-docs
|
||||
description: >-
|
||||
Draft new or updated Supabase docs content for a feature or launch,
|
||||
grounded in Linear (the ticket plus its product/PM context), a read of the
|
||||
actual code, and the docs style guide once one exists. Use when asked to
|
||||
write docs for a new feature, a launch (e.g. Select 2026), or a Linear
|
||||
ticket that needs net-new content rather than a bug fix. Not for
|
||||
implementing existing docs bug reports — use work-linear-issue for that.
|
||||
---
|
||||
|
||||
# Write the docs
|
||||
|
||||
Drafts net-new (or substantially rewritten) Supabase docs content for a feature or launch. Distinct from [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md), which implements and fixes existing docs tickets — this skill is for the case where the content doesn't exist yet and has to be authored from scratch, grounded in four inputs rather than guessed.
|
||||
|
||||
## Core rules
|
||||
|
||||
1. **Gather before drafting.** Never draft from a ticket title alone. Pull all four inputs below first; a thin gather phase produces a draft that's wrong about how the feature actually works.
|
||||
2. **Separate confirmed behavior from product intent from inference.** Code tells you what the feature does today. Linear/PRD/PRFAQ tells you what it's meant to do and how it should be positioned. Anything you had to guess, flag explicitly rather than stating it as fact.
|
||||
3. **Follow CONTRIBUTING.md and WORD_LIST.md; say so when you fall back to a precedent page.** Don't silently invent voice/structure rules — name the nearest existing-page precedent you followed instead (see [reference/style-fallback.md](reference/style-fallback.md)).
|
||||
4. **Reuse, don't duplicate.** For docs-app architecture/placement questions, use [`ask-the-docs`](../ask-the-docs/SKILL.md) and [`audit-docs-ia`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/audit-docs-ia/SKILL.md) rather than re-deriving that knowledge here.
|
||||
5. **Know what you're actually drafting.** Not everything that looks like "docs for a feature" is a hand-written page — see the content-type gate below before you start writing.
|
||||
|
||||
## Phase 1 — Gather (read-only)
|
||||
|
||||
Four inputs, in order:
|
||||
|
||||
1. **Style guide.** Start with [`apps/docs/CONTRIBUTING.md`](../../../apps/docs/CONTRIBUTING.md) and [`apps/docs/WORD_LIST.md`](../../../apps/docs/WORD_LIST.md) for voice, structure, and terminology. If those don't cover the case, fall back to the nearest comparable existing page under `apps/docs/content/` and say explicitly: _"no dedicated style guide yet — following the precedent of `<page>`."_ See [reference/style-fallback.md](reference/style-fallback.md).
|
||||
2. **Linear — the ticket and its product context.** Pull the Linear issue itself, then don't stop there: pull its parent project/initiative description too (PRD, PRFAQ, RFC, or initiative narrative) and any PM comments. Product framing/positioning language usually lives one level up from the ticket, not in the ticket body — see how the Select 2026 initiative's own description carried the real launch narrative, not any single project's ticket. Distinguish scope the ticket actually commits to from aspirational language in the PRD.
|
||||
3. **Code.** Read the actual implementation before writing a single behavior claim — the PRD describes intent, the code describes what shipped. Check the Linear issue/project first for a linked `supabase/supabase` PR — its diff and description are the most precise "what actually shipped" source, more precise than a general codebase read. If no PR is linked, locate the feature directly in `supabase/supabase` (or the product's own repo), and apply [`ask-the-docs`](../ask-the-docs/SKILL.md)'s reuse/minimalism lens: understand what exists before describing it. If code and PRD disagree, the code wins for behavior claims — flag the mismatch rather than silently picking one.
|
||||
4. **Whatever else the author supplies.** Screenshots, example projects, related pages, Slack threads, a specific voice sample. Screenshots are for more than general context — use them to verify the _exact_ button/menu/field labels before writing instructional steps that reference them; a mismatched UI label is one of the easiest, most avoidable errors in a draft. Ask for these when the feature's user-facing shape is still unclear after 1–3, rather than guessing.
|
||||
|
||||
Summarize all four back to the requester before drafting: what's confirmed, what's product intent vs. shipped behavior, what's still a gap. Stop and ask if a real gap would change the draft's structure or scope.
|
||||
|
||||
## Phase 1.5 — Content-type gate
|
||||
|
||||
Before drafting, classify what's actually being asked for against `apps/docs`'s real content types (see [`ask-the-docs`](../ask-the-docs/SKILL.md)'s `app-map.md` "Content types" table, and [reference/content-type-gate.md](reference/content-type-gate.md) here):
|
||||
|
||||
- **Guide / tutorial** — hand-written MDX under `content/guides/`. This is what this skill drafts.
|
||||
- **Troubleshooting** — hand-written MDX under `content/troubleshooting/`, sometimes synced from GitHub issues. Also in scope.
|
||||
- **Reference** — generated from `spec/` (OpenAPI, SDK YAML, CLI config) → `features/docs/generated/**`. **Not hand-authored via the standard MDX path.** If the ask is actually reference-type content (a new API endpoint, config option, or SDK method that needs a reference entry), stop drafting MDX — it would diverge from or get silently overwritten by the generator. Instead point to the spec/codegen pipeline (`apps/docs/spec/`, `apps/docs/generator/`; see `ask-the-docs`'s `management-api-reference.md` for the OpenAPI-specific flow) and say so explicitly rather than producing a page that looks done but isn't the real fix.
|
||||
|
||||
When in doubt, ask `ask-the-docs` rather than guessing — this classification is the one call in this skill most likely to be wrong if made from outside knowledge of the app.
|
||||
|
||||
## Phase 2 — Draft
|
||||
|
||||
- Follow `apps/docs` MDX conventions (component usage, frontmatter, code sample wiring) — see [`ask-the-docs`](../ask-the-docs/SKILL.md) for the pipeline details rather than re-deriving them.
|
||||
- Place the page using existing IA precedent; for a placement call that isn't obvious, consult [`audit-docs-ia`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/audit-docs-ia/SKILL.md)'s nav/IA knowledge rather than guessing a nav slot.
|
||||
- **Wire it into navigation, not just onto disk.** Placement (which section) and nav enablement (whether it actually shows up) are separate — confirm the current nav-registration mechanism via `ask-the-docs`/`audit-docs-ia` rather than assuming a page is discoverable just because the file exists in the right folder.
|
||||
- Ground every behavior claim in Phase 1's code read (the linked PR when there is one); ground every "why this matters" framing in the PRD/PM context; mark inferred material inline (e.g. an HTML comment or a flagged line in the handoff summary) so a reviewer can find it fast.
|
||||
|
||||
## Phase 2.5 — Review checklist
|
||||
|
||||
Before handing off, confirm:
|
||||
|
||||
- [ ] CONTRIBUTING.md / WORD_LIST.md followed, or precedent page named explicitly
|
||||
- [ ] Every behavior claim traces to the code read (ideally the linked PR), not just the PRD
|
||||
- [ ] Every "why it matters" / positioning line traces to Linear/PM context, not invented
|
||||
- [ ] Inferred or assumed material is flagged, not stated as fact
|
||||
- [ ] Content type confirmed as Guide/Troubleshooting (not something that belongs in generated Reference instead)
|
||||
- [ ] Nav placement and nav enablement both wired, not just the placement
|
||||
- [ ] Internal links resolve; first-use of new terms/acronyms is defined
|
||||
|
||||
## Phase 3 — Handoff
|
||||
|
||||
This skill stops at a reviewable draft. It does not open worktrees or PRs itself:
|
||||
|
||||
- Hand off to [`create-pull-request`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/create-pull-request/SKILL.md) (and [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md) if the ticket needs a full worktree+PR flow) for the actual PR mechanics. Carry the Phase 1/2 flagged-assumptions list forward explicitly into that handoff — it belongs in the PR description (e.g. a "needs review" section) so a reviewer sees it, not just as an inline comment buried in the draft.
|
||||
- If the feature is UI-driven and the PR will need screenshots/GIFs, flag [`proof-it-works`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/proof-it-works/SKILL.md) as the next step rather than capturing evidence here.
|
||||
|
||||
## Additional resources
|
||||
|
||||
- Style / terminology: [`apps/docs/CONTRIBUTING.md`](../../../apps/docs/CONTRIBUTING.md), [`apps/docs/WORD_LIST.md`](../../../apps/docs/WORD_LIST.md), [reference/style-fallback.md](reference/style-fallback.md)
|
||||
- Content-type gate detail: [reference/content-type-gate.md](reference/content-type-gate.md)
|
||||
- "Write the docs" checklist (Draft stage): [`pm-the-docs`](../pm-the-docs/SKILL.md)'s [reference/write-the-docs-checklist.md](../pm-the-docs/reference/write-the-docs-checklist.md)
|
||||
- Docs-app architecture/placement: [`ask-the-docs`](../ask-the-docs/SKILL.md), [`audit-docs-ia`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/audit-docs-ia/SKILL.md)
|
||||
- PR mechanics: [`create-pull-request`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/create-pull-request/SKILL.md), [`work-linear-issue`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/work-linear-issue/SKILL.md)
|
||||
- Screenshots/proof: [`proof-it-works`](https://github.com/supabase/docs-agent-skills/blob/main/.claude/skills/proof-it-works/SKILL.md)
|
||||
@@ -0,0 +1,22 @@
|
||||
# Content-type gate
|
||||
|
||||
Before drafting anything, classify the request against `apps/docs`'s real content types. This is grounded in `ask-the-docs`'s `app-map.md` "Content types" table — re-check that table if this note and the live app-map ever disagree, since the app-map is the source of truth.
|
||||
|
||||
| Type | Location | Hand-authored by this skill? |
|
||||
|---|---|---|
|
||||
| **Guide / tutorial** | `content/guides/` | Yes — hand-written MDX, goal-oriented. This is the default case. |
|
||||
| **Troubleshooting** | `content/troubleshooting/` | Yes, though some entries sync from GitHub issues — check before assuming a fresh page is needed. |
|
||||
| **Reference** | Generated from `spec/` (OpenAPI, SDK YAML, CLI config) → `features/docs/generated/**` | **No.** Reference pages do not use the standard MDX path — see `ask-the-docs`'s `docs-app-direction.md` for why, and `management-api-reference.md` for the OpenAPI-specific spec → codegen → reference-page flow. |
|
||||
| **Federated** | External repos, pulled at build time | No — out of scope for this skill; see `ask-the-docs`'s `federated-docs.md`. |
|
||||
|
||||
## What to do when the ask is actually Reference-type
|
||||
|
||||
A common trap: a ticket says "document the new `X` config option" or "add docs for the new API endpoint," which sounds like a normal doc-writing ask but is actually a spec change. If so:
|
||||
|
||||
1. Don't hand-draft an MDX reference page — it will diverge from or get silently overwritten by the next `generate-reference-markdown.ts` run.
|
||||
2. Identify the correct spec source (`apps/docs/spec/` — OpenAPI, SDKSpec, ConfigSpec, or CLISpec depending on the surface).
|
||||
3. Say explicitly in the handoff that the real fix is a spec/codegen change, not a docs PR from this skill, and point to `ask-the-docs` for the specific spec-editing workflow.
|
||||
|
||||
## When it's genuinely ambiguous
|
||||
|
||||
Some features span both — e.g. a new API endpoint (Reference) that also needs a task-oriented guide showing how to use it (Guide). In that case, split the work: flag the Reference-type piece per above, and draft only the Guide-type piece here.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Style guide fallback
|
||||
|
||||
There is no separate published style guide yet beyond what already lives in
|
||||
this repo. Use the public sources below, in order:
|
||||
|
||||
1. Read [`apps/docs/CONTRIBUTING.md`](../../../../apps/docs/CONTRIBUTING.md)
|
||||
for authoring conventions (voice, structure, document types).
|
||||
2. Read [`apps/docs/WORD_LIST.md`](../../../../apps/docs/WORD_LIST.md) for
|
||||
preferred spelling, capitalization, and terminology.
|
||||
3. If those don't cover the case, find the nearest comparable existing page
|
||||
under `apps/docs/content/` (same product area, similar content type —
|
||||
reference vs. guide vs. quickstart) and follow its voice, heading
|
||||
structure, and code-sample conventions.
|
||||
4. State which page you followed as precedent in the handoff summary — e.g.
|
||||
"no dedicated style guide yet — following the precedent of
|
||||
`guides/storage/uploads.mdx`."
|
||||
5. When a dedicated style guide is added to the repo later, prefer it over
|
||||
precedent-matching and drop this fallback step.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/ask-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/pm-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/review-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/write-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/ask-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/pm-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/review-the-docs
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../.agents/skills/write-the-docs
|
||||
@@ -19,6 +19,21 @@ To make docs as clear as possible:
|
||||
- Avoid using idioms and colloquialisms, such as `piece of cake`. These phrases are often specific to a region or culture.
|
||||
- Refer to the reader as `you`. Don't use `we` to refer to the reader. Use `we` only to refer to the Supabase team.
|
||||
|
||||
## AI agent skills for docs authoring
|
||||
|
||||
If you're using Claude Code or Cursor, this repo ships four skills that back the [Write the docs](../../.agents/skills/pm-the-docs/reference/write-the-docs-checklist.md) authoring checklist.
|
||||
|
||||
Invoke a skill by name: `/write-the-docs`, `/ask-the-docs`, `/pm-the-docs`, `/review-the-docs`.
|
||||
|
||||
| Skill | Checklist stage | Use for |
|
||||
| --- | --- | --- |
|
||||
| [`pm-the-docs`](../../.agents/skills/pm-the-docs/SKILL.md) | Frame / Shape | Audience, product-stage, and cross-cutting scope calls |
|
||||
| [`ask-the-docs`](../../.agents/skills/ask-the-docs/SKILL.md) | Frame / Shape | `apps/docs` architecture, IA placement, and where content lives |
|
||||
| [`write-the-docs`](../../.agents/skills/write-the-docs/SKILL.md) | Draft | Drafting net-new content grounded in the code |
|
||||
| [`review-the-docs`](../../.agents/skills/review-the-docs/SKILL.md) | Self-review / PR review | Checking a draft and PR triage/verification |
|
||||
|
||||
The canonical files live in `.agents/skills/`, with Git symlinks in `.claude/skills/` and `.cursor/skills/`.
|
||||
|
||||
## Document types
|
||||
|
||||
Supabase docs contain 4 types of documents. Before you start writing, think about what type of doc you need.
|
||||
|
||||
Reference in new issue
Block a user