Back to Plate

Shadcn Docs Restart Comparison

docs/plans/2026-05-23-shadcn-docs-restart-comparison.md

53.0.854.8 KB
Original Source

Shadcn Docs Restart Comparison

Goal

Compare latest local upstream shadcn docs in ../ui/apps/v4 with Plate's current docs app in apps/www, then identify every meaningful Plate-specific change before restarting Plate docs from upstream.

The question is not "how do we merge this today." The question is: when Plate restarts from latest shadcn docs, what is worth deliberately reapplying, what should be thrown away, and what should be adopted from upstream without debate?

Bottom Line

Restart from ../ui/apps/v4. Do not try to patch the current apps/www app forward. The two apps no longer differ by theme and copy. They have different route maps, search models, registry pipelines, and product surface.

Upstream should win for:

  • Fumadocs source pipeline.
  • Docs routing/page tree/search.
  • shadcn v4 registry contract, style/base layout, create/init/view flow.
  • Core shell pieces that are still generic shadcn docs infrastructure.

Plate should reapply only the parts that are real Plate product leverage:

  • Plate docs content from root content/**.
  • Plate API MDX component vocabulary and generated API docs support.
  • Plate registry content and install docs, modernized onto upstream shadcn v4 registry behavior.
  • Plate editor demos and registry preview/source display.
  • Workspace-package source aliases and split typecheck model.
  • Package integration tests if apps/www remains the integration harness.
  • CN docs only if Chinese docs are still a product requirement.
  • Plate-specific header links, MCP entry, Plate Plus links, and LLM/raw-markdown support through the upstream copy-page model.

Throw the Plate theme/customizer work. Brutal take: it is old fork residue with high surface area and low leverage. Upstream's current theme/style system is stronger, fresher, and tied to the actual shadcn v4 product.

2026-05-24 Current-State Refresh

This artifact was first written before the Plate docs source cutover landed. The current checkout is already past that first step:

  • The local upstream shadcn docs source is ../ui/apps/v4; ../shadcn/apps/v4 is not present in this workspace.
  • apps/www now has source.config.ts, src/lib/source.ts, createMDX in next.config.ts, build:source, postinstall: fumadocs-mdx, and docs routes that read source.getPage(...).
  • English docs rendering uses doc.data.body, doc.data.getText("raw"), and the registry component/example fallback.
  • CN docs are modeled through Fumadocs i18n with languages: ["en", "cn"].
  • Contentlayer is gone from apps/www scripts and dependencies.
  • Docs content now lives under content/docs/**, with content/docs/meta.json as the committed Fumadocs page-tree metadata root.
  • Runtime docs navigation, pager metadata, mobile docs nav, and command-menu fallback links no longer read docsConfig directly.

The current middle state is narrower than the original restart problem, but still not the final restart:

  • docsConfig and its sync generator are gone; committed content/docs/meta.json is the navigation metadata source.
  • The route tree, registry build, generated registry output model, and retained Plate product surfaces still need further upstream-aligned pruning.

So the next useful restart work is not "remove Contentlayer." That is done. The next useful work is to replace the remaining navigation/search/registry/app-shell authorities with the upstream Fumadocs and shadcn v4 model while deliberately reapplying Plate product surfaces.

Evidence Snapshot

AreaUpstream ../ui/apps/v4Plate apps/wwwTake
Main app files206 under app51 under src/appRoute tree diverged hard.
Content files227 under content/docs, including meta.jsonPlate docs now live under content/docs/**, including CN files and meta.jsonContent root is aligned; exact document set is Plate-owned.
Registry files1127 under registry381 under src/registryDifferent registry ownership and generated output model.
Components71 under components104 under src/componentsPlate added docs/API/editor/product components.
Scripts6 under scripts7 under apps/www/scriptsPlate replaced upstream registry/docs build pieces.
Shared app paths5 exact relative matches36 Plate-only app filesThis is a rewrite candidate, not a merge candidate.
Shared content paths0 exact relative matches251 Plate-only content filesContent has to be migrated, not merged.
Tests6 upstream app tests70+ Plate app/registry/package integration testsPlate tests are a separate asset.

Source Stacks

Upstream stack

Files:

  • ../ui/apps/v4/package.json
  • ../ui/apps/v4/next.config.mjs
  • ../ui/apps/v4/source.config.ts
  • ../ui/apps/v4/lib/source.ts
  • ../ui/apps/v4/mdx-components.tsx

Upstream uses fumadocs-mdx, fumadocs-ui, fumadocs-core, [email protected], [email protected], React 19.2.3, @base-ui/react, radix-ui, icon packs, and a shadcn v4 registry build.

Important scripts:

  • postinstall: fumadocs-mdx
  • dev: pnpm icons:dev & next dev --turbopack --port 4000
  • build: pnpm registry:build && next build
  • registry:build: pnpm --filter=shadcn build && bun run ./scripts/build-registry.mts

Fumadocs source is first-class:

  • source.config.ts calls defineDocs({ dir: "content/docs" }).
  • lib/source.ts loads @/.source through fumadocs-core/source.
  • next.config.mjs wraps config with createMDX({}).

Plate stack

Files:

  • apps/www/package.json
  • apps/www/next.config.ts
  • apps/www/source.config.ts
  • apps/www/src/lib/source.ts
  • apps/www/src/components/mdx-components.tsx
  • apps/www/scripts/build-registry.mts
  • apps/www/scripts/build-docs-registry.mts
  • apps/www/scripts/check-docs-source-parity.mts

Plate now uses [email protected], [email protected], createMDX, defineDocs({ dir: "../../content/docs" }), and [email protected]. It still uses many @platejs/* workspace deps, editor runtime deps, AI/upload/docx/yjs/dnd deps, and package integration tests.

Important scripts:

  • prebuild: pnpm build:source
  • build: pnpm build:registry && next build with the prebuild lifecycle running pnpm build:source
  • build:source: fumadocs-mdx
  • dev: pnpm build:source && next dev
  • typecheck: pnpm build:source && tsx --tsconfig ./scripts/tsconfig.scripts.json scripts/check-docs-source-parity.mts && tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.package-integration.json
  • build:registry: tsx --tsconfig ./scripts/tsconfig.scripts.json scripts/build-registry.mts

Decision: the Fumadocs source-engine adoption is already done in this checkout. Keep Plate's API MDX vocabulary and registry docs publishing as content/features, then finish the restart by replacing the remaining old nav/search/registry/app-shell pieces.

Routing Comparison

Upstream routes

Primary files:

  • ../ui/apps/v4/app/(app)/(root)/page.tsx
  • ../ui/apps/v4/app/(app)/docs/[[...slug]]/page.tsx
  • ../ui/apps/v4/app/(app)/docs/layout.tsx
  • ../ui/apps/v4/app/(app)/blocks/[...categories]/page.tsx
  • ../ui/apps/v4/app/(app)/charts/[type]/page.tsx
  • ../ui/apps/v4/app/(app)/colors/page.tsx
  • ../ui/apps/v4/app/(app)/create/page.tsx
  • ../ui/apps/v4/app/(app)/llm/[[...slug]]/route.ts
  • ../ui/apps/v4/app/(create)/init/route.ts
  • ../ui/apps/v4/app/(create)/init/md/route.ts
  • ../ui/apps/v4/app/(create)/init/v0/route.ts
  • ../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsx
  • ../ui/apps/v4/app/api/search/route.ts

Upstream docs app is also a shadcn product app:

  • Home.
  • Docs.
  • Blocks.
  • Charts.
  • Colors.
  • Create.
  • Examples.
  • View renderer.
  • Init API.
  • Search API.
  • LLM markdown route.

Plate routes

Primary files:

  • apps/www/src/app/(app)/page.tsx
  • apps/www/src/app/(app)/docs/[[...slug]]/page.tsx
  • apps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsx
  • apps/www/src/app/(app)/docs/layout.tsx
  • apps/www/src/app/(app)/docs/api/page.tsx
  • apps/www/src/app/(app)/docs/components/page.tsx
  • apps/www/src/app/(app)/docs/examples/page.tsx
  • apps/www/src/app/(app)/docs/plugins/page.tsx
  • apps/www/src/app/(app)/docs/examples/slate-to-html/page.tsx
  • apps/www/src/app/(app)/editors/page.tsx
  • apps/www/src/app/(blocks)/blocks/[name]/page.tsx
  • apps/www/src/app/(blocks)/blocks/playground/page.tsx
  • apps/www/src/app/api/registry-source/[name]/route.ts
  • apps/www/src/app/cn/docs/[[...slug]]/page.tsx
  • apps/www/src/app/dev/**

Plate docs app is a Plate product/docs/registry app:

  • Plate homepage.
  • Docs.
  • Editors.
  • Component docs.
  • Example docs.
  • API docs.
  • Plugin docs.
  • CN docs.
  • Editor/block demos.
  • Dev/debug routes.
  • Custom registry source API.

Decision: use upstream route shape as the base, then reintroduce Plate routes deliberately. Do not copy Plate's route tree wholesale.

Docs Engine And Content Model

Upstream

Files:

  • ../ui/apps/v4/source.config.ts
  • ../ui/apps/v4/lib/source.ts
  • ../ui/apps/v4/content/docs/**
  • ../ui/apps/v4/content/docs/**/meta.json

Upstream docs are Fumadocs-native:

  • source.generateParams().
  • source.getPage(params.slug).
  • source.pageTree.
  • page.data.getText("raw").
  • doc.body as the compiled MDX component.
  • Fumadocs meta.json drives navigation structure.

Plate

Files:

  • content/**/*.mdx
  • apps/www/source.config.ts
  • apps/www/src/lib/source.ts
  • apps/www/src/config/docs.ts
  • apps/www/src/config/docs-api.ts
  • apps/www/src/config/docs-examples.ts
  • apps/www/src/config/docs-plugins.ts
  • apps/www/src/config/registry-to-nav.ts

Plate docs are Fumadocs MDX plus hand-authored nav config:

  • Root content/**, not app-local content/docs/**.
  • (group) directory names are stripped from slugs.
  • *.cn.mdx translated docs live beside English docs.
  • docsConfig.sidebarNav is the real nav source.
  • source.config.ts extends Fumadocs frontmatter for component, docs, featured, links, published, and toc.
  • apps/www/src/lib/source.ts exposes Fumadocs i18n with English and Chinese languages.

Decision: the source engine has migrated, but the content layout has not restarted from upstream. The target should still be content/docs/** or an equally explicit Fumadocs layout with committed meta.json navigation, not root content plus permanent TS nav authority.

Keep from Plate:

  • The actual Plate docs content.
  • The docs, links, toc, and API-related frontmatter concepts if still used.
  • The category grouping idea: guides, installation, plugins, API, examples, components.

Throw from Plate:

  • Root-content routing as an implicit permanent compatibility layer.
  • The manual docsConfig nav as the only page-tree source.
  • Any lingering docs metadata fallback that duplicates Fumadocs page data without a transition check.

MDX And API Docs

Upstream MDX

Files:

  • ../ui/apps/v4/mdx-components.tsx
  • ../ui/apps/v4/components/component-preview.tsx
  • ../ui/apps/v4/components/component-source.tsx
  • ../ui/apps/v4/components/components-list.tsx
  • ../ui/apps/v4/components/code-tabs.tsx
  • ../ui/apps/v4/components/code-block-command.tsx

Upstream MDX components are mostly shadcn docs primitives:

  • Typography.
  • Callout.
  • CodeTabs.
  • ComponentPreview.
  • ComponentSource.
  • ComponentsListWrapper.
  • DirectoryList.
  • Kbd.
  • Tabs and accordions.

Plate MDX

Files:

  • apps/www/src/components/mdx-components.tsx
  • apps/www/src/components/api-list.tsx
  • apps/www/src/components/package-info.tsx
  • apps/www/src/components/component-installation.tsx
  • apps/www/src/components/component-preview.tsx
  • apps/www/src/components/component-preview-pro.tsx
  • apps/www/src/components/component-source.tsx
  • apps/www/src/components/framework-docs.tsx
  • apps/www/src/components/release-index.tsx
  • apps/www/src/registry/blocks/fumadocs/fumadocs-mdx-components.tsx
  • apps/www/src/registry/blocks/fumadocs/mdx-plate-components.tsx

Plate MDX adds a real API documentation language:

  • API
  • APIAttributes
  • APIItem
  • APIList
  • APIListAPI
  • APIMethods
  • APIOptions
  • APIParameters
  • APIProps
  • APIReturns
  • APIState
  • APISubList
  • APISubListItem
  • APITransforms
  • KeyTable
  • KeyTableItem
  • PackageInfo
  • ComponentInstallation
  • ComponentPreviewPro
  • ReleaseIndex

Usage evidence:

  • Root content/api/** heavily uses APIItem, APIOptions, APIParameters, APIReturns, APISubListItem, and PackageInfo.
  • The scan found thousands of Plate API component tags across MDX. This is not cosmetic.
  • apps/www/src/registry/blocks/fumadocs/fumadocs-mdx-components.tsx already looks like a bridge for rendering Plate API docs in Fumadocs.

Decision: keep Plate API MDX vocabulary. Rebuild it as a Fumadocs-compatible MDX component layer, starting from apps/www/src/registry/blocks/fumadocs/*, not from the old Contentlayer runtime wrapper.

Throw:

  • useMDXComponent from next-contentlayer2/hooks.
  • Jotai-only hydration inside MDX unless a current component still needs it.
  • Empty placeholder wrappers for registry install if the new target can render them cleanly.

Keep:

  • API component names and rendered behavior.
  • PackageInfo if bundle/source/npm metadata still matters.
  • ComponentInstallation if component docs remain generated from registry metadata.
  • ComponentPreviewPro only if Plate Plus examples remain linked from docs.

Docs Page And Layout

Upstream docs page

Files:

  • ../ui/apps/v4/app/(app)/docs/[[...slug]]/page.tsx
  • ../ui/apps/v4/app/(app)/docs/layout.tsx
  • ../ui/apps/v4/components/docs-sidebar.tsx
  • ../ui/apps/v4/components/docs-toc.tsx
  • ../ui/apps/v4/components/docs-copy-page.tsx
  • ../ui/apps/v4/components/docs-base-switcher.tsx
  • ../ui/apps/v4/components/open-in-v0-cta.tsx

Upstream page behavior:

  • Static docs with dynamic = "force-static", dynamicParams = false, revalidate = false.
  • Metadata requires title and description.
  • Uses findNeighbour(source.pageTree, page.url).
  • Uses DocsCopyPage.
  • Shows DocsBaseSwitcher for base/radix component docs.
  • Renders TOC from Fumadocs doc data.
  • Uses Fumadocs sidebar from source.pageTree.

Plate docs page

Files:

  • apps/www/src/app/(app)/docs/[[...slug]]/page.tsx
  • apps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsx
  • apps/www/src/app/(app)/docs/layout.tsx
  • apps/www/src/components/docs-nav.tsx
  • apps/www/src/components/docs-toc.tsx
  • apps/www/src/components/llm-copy-button.tsx
  • apps/www/src/components/view-options.tsx
  • apps/www/src/components/open-in-plus.tsx

Plate page behavior:

  • Static docs with dynamic = 'force-static'.
  • Looks up Fumadocs pages with source.getPage(params.slug, "en").
  • Falls back to registry-derived docs for /docs/components/[name] and /docs/examples/[name].
  • Generates static params from both source.getPages("en") and registry items.
  • Builds related docs from registry file/dependency data.
  • Renders ComponentInstallation for component docs.
  • Renders ComponentPreview for example docs.
  • Adds LLMCopyButton, ViewOptions, OpenInPlus, related docs badges, previous/next buttons, and custom TOC.

Decision: keep the registry-derived docs behavior. The first Fumadocs route cutover is already in place, but doc-content.tsx, related docs, pager/nav metadata, and LLM UI still need to be judged against upstream's Fumadocs page model instead of carried forward by inertia.

Keep:

  • Registry fallback pages for Plate UI components and examples.
  • Related docs inference from registry dependencies and file.meta.docs.
  • Plate-specific LLM context only if upstream's copy-page and .md route model leaves a real gap.
  • OpenInPlus if Plate Plus is still part of docs conversion.

Throw or rewrite:

  • Custom DocsNav accordion/filter as the primary nav. Use upstream DocsSidebar/Fumadocs page tree first.
  • Manual active-section syncing and delayed scroll hacks in DocsNav.
  • docsMap fallback as a substitute for source metadata.

Registry And Generated Docs

Upstream registry model

Files:

  • ../ui/apps/v4/scripts/build-registry.mts
  • ../ui/apps/v4/registry/bases/base/registry.ts
  • ../ui/apps/v4/registry/bases/radix/registry.ts
  • ../ui/apps/v4/registry/new-york-v4/**
  • ../ui/apps/v4/registry/styles/style-*.css
  • ../ui/apps/v4/public/r/**
  • ../ui/apps/v4/registry/config.test.ts

Upstream v4 registry pipeline:

  • Authored source lives in registry/bases/base and registry/bases/radix.
  • Style tokens live in registry/styles/style-*.css.
  • Demos live in examples.
  • Build creates base/style combinations.
  • Build emits runtime indexes, public registry JSON, styled UI copies, RTL UI for supported combinations, and generated output under public/r.
  • Registry schema comes from shadcn/schema.
  • Build uses upstream shadcn/utils transforms.

This is the contract Plate should follow at the installer boundary.

Plate registry model

Files:

  • apps/www/src/registry/registry.ts
  • apps/www/src/registry/registry-ui.ts
  • apps/www/src/registry/registry-components.ts
  • apps/www/src/registry/registry-examples.ts
  • apps/www/src/registry/registry-blocks.ts
  • apps/www/src/registry/registry-hooks.ts
  • apps/www/src/registry/registry-lib.ts
  • apps/www/src/registry/registry-kits.ts
  • apps/www/src/registry/registry-pro.ts
  • apps/www/scripts/build-registry.mts
  • apps/www/scripts/build-docs-registry.mts
  • apps/www/src/lib/rehype-utils.ts
  • apps/www/src/lib/registry-cache.ts
  • apps/www/public/r/**
  • apps/www/public/rd/**

Plate registry pipeline:

  • Builds a plate registry with homepage https://platejs.org.
  • Resolves non-@ registry dependencies to /r or /rd URLs.
  • Generates src/__registry__/index.tsx with React.lazy component previews.
  • Writes public/r/registry.json or public/rd/registry.json.
  • Runs shadcn build against generated registry JSON.
  • Optionally merges docs registry items into the main registry.
  • Builds registry-docs.json from root content/**.
  • Ships a fumadocs registry item containing mdx-components.tsx, mdx-plate-components.tsx, and docs dependencies.

Decision: keep Plate registry content and delivery, but modernize it around upstream shadcn v4 schema/resolver/base behavior. Do not preserve old shadcn 2.6.3 assumptions.

Keep:

  • Plate registry source files in apps/www/src/registry/**.
  • Plate install namespace/content.
  • Docs registry publishing concept from build-docs-registry.mts.
  • fumadocs registry item idea.
  • registry-shadcn.json lookup only if Plate registry still references upstream @shadcn/*.

Rewrite:

  • build-registry.mts around upstream shadcn v4 conventions.
  • URL dependency resolution to prefer namespace semantics where possible.
  • Server-side registry file reading so client-only registry items do not poison server builds.

Throw:

  • Any Plate-only registry schema idea that upstream shadcn does not understand.
  • Raw URL sprawl when upstream namespace dependencies work.
  • One-off generated index assumptions that force client components into server routes.

Component Preview And Source Display

Upstream

Files:

  • ../ui/apps/v4/components/block-viewer.tsx
  • ../ui/apps/v4/components/component-preview.tsx
  • ../ui/apps/v4/components/component-source.tsx
  • ../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsx

Upstream BlockViewer:

  • Uses style-specific /view/[style]/[name].
  • Has preview/code tabs.
  • Has responsive preview sizes.
  • Has mobile image fallback from /r/styles/new-york-v4/....
  • Supports Open in v0 and block copy tracking.
  • Reads highlighted code already on item.files.

Plate

Files:

  • apps/www/src/components/block-viewer.tsx
  • apps/www/src/components/component-preview.tsx
  • apps/www/src/components/component-installation.tsx
  • apps/www/src/components/component-source.tsx
  • apps/www/src/app/api/registry-source/[name]/route.ts
  • apps/www/src/app/(blocks)/blocks/[name]/page.tsx

Plate BlockViewer:

  • Uses /blocks/[name] or item.meta.src instead of upstream /view.
  • Lazy-fetches highlighted code from /api/registry-source/[name] when switching to code view.
  • Handles Pro examples through item.meta.isPro.
  • Copies npx shadcn@latest add ${siteConfig.registryUrl}${item.name}.
  • Shows dependency install commands inside manual install flow.

Decision: start from upstream preview/view architecture, then reapply Plate registry install behavior and Plate editor demo rendering. The Plate preview code has product value, but upstream's current view/style architecture is cleaner.

Keep:

  • Plate dependency-aware manual install display.
  • Plate registry URL install command.
  • Plate Pro handling if still used.
  • Plate examples/editor preview routing, if the routes stay.

Adopt:

  • Upstream /view concept if style previews matter.
  • Upstream mobile image fallback if Plate screenshots are generated.
  • Upstream source display polish and event tracking if analytics stays.

Throw:

  • A public-shaped /api/registry/[name] lazy code route. If lazy source loading stays, keep it under an internal docs-code route such as /api/registry-source/[name].
  • Stale commented image fallback blocks in Plate block-viewer.tsx.

Search And Navigation

Files:

  • ../ui/apps/v4/app/api/search/route.ts
  • ../ui/apps/v4/components/command-menu.tsx
  • ../ui/apps/v4/lib/page-tree.ts
  • ../ui/apps/v4/lib/source.ts

Upstream search:

  • Uses createFromSource(source) from fumadocs-core/search/server.
  • Uses useDocsSearch({ type: "fetch" }).
  • Searches Fumadocs pages.
  • Also includes nav pages, colors, blocks, component commands, package-manager command copy, search analytics, and delayed groups.

Files:

  • apps/www/src/components/command-menu.tsx
  • apps/www/src/config/docs.ts
  • apps/www/src/components/docs-nav.tsx

Plate search:

  • Client-only cmdk over docsConfig.mainNav and docsConfig.sidebarNav.
  • Searches item titles, labels, keywords, and manually listed headings.
  • Uses invisible Unicode suffixes to work around duplicate command values.
  • Pushes routes directly from nav config.
  • Keeps API group last.

Decision: use upstream Fumadocs search. Plate's current command menu is a hack and should not survive as-is.

Keep:

  • Plate-specific searchable groups: API, plugins, examples, editors, Plate Plus, MCP.
  • Locale-aware route display if CN survives.

Throw:

  • Invisible suffix uniqueness workaround.
  • Client-only nav config search as the main docs search.
  • Manual heading anchors derived from nav config.

Themes, Styling, And Customizer

Upstream styling

Files:

  • ../ui/apps/v4/app/globals.css
  • ../ui/apps/v4/app/legacy-themes.css
  • ../ui/apps/v4/components/active-theme.tsx
  • ../ui/apps/v4/components/theme-customizer.tsx
  • ../ui/apps/v4/lib/themes.ts
  • ../ui/apps/v4/registry/styles/style-*.css
  • ../ui/apps/v4/registry/themes.ts

Upstream has a current shadcn v4 theme/style system:

  • Imports shadcn/tailwind.css.
  • Imports generated style CSS files like style-vega, style-nova, style-lyra, style-maia, style-mira, style-luma, style-sera.
  • Uses ActiveThemeProvider to apply theme-${activeTheme} and theme-scaled.
  • Has create/customizer flow tied to presets, base colors, radius, fonts, icon libraries, and v0/project generation.

Plate styling

Files:

  • apps/www/src/app/globals.css
  • apps/www/src/app/themes.css
  • apps/www/src/lib/themes.ts
  • apps/www/src/components/theme-customizer.tsx
  • apps/www/src/components/customizer-drawer.tsx
  • apps/www/src/components/themes-button.tsx
  • apps/www/src/components/themes-selector.tsx
  • apps/www/src/components/themes-styles.tsx
  • apps/www/src/hooks/use-themes-config.ts

Plate custom themes include named palettes like Ayu, Catppuccin, Dune, Everforest, GitHub, Horizon, Linear, One Dark Pro, plus many custom CSS theme/radius/font variants.

Plate CSS has explicit cleanup comments:

  • Custom scrollbar styling (remove after sync).
  • Custom prose styling (remove after sync).
  • MDX (remove after sync).

Decision: throw Plate themes/customizer. Keep only Plate brand tokens that are actually used outside theme browsing.

Throw:

  • apps/www/src/lib/themes.ts.
  • apps/www/src/app/themes.css.
  • customizer-drawer.tsx.
  • Plate theme selector/customizer components.
  • Old prose/scrollbar/code CSS marked for sync removal.

Adopt:

  • Upstream shadcn v4 style/theme system.
  • Upstream ActiveThemeProvider.
  • Upstream create/customizer flow only if Plate wants a real install preset builder.

Providers And Runtime Boundaries

Upstream

Files:

  • ../ui/apps/v4/app/layout.tsx
  • ../ui/apps/v4/components/theme-provider.tsx
  • ../ui/apps/v4/components/active-theme.tsx

Upstream providers:

  • NuqsAdapter.
  • LayoutProvider.
  • ActiveThemeProvider.
  • ThemeProvider.
  • Base and radix tooltip providers.
  • Toaster.
  • Analytics.
  • TailwindIndicator.
  • LocalStorage script for theme/layout classes.
  • Theme shortcut toggles dark/light with d.

Plate

Files:

  • apps/www/src/app/layout.tsx
  • apps/www/src/components/context/providers.tsx
  • apps/www/src/components/context/theme-provider.tsx

Plate providers:

  • Jotai provider.
  • Next themes provider, defaulting to light.
  • Cookie sync for theme.
  • React DnD provider with HTML5Backend.
  • Agentation in dev.
  • GA.
  • Toaster.
  • TailwindIndicator.

Decision: start from upstream providers, then add Plate runtime providers only where current features require them.

Keep:

  • DndProvider if editor demos are still rendered in the docs app.
  • Jotai if any retained MDX/editor component uses atoms.
  • Theme cookie sync only if server behavior depends on it.
  • Agentation only if this repo still wants local visual feedback in dev.

Adopt:

  • Upstream ActiveThemeProvider.
  • Upstream tooltip provider stack.
  • Upstream theme shortcut unless it conflicts with editor keyboard shortcuts.

Known trap:

  • docs/solutions/developer-experience/2026-03-28-next-prerendered-client-editors-need-dnd-hooks-to-noop-on-the-server.md says app-level DnD providers are not enough. Browser-only DnD hooks must no-op during prerender. Do not "fix" docs restart DnD crashes by slapping ssr: false everywhere.

Next Config, SSR, And Build Behavior

Upstream

File: ../ui/apps/v4/next.config.mjs

Upstream config:

  • createMDX({}) wrapper.
  • typescript.ignoreBuildErrors = true.
  • Output tracing includes ./registry/**/* and ./styles/**/*.
  • Turbopack root is repo root.
  • Redirects shadcn docs legacy paths.
  • Rewrites /docs/:path*.md to /llm/:path*.
  • Rewrites /init.md to /init/md.
  • Remote image hosts include GitHub, Unsplash, Vercel avatar.

Plate

File: apps/www/next.config.ts

Plate config:

  • Builds workspace source aliases dynamically in dev.
  • externalDir only in dev.
  • reactCompiler: !isDev.
  • staticPageGenerationTimeout: 1200.
  • transpilePackages: ['ts-morph'].
  • Output tracing includes registry, public registry, and Tailwind assets for docs/blocks routes.
  • Redirects /r/:path and /rd/:path to JSON.
  • Redirects old ?locale=cn URLs to /cn.

Decision: merge the configs by intent, not by text.

Keep:

  • Dynamic workspace source aliases for Plate packages.
  • Registry/public output tracing for docs pages that render registry files.
  • /r and /rd JSON redirects if public registry URLs still rely on them.
  • Static generation timeout if Plate docs still generate a lot of registry/API pages.

Adopt:

  • Fumadocs createMDX.
  • Upstream /docs/*.md LLM rewrite.
  • Upstream init/create rewrites if create/init routes are kept.

Throw:

  • Contentlayer prebuild assumptions.
  • Old commented webpack fallbacks in apps/www/next.config.ts.

Known trap:

  • docs/solutions/developer-experience/2026-03-12-typescript-workspace-subpath-aliases-in-apps-www.md explains why workspace source aliases matter. Do not simplify them into broad wildcard aliases and call it done. That caused mixed source/dist TypeScript nonsense.

TypeScript And Tests

Files:

  • apps/www/tsconfig.json
  • apps/www/tsconfig.package-integration.json
  • ../ui/apps/v4/tsconfig.json
  • apps/www/src/__tests__/package-integration/**
  • apps/www/src/registry/**/*.spec.ts*
  • ../ui/apps/v4/app/(create)/**.test.ts
  • ../ui/apps/v4/registry/config.test.ts

Upstream TS config is simple and app-local:

  • @/* maps to app root.
  • Includes app files, scripts, next.config.mjs.
  • Has a react types path.

Plate TS config is a docs app plus package harness:

  • @/* maps to ./src/*.
  • Exact aliases for many @platejs/*/react and package root imports.
  • Broad @platejs/* and @udecode/* source aliases.
  • registry maps to ./public/r/registry.json.
  • registry-shadcn maps to ./registry-shadcn.json.
  • Split tsconfig.package-integration.json checks package integration tests against built package contracts.

Decision: keep Plate split typecheck. It exists because the docs app doubles as package integration proof.

Keep:

  • tsconfig.package-integration.json.
  • Package integration tests if apps/www remains the test harness.
  • Registry component specs.
  • Exact package source aliases.

Adopt:

  • Upstream simpler app tsconfig where possible for docs-only code.

Throw:

  • Any alias that only exists for Contentlayer after Contentlayer is gone.

CN Docs And Localization

Files:

  • content/**/*.cn.mdx
  • apps/www/src/app/cn/**
  • apps/www/src/hooks/useLocale.ts
  • apps/www/src/lib/withLocale.ts
  • apps/www/src/components/languages-dropdown-menu.tsx
  • apps/www/src/components/docs-nav.tsx

Plate has 124 CN MDX files and a duplicate /cn route tree. Upstream has no i18n in this app.

Decision: keep CN. Port it using Fumadocs i18n patterns. Do not preserve the current duplicate route logic unless forced.

Keep:

  • Existing translated content.
  • Language dropdown.
  • Locale-aware nav labels.

Rewrite:

  • /cn/docs/[[...slug]] duplicated page logic.
  • hrefWithLocale and manual route-prefix behavior around the new Fumadocs source tree.

Throw:

  • The old duplicate /cn route plumbing once Fumadocs i18n covers the same behavior.

Upstream

Files:

  • ../ui/apps/v4/app/(app)/(root)/page.tsx
  • ../ui/apps/v4/components/site-header.tsx
  • ../ui/apps/v4/lib/config.ts
  • ../ui/apps/v4/components/main-nav.tsx
  • ../ui/apps/v4/components/mobile-nav.tsx

Upstream header/nav:

  • Uses Fumadocs source.pageTree.
  • Has Docs, Components, Blocks, Charts, Directory, Create.
  • Includes GitHubLink, SiteConfig, ModeSwitcher, create/v0 controls, New button.

Plate

Files:

  • apps/www/src/app/(app)/page.tsx
  • apps/www/src/components/site-header.tsx
  • apps/www/src/config/site.ts
  • apps/www/src/components/logo.tsx
  • apps/www/src/components/main-nav.tsx
  • apps/www/src/components/mobile-nav.tsx
  • apps/www/src/components/mcp-dialog.tsx
  • apps/www/src/components/languages-dropdown-menu.tsx

Plate header/nav:

  • Plate brand.
  • Docs.
  • Editors.
  • GitHub.
  • Discord.
  • Language dropdown.
  • Mode switcher.
  • Setup MCP dialog.
  • Plate Plus links.

Decision: keep Plate branding and product links, but use upstream Fumadocs-aware nav infrastructure where possible.

Keep:

  • Plate logo/name/site config.
  • Docs and Editors nav.
  • GitHub/Discord links.
  • MCP dialog if it is still a real onboarding path.
  • Plate Plus link if it remains commercial surface.

Throw:

  • Plate theme button/customizer on the homepage.
  • Potion/pro iframe homepage pieces unless they are still part of current product direction.

LLM Routes And Copy Actions

Upstream files:

  • ../ui/apps/v4/app/(app)/llm/[[...slug]]/route.ts
  • ../ui/apps/v4/components/docs-copy-page.tsx
  • ../ui/apps/v4/lib/llm.ts

Plate files:

  • apps/www/src/components/llm-copy-button.tsx
  • apps/www/src/components/view-options.tsx
  • apps/www/src/lib/llm-context.ts

Upstream serves .md routes through Fumadocs and page.data.getText("raw"). Plate exposes copy/view actions on docs pages, but the restart should not preserve that duplicate UI by default.

Decision: adopt upstream .md route and copy-page model. Reapply Plate-specific LLM context only if the upstream route cannot cover a real Plate agent/docs workflow.

Keep:

  • Plate LLM context helpers only if they add context upstream cannot derive from Fumadocs raw text.

Adopt:

  • Upstream /docs/:path*.md rewrite.
  • Upstream LLM route structure.

Generated/Public Artifacts

Plate files:

  • apps/www/public/r/**
  • apps/www/public/rd/**
  • apps/www/registry-shadcn.json
  • apps/www/src/__registry__/index.tsx

Upstream files:

  • ../ui/apps/v4/public/r/**
  • ../ui/apps/v4/registry/__index__.tsx
  • ../ui/apps/v4/registry/bases/__index__.tsx
  • ../ui/apps/v4/examples/__index__.tsx

Decision: generated artifacts should come from the new source pipeline. Do not hand-edit them. For the restart, preserve source and scripts, not old generated output.

Keep source:

  • apps/www/src/registry/**.
  • apps/www/scripts/build-registry.mts only as input to rewrite.
  • apps/www/scripts/build-docs-registry.mts only as input to rewrite.

Regenerate:

  • public/r/**.
  • public/rd/**.
  • src/__registry__/index.tsx.

Known Local Traps From Prior Solution Notes

Read these before phase two implementation:

  • docs/solutions/developer-experience/2026-03-12-typescript-workspace-subpath-aliases-in-apps-www.md
    • Exact package source aliases and split typecheck prevent source/dist type conflicts.
  • docs/solutions/developer-experience/2026-04-06-next-turbopack-needs-client-boundaries-at-react-package-entrypoints.md
    • Server routes that import generated registry indexes can accidentally pull client-only registry items into the server graph.
  • docs/solutions/developer-experience/2026-04-06-registry-helper-refactors-must-update-template-registry-dependencies.md
    • Generated consumers depend on registry metadata, not whatever files exist in apps/www/src.
  • docs/solutions/developer-experience/2026-04-27-mdx-generated-markers-must-use-jsx-comments.md
    • Generated MDX markers must use JSX comments, not HTML comments.
  • docs/solutions/developer-experience/2026-03-28-next-prerendered-client-editors-need-dnd-hooks-to-noop-on-the-server.md
    • DnD failures during prerender are package runtime issues, not automatically missing provider bugs.

Keep, Throw, Adopt Matrix

ItemFilesVerdictPhase Two Action
Fumadocs engine../ui/apps/v4/source.config.ts, ../ui/apps/v4/lib/source.tsAdoptedAlready wired in apps/www/source.config.ts and apps/www/src/lib/source.ts; preserve it.
Contentlayer engineformer apps/www/contentlayer.config.js, next-contentlayer2 usageThrownAlready removed; do not recreate compatibility layers around it.
Plate docs contentcontent/docs/**KeepMoved under the upstream-style Fumadocs source root.
Fumadocs meta../ui/apps/v4/content/docs/**/meta.jsonAdoptedcontent/docs/meta.json is committed and owns the Plate page tree plus _plate overlays.
Manual docs navformer apps/www/src/config/docs*.tsThrownDeleted after metadata covered pages, labels, CN titles, registry/app-only links, sections, and category groups.
Plate API MDX componentsapps/www/src/components/api-list.tsx, apps/www/src/registry/blocks/fumadocs/*KeepPort into Fumadocs MDX layer.
Plate MDX Contentlayer wrapperapps/www/src/components/mdx-components.tsxRewritten partlyuseMDXComponent is gone; keep auditing component boundaries against Fumadocs/server rendering.
Registry-derived docs pagesapps/www/src/app/(app)/docs/[[...slug]]/page.tsxKept partlyFumadocs fallback is wired; next pass should simplify metadata fallbacks and align with upstream static highlighted-source flow.
Plate DocContent UXapps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsxKeep selectivelyPort related docs, Plus CTA, and any retained copy UX onto upstream page/tree assumptions.
Plate DocsNavapps/www/src/components/docs-nav.tsxKeep UX, rewrite codeKeep accordion/grouped sidebar behavior for Plate's large docs tree, but rebuild it on Fumadocs page data and upstream sidebar primitives.
Plate command menuapps/www/src/components/command-menu.tsxThrow/rewriteReplace with upstream Fumadocs search plus Plate groups.
Invisible command suffix hackapps/www/src/components/command-menu.tsxThrowDo not port.
Upstream search route../ui/apps/v4/app/api/search/route.tsAdoptUse Fumadocs search API.
Plate registry contentapps/www/src/registry/**KeepUpgrade to shadcn v4 contract.
Plate registry buildapps/www/scripts/build-registry.mtsRewriteKeep Plate content rules, adopt upstream v4 registry model.
Plate docs registry buildapps/www/scripts/build-docs-registry.mtsKeep conceptGenerate Fumadocs-ready docs registry.
Upstream registry v4 pipeline../ui/apps/v4/scripts/build-registry.mtsAdopt patternsUse schema/resolver/base/style behavior as source of truth.
Lazy registry source routeapps/www/src/app/api/registry-source/[name]/route.tsKeep internalKeep only for code-view bandwidth. Do not treat it as a public registry API.
Plate component install UIapps/www/src/components/component-installation.tsxKeepReapply for Plate registry items.
Plate previewsapps/www/src/components/component-preview.tsx, block-viewer.tsxKeep selectivelyCombine with upstream /view model.
Upstream /view route../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsxAdopt if style previews stayPrefer over Plate-only block preview route.
Plate editor demosapps/www/src/registry/examples/**, apps/www/src/app/(app)/editors/**KeepThese are Plate docs product surface.
Plate theme libraryapps/www/src/lib/themes.ts, apps/www/src/app/themes.cssThrowUse upstream shadcn theme/style system.
Plate customizer drawerapps/www/src/components/customizer-drawer.tsx, theme selectorsThrowDead weight for restart.
Upstream create/customizer../ui/apps/v4/app/(app)/create/**Adopt if wantedUse for preset/style generation, not Plate old theme UI.
Plate providersapps/www/src/components/context/providers.tsxKeep selectivelyAdd DnD/Jotai only for retained editor surfaces.
Upstream providers../ui/apps/v4/app/layout.tsx, components/theme-provider.tsx, active-theme.tsxAdoptUse as base shell.
Workspace aliasesapps/www/next.config.ts, apps/www/tsconfig.jsonKeepRequired for local package dev/typecheck sanity.
Split typecheckapps/www/tsconfig.package-integration.jsonKeepRequired if app remains package harness.
CN docscontent/**/*.cn.mdx, src/app/cn/**KeepKeep Chinese docs; rewrite routing with Fumadocs/i18n instead of duplicating the old route logic.
MCP dialogapps/www/src/components/mcp-dialog.tsxKeepKeep MCP install/docs/header flow.
Plate Plus linksOpenInPlus, ComponentPreviewPro, registry-pro.tsKeepKeep public Plus/Pro docs hooks.
Dev routesapps/www/src/app/dev/**Throw from public docs baseMove to internal/debug app if still useful.
Package integration testsapps/www/src/__tests__/package-integration/**KeepDo not lose behavioral coverage during app restart.

Proposed Final Decision Table

This is the recommended default for confirmation. "Discard upstream" means do not carry that shadcn product feature into Plate's public docs app, even if the implementation is good upstream code.

AreaKeep From Upstream ShadcnDiscard From Upstream ShadcnKeep From Custom PlateDiscard From Custom PlateSuggested Default
Base app foundationapps/v4 app-router structure, Fumadocs-first docs shell, modern shadcn v4 app patternsUpstream brand/product copyPlate brand, siteConfig, Plate nav labelsCurrent app shell if it fights FumadocsStart from upstream, rebrand to Plate
Docs enginefumadocs-mdx, fumadocs-ui, source.config.ts, lib/source.ts, createMDX Next wrapperNonePlate docs content and custom MDX vocabularyContentlayer runtime and next-contentlayer2Engine is adopted; keep it hard-cut from Contentlayer
Content sourceFumadocs content/docs/** layout and meta.json navigation modelUpstream shadcn docs content as public Plate docsRoot content/** Plate docs, API docs, examples, guides, plugins, install docsContent path grouping only if it blocks FumadocsAdd explicit Fumadocs metadata; move content only if root layout blocks page-tree authority
Public docs navigationFumadocs page tree, upstream DocsSidebar primitives, mobile nav modelUpstream nav items for Components, Blocks, Charts, Directory, Create unless Plate wants those pagesPlate nav categories: Docs, Editors, API, Plugins, Examples, InstallationManual nav as runtime authorityUse Fumadocs tree, generate/port Plate nav structure
Sidebar accordion/filterUpstream shadcn sidebar primitives and Fumadocs page-tree dataUpstream always-expanded flat docs sidebar as the final Plate UXPlate accordion sections, active-section compression, filter input, labels, CN labelsCurrent DocsNav implementation: manual docsConfig authority, timeout scroll, direct DOM query, route-prefix hacksKeep the Plate accordion UX, rewrite it cleanly
SearchFumadocs app/api/search/route.ts, useDocsSearch, upstream command-menu architectureUpstream color/block/create/v0 search groupsPlate API, plugins, examples, editors, MCP groupsInvisible Unicode suffix hack and client-only nav searchAdopt upstream search, inject Plate groups
Docs page renderingStatic Fumadocs page loading, TOC, neighbours, upstream copy-page patternOpenInV0CtaPlate DocContent ideas: related docs and Plus CTAMetadata fallbacks that duplicate Fumadocs, Plate extra LLM copy/view UIContinue rewriting Plate UX around Fumadocs page data
API MDX docsFumadocs MDX compile/runtime pathNoneAPI*, APISubList*, KeyTable, PackageInfo, current API docs contentOld useMDXComponent wrapperKeep strongly
Fumadocs API bridgeUpstream default MDX components and Fumadocs UI primitivesNonesrc/registry/blocks/fumadocs/fumadocs-mdx-components.tsx, mdx-plate-components.tsxPlaceholder behavior that hides needed docs UIUse this as the port starting point
Component docs generated from registryUpstream component-source/preview patternsUpstream shadcn component docs contentPlate ComponentInstallation, registry-derived /docs/components/[name]Contentlayer fallback shapeKeep concept, rewrite implementation
Example docs generated from registryUpstream preview/source UI patternsGeneric shadcn example docs contentPlate registry examples and /docs/examples/[name] pagesOld duplicate preview paths if replaced by upstream /viewKeep
Registry contractshadcn v4 schema, namespace behavior, resolver behavior, local-file install semanticsUpstream registry content that is unrelated to PlatePlate registry item content under src/registry/**, @plate namespacePlate-only schema ideas or installer workaroundsUpstream contract, Plate content
Registry buildUpstream v4 build design, style/base transforms, schema validation, generated output disciplineUpstream styles/components that Plate does not shipPlate docs-registry generation and local public/r/public/rd delivery needsOld shadcn 2.6.3 assumptionsRewrite Plate build from upstream v4 patterns
Generated registry outputUpstream rule: generated output comes from source pipelineHand-copied upstream public outputPlate public/r, public/rd, src/__registry__/index.tsx as regenerated artifactsManual edits to generated outputRegenerate only
Template/local install syncUpstream local-file install semanticsAny upstream template workflow not used by PlatePlate template sync tooling and @plate install entrypointGenerated-template hand editsKeep Plate sync, align with upstream installer
Source code previewUpstream highlighted code/file tree designv0-specific copy/open actionsPlate dependency-aware manual install and registry URL copy commandPublic-shaped lazy registry APIKeep lazy source loading for bandwidth, drop v0
Lazy registry source routeNone unless neededNone/api/registry-source/[name] for code-view payloads/api/registry/[name] as a public-looking registry APIKeep internal docs source endpoint only
Blocks routeUpstream /view/[style]/[name] renderer patternUpstream block gallery categories as public Plate pagesPlate editor block demo routesPlate duplicate route shape if upstream /view can cover itKeep renderer, not gallery
Charts pagesMaybe chart component implementation if registry needs it/charts/** public product pagesNone obviousNoneDiscard from Plate public docs
Colors pagesMaybe color utilities/tokens if style system needs them/colors public product pageNone obviousPlate old color/theme pagesDiscard page
Create/customizer appMaybe low-level preset/style code if registry build needs it/create public page, create app UX, project form, share/history/random UINone from Plate old customizerPlate theme/customizer drawerDiscard for now
v0NoneOpenInV0Cta, V0Button, app/(create)/init/v0, v0 search/copy/project hooksNonePlate commented v0 remnantsDiscard all v0
Init routeUpstream /init and /init.md pattern for shadcn-compatible bootstrapv0 init routePlate registry install URLs and @plate bootstrap needsAny custom installer semantics beyond shadcn-compatible registry bootstrapKeep non-v0 Plate init/bootstrap if it directly serves @plate; no create/v0 side quest
Directory/registry docsUpstream registry contract docs as implementation referencePublic shadcn directory pagesPlate installation/local-docs/MCP docsOld docs that explain obsolete Plate registry behaviorRewrite as Plate registry docs
Theme systemUpstream shadcn v4 CSS tokens, style CSS, ActiveThemeProviderUpstream public theme/create UI if not neededMinimal Plate brand tokensthemes.css, src/lib/themes.ts, custom theme selector/drawerKeep upstream system, discard Plate themes
CSS/prose/code stylesUpstream current globals and code stylingAny shadcn brand-only stylesPlate-specific prose/code tweaks only if API docs require themCSS blocks marked "remove after sync"Start upstream, reapply minimal Plate fixes
HeaderUpstream Fumadocs-aware header structure, mobile nav behaviorCreate/New/v0 controls, shadcn nav labelsPlate logo, GitHub, Discord, Docs, Editors, language switcher, MCP entryOld header comments, customizer buttons, v0/create buttonsKeep Plate brand on upstream structure
HomepageUpstream app structure patterns if usefulUpstream shadcn marketing contentPlate homepage direction: centered product/editor positioningTheme customizer, theme gallery, random Potion/pro iframe clutterKeep a Plate home page, centered and no themes
Public assets and manifestUpstream asset layout if usefulshadcn favicons/brand imagesPlate favicon, manifest, _og.png, Plate metadata assetsStale generated registry screenshots/assets only if regeneratedKeep Plate assets, regenerate generated assets
Redirects and rewritesUpstream .md LLM rewrite, non-v0 init rewrite if keptshadcn legacy redirects unrelated to Plate, v0 rewritesPlate /r and /rd JSON redirects, old ?locale=cn redirectsRedirects for discarded theme/create/v0 pagesKeep Plate registry/CN redirects and upstream LLM rewrite
ProvidersUpstream theme provider, tooltip providers, toaster, layout providersv0/create-only providersPlate DndProvider, Jotai only where retained components need them, Agentation dev only if wantedProviders required only by discarded theme/customizer codeStart upstream, add minimal Plate providers
DnD/editor runtimeNone directlyNoneDnD provider and package-level prerender no-op expectations for editor demosRoute-level SSR hacks as default fixKeep if editor demos stay
Package workspace aliasesNone from upstream simple appUpstream simple-only tsconfig as complete answerPlate next.config.ts source aliases, exact tsconfig paths, split integration typecheckContentlayer aliases after removalKeep Plate alias/typecheck model
Package integration testsNone comparable upstreamNoneapps/www/src/__tests__/package-integration/**, registry specsTests only tied to discarded Contentlayer UIKeep
Upstream create/init testsTests for kept non-v0 init behaviorv0 testsAdd Plate registry/install tests around kept behaviorNoneKeep only matching retained routes
CN docsNoneNoneExisting *.cn.mdx, language dropdown, locale labelsDuplicate /cn route implementation if Fumadocs i18n replaces itKeep CN
Plate Plus / ProNoneNoneComponentPreviewPro, OpenInPlus, registry-pro.ts, public Plus linksPro iframe/homepage clutter if not strategicKeep Plus/Pro hooks
MCP docs/dialogUpstream MCP docs can inform structureUpstream shadcn-specific MCP copyPlate mcp-dialog, installation MCP docs, header entryNone unless duplicated by better docs UIKeep MCP
LLM docsUpstream /docs/*.md rewrite, LLM route, and shadcn copy-page UINonePlate-specific context only if upstream route cannot cover itPlate LLMCopyButton, ViewOptions, duplicate LLM UIUse shadcn LLM/copy model
AnalyticsNone beyond basic app analytics shapev0/create/per-click event trackingPlate GAPer-click event tracking and analytics around discarded surfacesKeep GA only
OG/RSSUpstream OG/RSS structureshadcn-specific contentPlate OG branding and metadataStale duplicate font assets if not neededKeep structure, rebrand
Dev/debug routesNoneNoneMove useful debug tools elsewhere if still neededapps/www/src/app/dev/** in public docs appDiscard from restart
Slate-to-HTML special pageNoneNonedocs/examples/slate-to-html, blocks/slate-to-html, Tailwind trace includeGeneric preview path for this page, because RSC cannot be previewed normallyKeep special route/page
Release docsFumadocs content patternsshadcn changelog contentPlate content/releases/index.mdx, ReleaseIndex if release docs stayContentlayer-only release generation assumptionsKeep content, port renderer
DependenciesCurrent upstream Fumadocs/shadcn v4 depsv0-only deps if anyPlate editor/runtime deps required by retained demoscontentlayer2, next-contentlayer2, old theme-only depsKeep upgrading and pruning
Verification modelUpstream app tests for retained upstream routesTests for discarded routesPlate package integration and registry validationBrowser checks for discarded theme/create/v0 pathsVerify retained surfaces only
  1. Treat the Fumadocs source cutover as complete; do not redo the Contentlayer removal.
  2. Create Fumadocs metadata from docsConfig and current content grouping, then move sidebar/pager toward source.pageTree.
  3. Replace command-menu search with upstream Fumadocs search plus Plate groups.
  4. Start the app-shell restart from ../ui/apps/v4, bringing over Plate siteConfig, logo, product nav labels, and minimal providers.
  5. Confirm whether root content/** remains acceptable. Move Plate content into content/docs/** only if that is needed for clean Fumadocs metadata and page-tree authority.
  6. Continue porting Plate API MDX components using apps/www/src/registry/blocks/fumadocs/* as the starting point.
  7. Keep and simplify registry-derived docs pages for components/examples around Fumadocs page data.
  8. Port Plate registry content and rewrite build scripts against upstream shadcn v4 registry behavior.
  9. Reapply editor demos and preview/source display.
  10. Reapply confirmed product surfaces: CN docs, Plate Plus/Pro hooks, MCP docs/dialog, GA-only analytics, centered Plate homepage, Slate-to-HTML special route, and non-v0 @plate init/bootstrap if useful.
  11. Preserve package integration tests and workspace alias/typecheck model.
  12. Regenerate public registry output.
  13. Run build/typecheck/lint/browser verification.

Confirmed Product Decisions

  • CN docs: keep.
  • Plate Plus / Pro: keep public docs hooks such as ComponentPreviewPro, OpenInPlus, and registry-pro.ts.
  • MCP: keep install/docs/dialog flow.
  • LLM UI: use upstream shadcn .md route and copy-page model; discard Plate's extra LLMCopyButton / ViewOptions unless a later gap appears.
  • Analytics: keep GA only; no per-click event tracking.
  • Homepage: keep a Plate homepage, aligned with the current Plate direction, centered, no theme/customizer surface.
  • Slate-to-HTML: keep the special route/page because it cannot be previewed through the normal registry preview path.
  • Init route: keep a non-v0 Plate init/bootstrap route only if it directly serves @plate registry install; skip create/v0/product-generator behavior.

Hard Calls

  • Custom Plate themes: throw.
  • Contentlayer: throw.
  • Manual nav config as runtime source: throw.
  • Plate API docs components: keep.
  • Plate registry content: keep.
  • Plate registry build scripts: rewrite.
  • Plate editor demos: keep.
  • CN docs: keep.
  • Plate Plus / Pro: keep public docs hooks.
  • MCP: keep.
  • LLM UI: use shadcn model, discard Plate's extra copy/view UI.
  • Analytics: keep GA only.
  • Homepage: keep Plate homepage, centered, no themes.
  • Slate-to-HTML: keep special route/page.
  • Init route: keep non-v0 @plate bootstrap only if directly useful.
  • /api/registry/[name]: throw as a public-shaped route. Keep /api/registry-source/[name] for lazy code-view bandwidth if large registry payloads require it.
  • docsConfig files: use as migration data, not the new architecture.

Verification

Completed evidence pass:

  • Compared package scripts/dependencies for both apps.
  • Compared app route trees.
  • Compared content file layout and counts.
  • Compared MDX engines and component vocabulary.
  • Compared docs page/layout behavior.
  • Compared registry source/build/public output models.
  • Compared search/nav implementations.
  • Compared theme/customizer/provider surfaces.
  • Compared TypeScript configs and test inventories.
  • Checked prior docs/solutions traps relevant to apps/www.

2026-05-24 refresh evidence:

  • Confirmed ../ui/apps/v4 exists and ../shadcn/apps/v4 does not in this workspace.
  • Confirmed upstream still has 206 app files, 227 docs content/meta files, and 1127 registry files.
  • Confirmed Plate currently has 51 app files, 251 MDX content files, 124 Chinese MDX files, 0 committed meta.json files, and 381 registry source files.
  • Confirmed apps/www/package.json uses build:source, postinstall: fumadocs-mdx, and typecheck runs scripts/check-docs-source-parity.mts.
  • Confirmed apps/www/source.config.ts, apps/www/src/lib/source.ts, and apps/www/next.config.ts are the active Fumadocs source path.
  • Confirmed apps/www/src/app/(app)/docs/[[...slug]]/page.tsx uses source.getPage, source.getPages, doc.data.body, and doc.data.getText("raw").
  • Confirmed docs-nav, pager, site-header, and command-menu still import docsConfig.

No runtime verification was needed because this refresh only updated the research artifact. No source app behavior was changed.