diff --git a/ROADMAP.md b/ROADMAP.md index 02770323..f94a75cc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,8 +4,8 @@ > **Now:** `component-sidebar` — finish `.5`/`.6`, then ship `@vllnt/ui@0.4.0`. > **Next:** `agent-ui-cli` (MVP) · `ai-elements-parity`. > **Horizon (gated):** `native-parity` (needs an RN consumer) · the front-studio line (`studio` → `studio-hub` — after the CLI ships + a real need). -> **Visibility track:** SEO/GEO phases — `search-consolidation` → `ai-toolchain-registration` → `visibility-measurement` → `seo-content-engine` → `backlink-authority`. Diagnosis: infra is DONE (`agent-surface`) but GSC shows indexed-yet-buried (141 pages, 2 clicks/90d, 0 AI-query visibility) + a dead `.com` twin outranking the live `.ai`. Full plan: [strategy dossier](https://claude.ai/code/artifact/6e2359db-a626-4226-aa54-a9e53ecfd766). -> **Last updated:** 2026-07-02 +> **Visibility track:** SEO/GEO phases — `search-consolidation` → `ai-toolchain-registration` → `visibility-measurement` → `mdx-content-system` → `seo-content-engine` → `backlink-authority`. Diagnosis: infra is DONE (`agent-surface`) but GSC shows indexed-yet-buried (141 pages, 2 clicks/90d, 0 AI-query visibility) + a dead `.com` twin outranking the live `.ai`. Full plan: [strategy dossier](https://claude.ai/code/artifact/6e2359db-a626-4226-aa54-a9e53ecfd766). +> **Last updated:** 2026-07-13 > **Channels:** `@latest` = `0.3.0` · `@canary` = `0.4.0-canary.` (auto-publishes on every merge to main). Tracking: [milestone 0.3.0](https://github.com/vllnt/ui/milestone/1) Convention: phases are kebab-case outcome slugs, ordered DONE → ACTIVE → PLANNED. Tasks carry stable `.` IDs; functional tasks pair with a `Validate`/`E2E` task. History is never deleted. Shipped 0.3.0 detail lives in `CHANGELOG.md` and the 197 closed issues; phases below summarize it. @@ -247,11 +247,29 @@ Falls out of API-first (`studio.11`) — registration is just another API — pl - [ ] visibility-measurement.3 Add server-log crawler monitoring for GPTBot/ClaudeBot/Claude-Code/PerplexityBot/OAI-SearchBot — proves llms.txt consumption (cmd: `grep -Ec 'GPTBot|ClaudeBot|Claude-Code' access.log`) - [ ] visibility-measurement.4 Script a recurring GSC position/impressions review via `gsc.py` (cmd: `python3 gsc.py query --site sc-domain:ui.vllnt.com --dimensions query --days 28`) +## mdx-content-system [PLANNED] + +**Goal:** Make every content page one `.mdx` file — shared component map, frontmatter-driven JSON-LD, generic shells — so a new page is a file drop, not a route. +**Exit criteria:** A new page ships by adding one `content/pages///en.mdx` — no TSX, no `staticRoutes()` edit; the body may embed `` / `` from a shared map; JSON-LD (FAQPage/TechArticle) is emitted by the shell from frontmatter, never the body; the page is sitemapped automatically; adding `fr.mdx` localizes it with zero code change. +**Verify:** a maintainer drops `content/pages/guides/foo/en.mdx` carrying a `` + `faq:` frontmatter → `/guides/foo` renders the grid, Rich Results shows FAQPage, `/sitemap.xml` lists it, and adding `fr.mdx` makes `/fr/guides/foo` French. Personas: maintainer authoring content (no TSX); AI answer engine extracting the FAQ; translator adding a locale. (needs: search-consolidation.4 for the LD helpers) + +Infra already exists and is under-used: `MDXContent` (`packages/ui/src/components/mdx-content/mdx-content.tsx`) accepts a `components` map, defaults `enableMDX = true`, auto-detects JSX via `/<[A-Z]/` after stripping fenced blocks, falls back to `ReactMarkdown` + `remarkGfm` (GFM tables), and `removeImportStatements` drops import lines. `getPageContent` already resolves `/.mdx` → default locale → flat file, so i18n is opt-in per page. Today every caller passes the **empty** default map — that is the gap this phase closes. + +- [ ] mdx-content-system.1 Shared MDX component map `apps/registry/lib/mdx-components.tsx` (`ComponentGrid`, `CompareTable`, `Faq`, `InstallCommand`, `Preview`), passed as `` from every content shell (cmd: `grep -rc 'components={mdxComponents}' apps/registry/app/\[locale\]` → ≥4) +- [ ] mdx-content-system.2 Extend `pageFrontmatterSchema` (`apps/registry/lib/schemas.ts`) with `faq[]`, `componentSlugs[]`, `updated`, `type: +guide|vs|react`; shells emit FAQPage/TechArticle LD from frontmatter via `lib/jsonld.ts` (test: `pnpm test lib/schemas.test.ts`) +- [ ] mdx-content-system.3 Generic MDX shells `/guides/[slug]`, `/vs/[slug]`, `/react/[slug]` reading `getPageContent()` — a new page is one `.mdx`, zero TSX → docs/specs/mdx-content-system.md +- [ ] mdx-content-system.4 Sitemap enumerates MDX slugs by globbing `content/pages/**` instead of hand-listed `staticRoutes()` entries (cmd: `curl -s https://ui.vllnt.com/sitemap.xml | grep -c /guides/`) +- [ ] mdx-content-system.5 Author guard for the `evaluate()` hazard — a page containing JSX must not use inline `` `` `` code-spans (MDX 3 parses them as JSX; only fenced blocks are stripped before detection) (test: `pnpm test content-mdx-brackets.test.ts`) +- [ ] mdx-content-system.6 Migrate the 3 shipped TSX `/vs` pages (shadcn, vercel-ai-sdk, assistant-ui) onto the `/vs/[slug]` MDX shell, URLs unchanged (needs: mdx-content-system.3) (cmd: `curl -s https://ui.vllnt.com/vs/shadcn | grep -c '/en.mdx` with `` + `faq:` renders the grid, emits FAQPage LD, and appears in the sitemap; `fr.mdx` serves `/fr/guides/`; the 3 migrated `/vs` pages still render tables at unchanged URLs (E2E: `pnpm test:e2e mdx-content`) + ## seo-content-engine [PLANNED] **Goal:** Build the content flywheel — an MDX blog plus programmatic integration / alternative / comparison pages that capture long-tail install intent and definitional AI-wedge queries. **Exit criteria:** `/blog` + `/blog/[slug]` render MDX posts with BlogPosting JSON-LD, Shiki highlighting, per-post OG + RSS; `/integrations/{tool}` + `/alternatives/{competitor}` pages ship and are in the sitemap; 3 flagship guides live; each `/components/[slug]` has unique copy + live demo + install command. -**Verify:** a dev searching "how to build a chat ui with the vercel ai sdk" finds a VLLNT guide; `/alternatives/assistant-ui` renders a comparison table; a blog post shows correct BlogPosting rich data. Personas: dev in organic search; dev comparing libraries; AI answer engine extracting a table. (needs: search-consolidation done first) +**Verify:** a dev searching "how to build a chat ui with the vercel ai sdk" finds a VLLNT guide; `/alternatives/assistant-ui` renders a comparison table; a blog post shows correct BlogPosting rich data. Personas: dev in organic search; dev comparing libraries; AI answer engine extracting a table. (needs: search-consolidation done first · mdx-content-system for the MDX shells) + +**SYNC 2026-07-13 — GSC evidence + namespace split** (90d, `sc-domain:ui.vllnt.ai`). **Evidence:** demand is entirely component-level and framework-qualified (`react callout` ~60 impr @pos 80+, `react floating action button` ~40 impr @58–95, `radix {dialog,slider,popover,scroll-area,button}` ~20 impr) — components that mostly *exist* but rank buried, so `.6`'s uniqueness pass outranks new paths for `callout` + `floating-action-button`. The **"AI UI development" head term has zero demand**: the pillar (`.13`) is a recall/GEO bet (compounding, not near-term impressions), justified because AI *component* pages already rank pos 5–7 (`ai-chat-input`, `ai-source-citation`) and the pillar funnels to them + `/families/ai`. **Namespace decision (2026-07-13):** `/vs` = tools + libs (shadcn, radix, mui, vercel-ai-sdk) · `/alternatives` (`.5`) = direct competitors (assistant-ui, copilotkit, ai-elements) — the shipped `/vs/assistant-ui` migrates in `.11` · `/integrations` (`.4`) stays distinct (how-to-use intent, not comparison) · `/guides` = evergreen reference (new namespace, `.13`/`.14`) while `/blog` (`.1`–`.3`, `.7`) stays dated articles. All new content pages are **MDX** on the `mdx-content-system` shells. - [ ] seo-content-engine.1 Add the MDX blog: `content/blog/{slug}/{locale}.mdx` + `lib/blog.ts` (Content Collections `@content-collections/mdx`, Zod frontmatter — NOT Contentlayer; Velite fallback) mirroring `lib/content.ts` (needs: search-consolidation.4) → docs/specs/blog-system.md - [ ] seo-content-engine.2 Routes `/blog` + `/blog/[slug]` with `generateMetadata` + BlogPosting/Breadcrumb JSON-LD + Shiki build-time highlighting + per-post OG via `ImageResponse` (cmd: `curl -s https://ui.vllnt.com/blog/ | grep -c '"@type":"BlogPosting"'`) @@ -261,6 +279,13 @@ Falls out of API-first (`studio.11`) — registration is just another API — pl - [ ] seo-content-engine.6 Per-component uniqueness pass: unique copy + live demo + install command on each `/components/[slug]` → docs/specs/component-page-uniqueness.md - [ ] seo-content-engine.7 Publish 3 flagship guides (best react components for AI agents; assistant-ui vs ai-elements vs vllnt; render tool calls in react) — answer-first, stats + tables, TechArticle LD (cmd: `curl -s https://ui.vllnt.com/blog/best-react-components-for-ai-agents | grep -c '` queries (needs: mdx-content-system.3) (cmd: `curl -sI https://ui.vllnt.com/react/callout | grep -c 200`) +- [ ] seo-content-engine.13 `/guides/ai-ui` pillar MDX — AI-UI-development reference: `` + `faq:` frontmatter, funnels to `/families/ai` + `/build/*` + `/vs/*`, with a Mobile/React-Native coming-soon section (needs: mdx-content-system.3) → docs/specs/ai-ui-pillar.md +- [ ] seo-content-engine.14 `/guides/streaming-ui` + `/guides/design-tokens` evergreen MDX reference pages (needs: mdx-content-system.3) (cmd: `curl -sI https://ui.vllnt.com/guides/design-tokens | grep -c 200`) +- [ ] seo-content-engine.15 Validate seo-content-engine.9–14: E2E — `/vs/radix` + `/vs/mui` render comparison tables; `/vs/assistant-ui` 301s to `/alternatives/assistant-ui`; `/react/callout` returns 200 with unique copy; `/guides/ai-ui` emits FAQPage LD + renders the AI grid + the mobile coming-soon section; all appear in `/sitemap.xml` (E2E: `pnpm test:e2e content-paths`) ## backlink-authority [PLANNED] @@ -290,6 +315,8 @@ Unscheduled — pull into a phase when prioritized. - **agent-ui-cli-v1** — config bundle, `doctor` wrapper, `add`, `ci` reusable workflow (+ `act` for local==CI), `list`/`info`/`why`/`search`, `vllnt.config`, `upgrade`; **drift gates** — `api-extractor` (public-API `.api.md` diff), `dependency-cruiser` (import boundaries across 309 components), `sherif` (dep-version drift); **test** — wrap Storybook 10 `addon-vitest` (interaction + a11y + coverage via Vitest browser mode), don't rebuild; **dual-primitive** — `context`/`check` handle `--base radix|base-ui` (Base UI ascendant, Radix at plateau). - **agent-ui-cli-v2** — `audit` (knip + size-limit + dependency-cruiser graph), baseline gating, i18n lint, client security, `new`/scaffold, `theme new`/`edit`, `remove`/`diff`, `watch`/`report`. (Whole-site `audit --browser` + visual regression are now the **`studio`** phase; the human↔agent review loop is **`review-loop`**. Chrome DevTools MCP + Playwright MCP feed both.) - **docs + search** — `/docs` expansion (#248), Pagefind full-text (#257), Sandpack playground (#256), `/vs` pages (#258), `/templates` (#259), i18n via next-intl (#281). +- **multiselect** — multi-select / token-input component. GSC surfaces demand with **no component today**: "multiselect" / "multiselect ui" / "multiselect 2" / "material design multi select" (~12 impr/90d, pos 73–92, `sc-domain:ui.vllnt.ai`). New registry item (component + story + test + `registry:build`); pull into a `demand-driven-components` phase when prioritized. +- **filter-bar** — faceted filter bar. GSC surfaces demand with **no component today**: "filter bar" / "filter bars" (~5 impr/90d, pos 78–87). New registry item; pairs with the `multiselect` gap above. ---