From d59413a30f14f0fa0503e7ff8d66ec76766f37d9 Mon Sep 17 00:00:00 2001 From: olliethedev <5933733+olliethedev@users.noreply.github.com> Date: Tue, 1 Sep 2026 17:45:19 -0400 Subject: [PATCH] docs: add remaining plugin evaluator guides (#263) --- README.md | 4 +- docs/assets/product-proof/cms-proof.webp | Bin 0 -> 31752 bytes docs/assets/product-proof/comments-proof.webp | Bin 0 -> 23800 bytes docs/assets/product-proof/kanban-proof.webp | Bin 0 -> 25442 bytes docs/assets/product-proof/manifest.json | 57 ++- docs/assets/product-proof/media-proof.webp | Bin 0 -> 20096 bytes .../product-proof/route-docs-proof.webp | Bin 0 -> 35888 bytes docs/content/docs/index.mdx | 2 +- docs/content/docs/plugins/ai-chat.mdx | 14 +- docs/content/docs/plugins/better-auth-ui.mdx | 3 + docs/content/docs/plugins/cms.mdx | 27 +- docs/content/docs/plugins/comments.mdx | 12 +- docs/content/docs/plugins/index.mdx | 65 +-- docs/content/docs/plugins/kanban.mdx | 23 +- docs/content/docs/plugins/media.mdx | 17 +- docs/content/docs/plugins/route-docs.mdx | 21 +- docs/content/docs/plugins/ui-builder.mdx | 34 +- docs/src/components/plugin-evaluator.tsx | 404 ++++++++++++++++-- e2e/product-proof/capture.mjs | 173 ++++++++ e2e/product-proof/dogfood-data.json | 50 +++ packages/cli/plugin-decisions.json | 227 ++++++++++ .../plugin-decision-manifest.test.ts | 8 + .../src/utils/__tests__/plugin-meta.test.ts | 116 ++++- packages/cli/src/utils/constants.ts | 8 + packages/cli/src/utils/plugin-decision.ts | 208 ++++++++- 25 files changed, 1223 insertions(+), 250 deletions(-) create mode 100644 docs/assets/product-proof/cms-proof.webp create mode 100644 docs/assets/product-proof/comments-proof.webp create mode 100644 docs/assets/product-proof/kanban-proof.webp create mode 100644 docs/assets/product-proof/media-proof.webp create mode 100644 docs/assets/product-proof/route-docs-proof.webp diff --git a/README.md b/README.md index a36baf71..ab02207b 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ function createAppClientStack(queryClient: QueryClient, origin: string) { ![The current Blog backend and client registrations point to the real published Blog route they produce.](docs/assets/product-proof/code-to-result.webp) -Blog adds publishing routes, API operations, its data model, hooks, SSR-aware pages, editor UI, SEO metadata, RSS, and sitemap entries. Other plugins have different boundaries: one-sided and companion plugins are labeled instead of being forced into a full-stack claim. +Blog adds publishing routes, API operations, its data model, hooks, SSR-aware pages, editor UI, published-page metadata, and sitemap entries. Other plugins have different boundaries: one-sided and companion plugins are labeled instead of being forced into a full-stack claim. ## Released capabilities @@ -121,7 +121,7 @@ Every capability below is installable from the released CLI. Follow its document | Capability | Topology | Outcome | | --- | --- | --- | -| [Blog](https://www.better-stack.ai/docs/plugins/blog) | Full-stack | Publishing workflow, routes, API, data model, editor, SEO, and RSS | +| [Blog](https://www.better-stack.ai/docs/plugins/blog) | Full-stack | Publishing workflow, routes, API, data model, editor, metadata, and sitemap entries | | [AI Chat](https://www.better-stack.ai/docs/plugins/ai-chat) | Full-stack | Streaming conversations, model integration, history, routes, and chat UI | | [CMS](https://www.better-stack.ai/docs/plugins/cms) | Full-stack | Typed content models, APIs, generated forms, and editorial UI | | [Form Builder](https://www.better-stack.ai/docs/plugins/form-builder) | Full-stack | Form authoring, validation, rendering, and submissions | diff --git a/docs/assets/product-proof/cms-proof.webp b/docs/assets/product-proof/cms-proof.webp new file mode 100644 index 0000000000000000000000000000000000000000..601ae9ed07f4e4637295ca58aedf6c583d0abaf7 GIT binary patch literal 31752 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%0DdtS{|TbnaY$*#{2}ky@{!2d&T-@xsj8<7 z&VJ2-5DWiqr+#SVgJ7i$5I#@^?A;=civvGa>5{7)?d$00|=9_CwSOXR~wCe@e=I?gtg3^a79 z_lb<(KrHai|44SLiTQAFQ~M1XfYFyhC2(<3Mr!ybZ()f!)< z+#HHEuN`sc@%)+bAk*5GPg$=&%g0dtwAi6+*nUizo-QUZF47Af79u*HO*pFT9t5H3 zII@9YX3zAWm|jTDon?!0Lj@XDjeDrWESn5Z1xah)N87$Eb@OUN=|C)A2g41`+voiZ zg}C{aNWYdes5tv85_Wz@cZOCxr9gXJw%1wpJ4fovgZ|rKi6rO5r&a8p@l?Z!lVa(A z9Ho3(AR1$ous^495^z&y1B?{KS6_zK5!lyvDjTN)*3C56uf;96p6o&$5t&h!yrpI8 zq`ez~lf7a|XPLs%bds0&HSxAdzcYvvSL|C$td3I^GC~g%Z2*F5$oyQYfrk-Od<7xj zE=wW~t3S4knx2uaPv_66k&_dDhCxT$DHO7rBm0Iwl%(*H>Hr(4wGCdfsByvv`TjCs zo-5G;A=RE)HhJ%C2r~@8E0<&wWO>`tV9@HC6i>6ibaw1S8l^E&LX;#?7*YA%q(e4eIa+rt#dR0ihq{A$H?uI2KybbufOc%ki%3V7(?;`r6v zY0Ht^ZfU8)frdfSL{#3eF2a|t4SsLO?UA(mej0&lZxgiK#mu+Oi1HoA@!=;8E|gD~ zj$+S9dzKH3El2OLfVSs@&gq&~SApIAFWJi!sR7h`$kMn|LhXz61Ds{LKk2%P1@s@1 zbf;VkSn~tYC!y;<-*psk6Nbkj?K*3_>{Y~mcY?aR*mwx{QZ~yW`jDW&KmdOM0t84< zpbC8gJaYJZffSfTEi;bU777cWN*IZ}*@r=hiTpplbM`%}^G569dyr8Q)0%Wj>lH*# zui+%XgzoX7CO1%EyUH&v`~O*T+~f#3RvrE^tN}?@SjW>3f5mW5C8rBTV;a!?*pJNR zMI!`SqmI7qlf8PVyXI7ClPrh;E6bjJHlR{4KQu6Nxwdfat?a0WPC<<()Ekb8ThV)* zK`hCF%;n!(S93j!6^S$)C0T90NS~TEGc4}shF6x=voNUVnvXrkObu0z?nwu7f$G?oxy4=JXhJAE$cj5I` znpdL`?FvPOn}W5fpxFQ3>i%J}^EKrwbivbnaV(UPW4SHCLn68S?W?P5N|ySDH*EZO zj+bhnh-SqH`#AlAOngCABqp91*#q9ye4SGw4bSuD&vE9bL`;fGFrn;Al|Uj-sNLJ< zn$TBB9>j}iIL5?#X5fOpP!*eX|F=r4hbFZZ_9+++Z@~lmY5fn&JIss|cngS3zho>U z2?rr^jDc0CMOh07Ex<--QlmKCgY$mHn>MO`n}}nk`{+p0A+)te&f(P4Yr4bpvM*O! zjgLvO?Bh=a_R#Ms+;$Ji+_(t!vRlkk2lg4!1CHQ>9gWCAre$@aJ;)8*F#!pucGUr( z0Dp`aoTr$e@k?CANV$;vp&L>)tcu%a{uyZh=N)coI&K@DGqy}eLb<;4U;4JuOagdWP$VYz@#hRW?Si!bdR zDGL$=pYn|W$-P@-lL752!H6ZCkj;aacV}M{i-IgV*vx#RFuL;uIW3lP!H>&j)9BUSRRtsYBg(M5K$VPSx=Yftrc7|;{?pKAuW XF8~0b+WY@Ux{mm-TN(Uc1pxdX=_d;d literal 0 HcmV?d00001 diff --git a/docs/assets/product-proof/comments-proof.webp b/docs/assets/product-proof/comments-proof.webp new file mode 100644 index 0000000000000000000000000000000000000000..2810fc5445d89cd74540575de2c52c3fcf470614 GIT binary patch literal 23800 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 z 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%0D*A(m;@XyMXc;aAej?eYuLN=rPw zU^d*(RAY3RxXYl_qvGwLPfzB9H^&ulttsFJ-&ixs;jb8DPO5uaHq;1f;LD=k2e100 zuG`|p%HG)6{jQ;kdJ_*G3G$*JgqgG9toXaciQ%mW*hrKwYZr3JUpn@YNt1iY;DxFg za`2-ZvCJe3IQW$Pj=V6YI0M3eRM5$uBLSZ(lH+d}>s5J4F$V#6oJ-&SJaK2*;K_^w|-0Lqm6V z_7oEDsIGBm#`SH-8v|_UaIyuJI&YHmbPLTmO~B4f;W!R5JQt7>z@ldhmlGmdT;Y=MY)K*P-7e)O5j=25L5a&G%#tNTE{{%@j zIA8LKIX2zAK64qZDIdpV26*7u**%TTRo(p&^GVgWG$CC zR1+*cX{{{Z%4u9)@wNV8L9P%UK8bxzV??MfYMDH*N0$M52C$9N;#+mfR2E8{fKAnW z6U1%~iIRjOL*ki>*W3+7bu3q2WxA9lHLkTsM*uYxzn=K$q!`w9%F4|puc5ijE6RbM zu!oO)=fRu+V@R{_Glz>S*If!jiv_#@<}o7MrtMT(9Cf}#KANI&svt05Z-ZNai{N{Q z(}r&DT?Q$tVaGhMIRBx4?szj)5Mx7KG7pwCj2t^1vQ;XmAWWj z)-F*c?i>G`UR^%-9bd=ObphsO+MXsfuh_AMEtMBvLBgNc{y3CL`mMmaQSYcWVCdh6 z-|ug&=cUm3D15QcYpKaAa?}hC^V^R0nfUpzO;_=Kt_94b+_rAtUVir~IrLvFlOz2D z{_#!S-W-$H>Bxu=T_(-mxOBcjxdd?hNyLs4`~)Qg>NZZ@)3_9ShQX=Rc9~kOcaql# z&c_V}DuoZ6=nYQ|&6liwOWZv(#DX?Jjs`!UZc*oJz%eutQlbsqh65rn%hg(8OUYux zYo?hPy7RUh_b6oB&#KSM%Jf3n&L27scX4c~E$A~F$)7QyMa~dFD(z3x*^Z;NNL9V( zhP%w!hPPVM20N!IM5}*NgCkl%#IrJ-tayVSK`J|63L&8~51{cYluNmYE8fU#FG|B| z8%4n%KNWQN4}A2}H-(Q?9YYw#d3rKNy+e#2UL0Pm`}OR0bTj0*RMMX2ST7)WI7MQk zKoh%t_WG`z`eFRLJ?;+kV`19tn3g#v;-GN1#lAo*_1Ut-|6QG29h~3I(YtMs6?JEr zF*vn{BD@0o==nG2n8Dg8)NhIwev_OcRT z35)-Y77i!m1ZCGf*sXserCF9yW2rwg`yK6o)C6>4GF6casC?)Tm2v zA@<_!Y$3s$v@suhCx<||7QX&pn-Hrop_frrHS6i0NtCbkR=lNJ`dmToE=r!3u z9epR4R%7;QVZOjBL%ndh3CBK`%Mr<-W5~{i(Ul8H^f0nZR=J4xS(5O_m^2idRbH6d zGA4-K)TJH0!smGxQXNl6Q>|>KqOO-4#+VT8wl2DrnY=5C9R;>IY>2@>)aTR^cQ565 z^j{|AAJbF>%LjuiO(~#yTFTlgiN@t_l`6jL+_^7PfEKw1AM+ZGFFlVv^n?|1ac!;6 zFpgp8IdNz^>NJAdhLg09s%wk8gr^)Uo$LiG*zw8u%9qcpTc9CBr47XBUN}zAK5%x8 zXOqx&UJiQZJ)GM z%Z^=S32s4{T<}GDy<6b3T}{u-`J=q)32W~!uSQW}E;jGtc2Wn+ak*w5fsQ--jnhmST{ z1b*lZzqFy8h-$<_`%QvzphUau1lPu3ZasE>4u{RHrKkWS62YU&@wSb{8;Um+ZYbPQ zxTA4K;*G@{iZ>K)DBMxFqj5&!jl~;^HxzCt+)=oraYo{e#T$w@6mBToQMjXVM&gad z8;Rglt|d1o_L-phK1NC5Mg_lEr1CJK#LjEC-4Z$@qGZJZoKOG&035VO7+`<^2s49@ YVt@by8NtUuAOHdk;NzH}000000O&{%n*aa+ literal 0 HcmV?d00001 diff --git a/docs/assets/product-proof/route-docs-proof.webp b/docs/assets/product-proof/route-docs-proof.webp new file mode 100644 index 0000000000000000000000000000000000000000..92ffaa2a142914aed96ea671fea4b896bd3e800f GIT binary patch literal 35888 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 G0002jaAsuy literal 0 HcmV?d00001 diff --git a/docs/content/docs/index.mdx b/docs/content/docs/index.mdx index 8366bdc6..866eeed9 100644 --- a/docs/content/docs/index.mdx +++ b/docs/content/docs/index.mdx @@ -66,7 +66,7 @@ runs. | Capability | Topology | What it adds | | --- | --- | --- | -| [Blog](/plugins/blog) | Full-stack | Publishing workflow, routes, API, data model, editor, SEO, and RSS | +| [Blog](/plugins/blog) | Full-stack | Publishing workflow, routes, API, data model, editor, metadata, and sitemap entries | | [AI Chat](/plugins/ai-chat) | Full-stack | Streaming conversations, model integration, history, routes, and UI | | [CMS](/plugins/cms) | Full-stack | Typed content models, APIs, generated forms, and editorial UI | | [Form Builder](/plugins/form-builder) | Full-stack | Form authoring, validation, rendering, and submissions | diff --git a/docs/content/docs/plugins/ai-chat.mdx b/docs/content/docs/plugins/ai-chat.mdx index e2f9b0de..dd3311f9 100644 --- a/docs/content/docs/plugins/ai-chat.mdx +++ b/docs/content/docs/plugins/ai-chat.mdx @@ -5,19 +5,9 @@ description: AI-powered chat functionality with conversation history, streaming, import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; -import Image from "next/image"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -import aiChatProof from "../../../assets/product-proof/ai-chat-proof.webp"; - -

- -This capture proves the shipped chat shell and prompt boundary. It deliberately does not fabricate a model response. - -[View interactive demo →](https://www.better-stack.ai/playground?plugins=ai-chat&view=preview) + ## Installation diff --git a/docs/content/docs/plugins/better-auth-ui.mdx b/docs/content/docs/plugins/better-auth-ui.mdx index 4b759286..5170996c 100644 --- a/docs/content/docs/plugins/better-auth-ui.mdx +++ b/docs/content/docs/plugins/better-auth-ui.mdx @@ -5,6 +5,9 @@ description: Add optional auth and account pages to an application that already import { Callout } from "fumadocs-ui/components/callout"; import { Tabs, Tab } from "fumadocs-ui/components/tabs"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; + + [`@btst/better-auth-ui`](https://github.com/better-stack-ai/better-auth-ui) is the separately maintained Better Auth UI companion for BTST v3. It adds diff --git a/docs/content/docs/plugins/cms.mdx b/docs/content/docs/plugins/cms.mdx index 835d5eae..79145bd4 100644 --- a/docs/content/docs/plugins/cms.mdx +++ b/docs/content/docs/plugins/cms.mdx @@ -5,32 +5,9 @@ description: Headless CMS with code-defined content types, dynamic forms, and ag import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -import Image from "next/image"; - -The CMS plugin provides a headless content management system where developers define content types as Zod schemas in code. This "agency workflow" approach means: - -- **Developers** define the content model (schemas, validation rules, field descriptions) -- **Clients** manage content items through a friendly admin UI -- **TypeScript** provides end-to-end type safety when schema shapes change - -import cmsDemo from "../../../assets/cms-demo.png"; -import cmsDemo1 from "../../../assets/cms-demo-1.png"; -import cmsDemo2 from "../../../assets/cms-demo-2.png"; - - - -[View interactive demo →](https://www.better-stack.ai/playground?plugins=cms&view=preview) + ## Installation diff --git a/docs/content/docs/plugins/comments.mdx b/docs/content/docs/plugins/comments.mdx index dd5e2d09..af779c4d 100644 --- a/docs/content/docs/plugins/comments.mdx +++ b/docs/content/docs/plugins/comments.mdx @@ -5,17 +5,9 @@ description: Threaded comments with moderation, likes, replies, and embeddable C import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -The Comments plugin adds threaded commenting to any resource in your application — blog posts, Kanban tasks, CMS content, or your own custom pages. Comments are displayed with the embeddable `CommentThread` component and managed via a built-in moderation dashboard. - -**Key Features:** -- **Threaded replies** — Top-level comments and nested replies -- **Like system** — One like per user, optimistic UI updates, denormalized counter -- **Edit support** — Authors can edit their own comments; an "edited" timestamp is shown -- **Moderation dashboard** — Tabbed view (Pending / Approved / Spam) with bulk actions -- **Server-side user resolution** — `resolveUser` hook to embed author name and avatar in API responses -- **Optimistic updates** — New comments appear instantly with a "Pending approval" badge when `autoApprove: false` -- **Scroll-into-view lazy loading** — `CommentThread` is mounted only when it scrolls into the viewport + ## Installation diff --git a/docs/content/docs/plugins/index.mdx b/docs/content/docs/plugins/index.mdx index 4f08779e..2d974764 100644 --- a/docs/content/docs/plugins/index.mdx +++ b/docs/content/docs/plugins/index.mdx @@ -4,7 +4,7 @@ description: Available plugins and features for BTST --- import { Card, Cards } from "fumadocs-ui/components/card"; -import { Database, Hammer, Bot, Route, Layout, Columns3, MessageSquare, ImageIcon, ShieldCheck } from "lucide-react"; +import { Hammer } from "lucide-react"; import { PluginCatalogCard } from "@/components/plugin-evaluator"; @@ -30,55 +30,20 @@ workflow-heavy feature, and an intentionally one-sided plugin. ## More released plugins +
+ + + + + + + + +
+ +## Build a plugin + - } - description="AI-powered chat with conversation history, streaming, and customizable models." - /> - } - description="Headless CMS with custom content types, Zod schemas, and auto-generated forms." - /> - } - description="Visual drag-and-drop page builder with component registry and public rendering." - /> - } - description="Project management with boards, columns, tasks, drag-and-drop, and priority levels." - /> - } - description="Threaded comments with moderation, likes, replies, and embeddable comment threads." - /> - } - description="Media library with uploads, folders, picker UI, URL registration, and reusable image inputs." - /> - } - description="Auto-generated client route documentation with interactive navigation." - /> - } - description="Optional auth and account routes for applications that already run Better Auth." - /> - - Kanban Plugin Demo - Board View - - - -## Overview - -The Kanban plugin provides a full-featured project management system with: -- **Boards** - Organize different projects or workflows -- **Columns** - Define workflow stages (e.g., To Do, In Progress, Done) -- **Tasks** - Track individual work items with priorities -- **Assignees** - Assign users to tasks with avatar display -- **Drag-and-Drop** - Reorder tasks and columns with smooth animations -- **Priority Levels** - LOW, MEDIUM, HIGH, URGENT with visual badges -- **Organization Support** - Optional scoping by user or organization - -[View interactive demo →](https://www.better-stack.ai/playground?plugins=kanban&view=preview) + ## Installation diff --git a/docs/content/docs/plugins/media.mdx b/docs/content/docs/plugins/media.mdx index 23b507b7..be75a014 100644 --- a/docs/content/docs/plugins/media.mdx +++ b/docs/content/docs/plugins/media.mdx @@ -5,22 +5,9 @@ description: Media library, uploads, folders, picker UI, and reusable image inpu import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; -import Image from "next/image"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -import mediaDemo1 from "../../../assets/media-demo-1.png"; - - - -The Media plugin gives you a built-in media library with folders, uploads, URL-based asset registration, and reusable picker components that can be embedded anywhere in your app. It works well as a standalone `/media` library route and as shared infrastructure for other plugins such as Blog, CMS, and Kanban. + ## Installation diff --git a/docs/content/docs/plugins/route-docs.mdx b/docs/content/docs/plugins/route-docs.mdx index a854cf0e..3d8b5a5f 100644 --- a/docs/content/docs/plugins/route-docs.mdx +++ b/docs/content/docs/plugins/route-docs.mdx @@ -5,26 +5,9 @@ description: Auto-generated client route documentation with interactive navigati import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; -import Image from "next/image"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -import routeDocsDemo from "../../../assets/route-docs-demo.png"; - - - -The Route Docs plugin automatically generates documentation for all your client-side routes. It provides an interactive reference page that displays route paths, parameters, sitemap entries, and navigation tools. - -## Features - -- **Automatic Route Discovery** - Traverses all registered client plugins and extracts route metadata -- **Interactive Navigation** - Click any route to scroll to its details, or use the sidebar -- **Parameter Documentation** - Shows path and query parameters with types and descriptions -- **Sitemap Integration** - Displays sitemap entries for each route -- **Live Route Testing** - Fill in parameters and navigate directly to routes -- **Responsive Design** - Mobile-friendly with collapsible sidebar + ## Installation diff --git a/docs/content/docs/plugins/ui-builder.mdx b/docs/content/docs/plugins/ui-builder.mdx index 7e8bed80..90fb702d 100644 --- a/docs/content/docs/plugins/ui-builder.mdx +++ b/docs/content/docs/plugins/ui-builder.mdx @@ -5,39 +5,9 @@ description: Visual drag-and-drop page builder with component registry, variable import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Callout } from "fumadocs-ui/components/callout"; -import { BookOpen } from "lucide-react"; -import Image from "next/image"; +import { PluginEvaluatorHeader } from "@/components/plugin-evaluator"; -import uiBuilderProof from "../../../assets/product-proof/ui-builder-proof.webp"; - - - -The UI Builder plugin provides a visual drag-and-drop page creation interface where administrators can create pages using pre-defined components. Pages are stored as JSON layers in the CMS and can be rendered on public routes. - - - - -For comprehensive documentation including interactive demos, block templates, and advanced customization options, visit [uibuilder.app](https://www.uibuilder.app/). - - -**Key Features:** -- **Visual Page Builder** - Drag-and-drop interface for creating pages with components -- **Component Registry** - Pre-built shadcn/ui components + custom component support -- **Variables** - Define page variables for dynamic content -- **CMS Integration** - Leverages the CMS plugin for data persistence -- **Public Page Rendering** - Render pages by slug with the `PageRenderer` component -- **Shared Authorization** - One CMS rule set gates browser UI and backend operations - -[View interactive demo →](https://www.better-stack.ai/playground?plugins=ui-builder&view=preview) + ## Installation diff --git a/docs/src/components/plugin-evaluator.tsx b/docs/src/components/plugin-evaluator.tsx index a74444e5..8dceec3e 100644 --- a/docs/src/components/plugin-evaluator.tsx +++ b/docs/src/components/plugin-evaluator.tsx @@ -2,17 +2,30 @@ import { ArrowRight, ExternalLink } from "lucide-react"; import Image, { type StaticImageData } from "next/image"; import Link from "next/link"; import type { ReactNode } from "react"; +import aiChatProof from "../../assets/product-proof/ai-chat-proof.webp"; import blogProof from "../../assets/product-proof/blog-proof.webp"; +import cmsProof from "../../assets/product-proof/cms-proof.webp"; +import commentsProof from "../../assets/product-proof/comments-proof.webp"; import formBuilderProof from "../../assets/product-proof/form-builder-proof.webp"; -import productProofManifest from "../../assets/product-proof/manifest.json"; +import kanbanProof from "../../assets/product-proof/kanban-proof.webp"; +import mediaProof from "../../assets/product-proof/media-proof.webp"; import openApiProof from "../../assets/product-proof/openapi-proof.webp"; +import productProofManifest from "../../assets/product-proof/manifest.json"; +import routeDocsProof from "../../assets/product-proof/route-docs-proof.webp"; +import uiBuilderProof from "../../assets/product-proof/ui-builder-proof.webp"; import { PLUGINS } from "@btst/codegen/meta"; -type RepresentativePluginKey = "blog" | "form-builder" | "open-api"; +type EvaluatorPluginKey = (typeof PLUGINS)[number]["key"]; type PluginDecisionMeta = NonNullable< (typeof PLUGINS)[number]["decision"] >; -type DecisionActionTarget = "demo" | "docs" | "installation" | "workflow"; +type DecisionActionTarget = + | "demo" + | "docs" + | "installation" + | "setup" + | "source" + | "workflow"; interface WorkflowStepCopy { label: string; @@ -29,7 +42,8 @@ interface ResolvedDecisionAction extends DecisionActionCopy { external: boolean; } -interface RepresentativeCopy { +interface EvaluatorCopy { + catalogTitle?: string; outcome: string; audience: string; ownership: string; @@ -38,7 +52,7 @@ interface RepresentativeCopy { actions: readonly [DecisionActionCopy, DecisionActionCopy]; } -const representativeCopy = { +const evaluatorCopy = { blog: { outcome: "Publish and manage a content section inside the React application you already run.", @@ -72,6 +86,74 @@ const representativeCopy = { { label: "Install Blog", target: "installation" }, ], }, + "ai-chat": { + outcome: + "Add a streaming conversation surface while choosing the model, access policy, and operating limits yourself.", + audience: + "React teams that already know which AI SDK model provider they want and need chat history, tools, and product UI inside their app.", + ownership: + "You select and pay the model provider. Authenticated history stays in your database, and ejected chat pages become editable application code while streaming and data behavior remain packaged.", + workflow: [ + { + label: "Choose a model", + detail: + "Pass an AI SDK model and keep its credentials in your server environment.", + }, + { + label: "Set access", + detail: + "Use authenticated persistence with typed rules or choose explicit stateless public mode.", + }, + { + label: "Stream", + detail: + "Run prompts, tools, and optional attachments through the supplied chat route.", + }, + { + label: "Keep context", + detail: + "Store identity-scoped conversations in your database when authenticated mode is enabled.", + }, + ], + catalogAction: { label: "Explore AI Chat", target: "docs" }, + actions: [ + { label: "View chat shell", target: "demo" }, + { label: "Install AI Chat", target: "installation" }, + ], + }, + cms: { + outcome: + "Define structured content in TypeScript and give operators generated forms for managing it.", + audience: + "Teams that want developers to own content models while editors manage records through an in-app admin interface.", + ownership: + "Content models live in your code and records stay in your database. You own public rendering and uploads; the packaged admin pages can be overridden or ejected.", + workflow: [ + { + label: "Model", + detail: "Define each content type as a shared Zod schema in your app.", + }, + { + label: "Generate forms", + detail: + "Turn schema fields and metadata into validated operator-facing forms.", + }, + { + label: "Manage", + detail: "Create and edit typed content records through the admin routes.", + }, + { + label: "Render", + detail: + "Load records with packaged hooks and present them on application-owned routes.", + }, + ], + catalogAction: { label: "Explore CMS", target: "docs" }, + actions: [ + { label: "View CMS workflow", target: "demo" }, + { label: "Install CMS", target: "installation" }, + ], + }, "form-builder": { outcome: "Let operators design forms visually, publish them inside your app, and collect validated submissions.", @@ -105,6 +187,176 @@ const representativeCopy = { { label: "Install Form Builder", target: "installation" }, ], }, + "ui-builder": { + catalogTitle: "UI Builder", + outcome: + "Let operators compose pages visually, store the layout through CMS, and render it on routes you own.", + audience: + "Teams that already use the BTST CMS plugin and want a constrained visual editor over application-approved components.", + ownership: + "The CMS-backed page record stays in your database. You choose the component registry and public route; editor views can be ejected while CMS data behavior remains packaged.", + workflow: [ + { + label: "Add CMS", + detail: + "Use the required CMS plugin; the CLI adds it automatically when selected.", + }, + { + label: "Register components", + detail: + "Define the components and blocks an operator is allowed to place.", + }, + { + label: "Compose", + detail: "Arrange layers, variables, and properties in the visual editor.", + }, + { + label: "Render", + detail: + "Load the CMS record and mount PageRenderer on an application-owned public route.", + }, + ], + catalogAction: { label: "Explore UI Builder", target: "docs" }, + actions: [ + { label: "View builder workflow", target: "demo" }, + { label: "Install UI Builder", target: "installation" }, + ], + }, + kanban: { + outcome: + "Add boards, columns, tasks, priorities, and drag-and-drop workflows inside your product.", + audience: + "Product teams that need an application-native work board and want to connect it to their own users and authorization rules.", + ownership: + "Boards and tasks stay in your database. Your app supplies identity and workflow policy; packaged Kanban pages can be customized or ejected.", + workflow: [ + { + label: "Create boards", + detail: "Use supplied routes and APIs to create a board and its columns.", + }, + { + label: "Add work", + detail: "Create prioritized tasks and connect assignees through your user resolver.", + }, + { + label: "Move", + detail: + "Reorder columns and drag tasks through isolated database transactions.", + }, + { + label: "Enforce policy", + detail: + "Apply app-owned authorization rules and domain hooks to every operation.", + }, + ], + catalogAction: { label: "Explore Kanban", target: "docs" }, + actions: [ + { label: "View Kanban board", target: "demo" }, + { label: "Install Kanban", target: "installation" }, + ], + }, + comments: { + outcome: + "Attach threaded discussion and moderation to a resource your application already owns.", + audience: + "Teams that need comments on posts, tasks, content records, or a custom resource without adopting a hosted discussion service.", + ownership: + "Comments and reactions stay in your database. You define resource identity, access rules, and author resolution; the moderation page can be ejected.", + workflow: [ + { + label: "Name the resource", + detail: + "Mount CommentThread with the resource type and identifier owned by your app.", + }, + { + label: "Resolve identity", + detail: + "Connect request identity, typed authorization rules, and optional author profiles.", + }, + { + label: "Discuss", + detail: "Create replies and reactions through the supplied typed APIs and UI.", + }, + { + label: "Moderate", + detail: + "Review pending, approved, and spam comments on the built-in route.", + }, + ], + catalogAction: { label: "Explore Comments", target: "docs" }, + actions: [ + { label: "Understand the workflow", target: "workflow" }, + { label: "Install Comments", target: "installation" }, + ], + }, + media: { + outcome: + "Upload, organize, register, and reuse media through a library that runs with your storage.", + audience: + "Teams that need a shared media layer for product features while keeping files, metadata, and storage credentials under their control.", + ownership: + "Asset metadata stays in your database and files stay in the storage you configure. You own limits, access policy, and embedding; the library view can be ejected.", + workflow: [ + { + label: "Choose storage", + detail: + "Configure local, S3-compatible, or Vercel Blob storage in your backend.", + }, + { + label: "Upload or register", + detail: + "Send a file through the matching protocol or register an allowed asset URL.", + }, + { + label: "Organize", + detail: "Search assets, maintain folders, and edit metadata in the library.", + }, + { + label: "Reuse", + detail: + "Embed MediaPicker or ImageInputField wherever your application needs an asset.", + }, + ], + catalogAction: { label: "Explore Media", target: "docs" }, + actions: [ + { label: "Understand the workflow", target: "workflow" }, + { label: "Install Media", target: "installation" }, + ], + }, + "route-docs": { + outcome: + "Generate an explorable reference for the client routes already registered in your BTST stack.", + audience: + "Teams that want route paths, parameters, sitemap entries, and navigation context visible inside a development or protected application surface.", + ownership: + "The reference is derived from your registered client stack and served by your app. You control which routes exist, who can see the page, and whether to eject its UI.", + workflow: [ + { + label: "Register routes", + detail: "Compose the client plugins whose route definitions should appear.", + }, + { + label: "Inspect", + detail: + "Read route paths, typed parameters, metadata, and sitemap declarations.", + }, + { + label: "Generate", + detail: + "Render the route inventory with its owning plugin and dynamic context.", + }, + { + label: "Navigate", + detail: + "Supply concrete parameters and open a resolved route in your application.", + }, + ], + catalogAction: { label: "Explore Route Docs", target: "docs" }, + actions: [ + { label: "Understand the output", target: "workflow" }, + { label: "Install Route Docs", target: "installation" }, + ], + }, "open-api": { outcome: "Expose an OpenAPI 3.1 contract for registered BTST routes and, when useful, an interactive API reference.", @@ -137,30 +389,73 @@ const representativeCopy = { { label: "Install OpenAPI", target: "installation" }, ], }, -} as const satisfies Record; + "better-auth-ui": { + catalogTitle: "Better Auth UI", + outcome: + "Add auth and account routes to a BTST client stack that already has a Better Auth backend.", + audience: + "Teams already operating Better Auth that want its auth and account UI composed into the maintained BTST framework paths.", + ownership: + "Your application keeps the Better Auth server, database, providers, secrets, sessions, and deployment. The companion supplies client routes and UI; it does not create or host authentication.", + workflow: [ + { + label: "Operate Better Auth", + detail: + "Keep the existing server endpoint, schema, providers, secrets, and browser client.", + }, + { + label: "Add the companion", + detail: "Register auth and account client plugins in the BTST client stack.", + }, + { + label: "Mount routes", + detail: + "Serve sign-in, recovery, account, security, and settings views under your site path.", + }, + { + label: "Refresh sessions", + detail: + "Use the generated framework-native refresh seam after session changes.", + }, + ], + catalogAction: { label: "Explore Better Auth UI", target: "docs" }, + actions: [ + { label: "View companion source", target: "source" }, + { label: "Install the companion", target: "setup" }, + ], + }, +} as const satisfies Record; -const representativeAssets = { +const evaluatorAssets: Partial< + Record +> = { blog: { file: "blog-proof.webp", image: blogProof }, + "ai-chat": { file: "ai-chat-proof.webp", image: aiChatProof }, + cms: { file: "cms-proof.webp", image: cmsProof }, "form-builder": { file: "form-builder-proof.webp", image: formBuilderProof, }, + "ui-builder": { file: "ui-builder-proof.webp", image: uiBuilderProof }, + kanban: { file: "kanban-proof.webp", image: kanbanProof }, + comments: { file: "comments-proof.webp", image: commentsProof }, + media: { file: "media-proof.webp", image: mediaProof }, + "route-docs": { file: "route-docs-proof.webp", image: routeDocsProof }, "open-api": { file: "openapi-proof.webp", image: openApiProof }, -} as const satisfies Record< - RepresentativePluginKey, - { file: string; image: StaticImageData } ->; +}; -function getRepresentativePlugin(key: RepresentativePluginKey) { +function getEvaluatorPlugin(key: EvaluatorPluginKey) { const plugin = PLUGINS.find((candidate) => candidate.key === key); if (!plugin?.decision) { throw new Error(`Missing evaluator metadata for ${key}`); } - return { plugin, decision: plugin.decision, copy: representativeCopy[key] }; + const copy: EvaluatorCopy = evaluatorCopy[key]; + return { plugin, decision: plugin.decision, copy }; } -function getProofAsset(key: RepresentativePluginKey) { - const asset = representativeAssets[key]; +function getProofAsset(key: EvaluatorPluginKey) { + const asset = evaluatorAssets[key]; + if (!asset) return null; const copy = productProofManifest.assets.find( (candidate) => candidate.file === asset.file, ); @@ -289,7 +584,7 @@ function WorkflowStrip({ } function resolveAction( - key: RepresentativePluginKey, + key: EvaluatorPluginKey, decision: PluginDecisionMeta, action: DecisionActionCopy, ): ResolvedDecisionAction { @@ -303,6 +598,14 @@ function resolveAction( return { ...action, href: decision.docsPath, external: false }; case "installation": return { ...action, href: "#installation", external: false }; + case "setup": + return { + ...action, + href: "#generate-the-minimal-integration", + external: false, + }; + case "source": + return { ...action, href: decision.sourcePath, external: true }; case "workflow": return { ...action, href: `#${key}-workflow`, external: false }; } @@ -311,9 +614,9 @@ function resolveAction( export function PluginEvaluatorHeader({ pluginKey, }: { - pluginKey: RepresentativePluginKey; + pluginKey: EvaluatorPluginKey; }) { - const { decision, copy } = getRepresentativePlugin(pluginKey); + const { decision, copy } = getEvaluatorPlugin(pluginKey); const proof = getProofAsset(pluginKey); const actions = copy.actions.map((action) => resolveAction(pluginKey, decision, action), @@ -324,7 +627,13 @@ export function PluginEvaluatorHeader({ aria-labelledby={`${pluginKey}-evaluator-title`} className="not-prose my-8 overflow-hidden rounded-2xl border border-fd-border bg-fd-background shadow-sm" > -
+

@@ -340,7 +649,7 @@ export function PluginEvaluatorHeader({ {copy.outcome}

- {actions.map((action, index) => ( + {actions.map((action, index) => (
-
- {proof.alt} -
- {proof.caption} -
-
+ {proof ? ( +
+ {proof.alt} +
+ {proof.caption} +
+
+ ) : null}
@@ -404,10 +715,7 @@ export function PluginEvaluatorHeader({
- + ); } @@ -415,9 +723,9 @@ export function PluginEvaluatorHeader({ export function PluginCatalogCard({ pluginKey, }: { - pluginKey: RepresentativePluginKey; + pluginKey: EvaluatorPluginKey; }) { - const { plugin, decision, copy } = getRepresentativePlugin(pluginKey); + const { plugin, decision, copy } = getEvaluatorPlugin(pluginKey); const proof = getProofAsset(pluginKey); const catalogAction = resolveAction( pluginKey, @@ -427,13 +735,15 @@ export function PluginCatalogCard({ return (
- {proof.alt} + {proof ? ( + {proof.alt} + ) : null}

@@ -441,7 +751,7 @@ export function PluginCatalogCard({ href={decision.docsPath} className="rounded-sm outline-none hover:underline focus-visible:ring-2 focus-visible:ring-fd-primary" > - {plugin.label} + {copy.catalogTitle ?? plugin.label}

diff --git a/e2e/product-proof/capture.mjs b/e2e/product-proof/capture.mjs index 041d8cea..778d435a 100644 --- a/e2e/product-proof/capture.mjs +++ b/e2e/product-proof/capture.mjs @@ -71,6 +71,31 @@ async function roundedScreenshot(input, width, height) { .toBuffer(); } +async function combineScreenshots(left, right) { + const [leftPanel, rightPanel] = await Promise.all( + [left, right].map((input) => + sharp(input) + .resize(1120, 340, { fit: "cover", position: "top" }) + .png() + .toBuffer(), + ), + ); + return sharp({ + create: { + width: 1120, + height: 700, + channels: 4, + background: palette.ink, + }, + }) + .composite([ + { input: leftPanel, left: 0, top: 0 }, + { input: rightPanel, left: 0, top: 360 }, + ]) + .png() + .toBuffer(); +} + async function writeWebP(file, base, composites, quality = 72) { await sharp(base) .composite(composites) @@ -292,6 +317,78 @@ async function seedComments(request) { } } +async function seedCms(request) { + const path = `/api/data/content/${seed.cms.typeSlug}`; + const response = await jsonRequest( + request, + "GET", + `${path}?limit=100&offset=0`, + ); + const current = await response.json(); + for (const item of current.items ?? []) { + if (seed.cms.records.some((record) => record.slug === item.slug)) { + await jsonRequest(request, "DELETE", `${path}/${item.id}`); + } + } + for (const record of seed.cms.records) { + await jsonRequest(request, "POST", path, record); + } + const persistedResponse = await jsonRequest( + request, + "GET", + `${path}?limit=100&offset=0`, + ); + const persisted = await persistedResponse.json(); + for (const record of seed.cms.records) { + const matches = (persisted.items ?? []).filter( + (item) => + item.slug === record.slug && item.parsedData?.name === record.data.name, + ); + if (matches.length !== 1) { + throw new Error( + `CMS fixture expected one persisted ${record.slug} record`, + ); + } + } +} + +async function seedKanban(request) { + const currentResponse = await jsonRequest( + request, + "GET", + `/api/data/boards?${new URLSearchParams({ slug: seed.kanban.slug, limit: "100" })}`, + ); + const current = await currentResponse.json(); + for (const board of current.items ?? []) { + await jsonRequest(request, "DELETE", `/api/data/boards/${board.id}`); + } + const createdResponse = await jsonRequest( + request, + "POST", + "/api/data/boards", + { + name: seed.kanban.name, + slug: seed.kanban.slug, + description: seed.kanban.description, + }, + ); + const board = await createdResponse.json(); + if (!Array.isArray(board.columns) || board.columns.length < 3) { + throw new Error( + "Kanban fixture requires the three generated board columns", + ); + } + for (const task of seed.kanban.tasks) { + await jsonRequest(request, "POST", "/api/data/tasks", { + title: task.title, + description: task.description, + priority: task.priority, + columnId: board.columns[task.column].id, + }); + } + return board; +} + async function cleanupMedia(request) { const params = new URLSearchParams({ query: seed.media.uploadName, @@ -499,6 +596,8 @@ async function main() { try { await seedBlog(context.request); await seedComments(context.request); + await seedCms(context.request); + const kanbanBoard = await seedKanban(context.request); await visit(page, "/pages/blog"); await page.getByRole("heading", { name: "Blog Posts" }).waitFor(); const blog = await screenshot(page, "blog.png"); @@ -518,11 +617,28 @@ async function main() { .dragTo(page.getByTestId("form-builder-canvas")); const form = await screenshot(page, "form-builder.png"); + await visit(page, "/pages/cms"); + await page.getByTestId("cms-dashboard-page").waitFor(); + const cmsDashboard = await screenshot(page, "cms-dashboard.png"); + await visit(page, `/pages/cms/${seed.cms.typeSlug}`); + await page.getByText(seed.cms.records[0].slug, { exact: true }).waitFor(); + const cmsRecords = await screenshot(page, "cms-records.png"); + const cms = await combineScreenshots(cmsDashboard, cmsRecords); + const uiBuilderPage = await seedUiBuilder(context.request); await visit(page, `/pages/ui-builder/${uiBuilderPage.id}/edit`); await page.getByRole("heading", { name: "Component Properties" }).waitFor(); const uiBuilder = await screenshot(page, "ui-builder.png"); + await visit(page, `/pages/kanban/${kanbanBoard.id}`); + await page.getByText(seed.kanban.name, { exact: true }).waitFor(); + const kanban = await screenshot(page, "kanban.png"); + + await visit(page, "/pages/comments/moderation"); + await page.getByTestId("tab-approved").click(); + await page.getByText(seed.comments[0].body, { exact: true }).waitFor(); + const comments = await screenshot(page, "comments.png"); + await seedMedia(context.request); await visit(page, seed.media.libraryPath); await page.getByPlaceholder(seed.media.expectedControl).waitFor(); @@ -538,12 +654,14 @@ async function main() { `Media library expected one visible ${seed.media.uploadName} card`, ); } + const media = await screenshot(page, "media.png"); await visit(page, seed.routeDocs.pagePath); await page .getByText(seed.routeDocs.expectedTitle, { exact: false }) .first() .waitFor(); + const routeDocs = await screenshot(page, "route-docs.png"); await visit(page, seed.openApi.referencePath); await page @@ -584,6 +702,17 @@ async function main() { result: "Editable form + live preview", label: "FORM BUILDER / AUTHENTIC GENERATED APP", }); + await proofFrame("cms-proof.webp", cms, { + eyebrow: "Schema-to-operations proof", + title: ["Define content.", "Give editors", "a workflow."], + body: [ + "The dashboard reflects types", + "defined in code; the list shows", + "records stored by the same app.", + ], + result: "Content model + managed records", + label: "CMS / TWO AUTHENTIC WORKFLOW STATES", + }); await proofFrame("ui-builder-proof.webp", uiBuilder, { eyebrow: "Complex UI proof", title: ["Compose pages.", "Keep the code."], @@ -595,6 +724,50 @@ async function main() { result: "Published page composition", label: "UI BUILDER / AUTHENTIC GENERATED APP", }); + await proofFrame("kanban-proof.webp", kanban, { + eyebrow: "Workflow state proof", + title: ["Move work", "through", "your app."], + body: [ + "The generated board holds", + "columns, priorities, and tasks", + "in the adopter's database.", + ], + result: "Board + columns + task state", + label: "KANBAN / AUTHENTIC GENERATED APP", + }); + await proofFrame("comments-proof.webp", comments, { + eyebrow: "Moderation proof", + title: ["Discussion", "stays with", "the resource."], + body: [ + "A seeded resource comment", + "appears in the shipped", + "moderation workflow.", + ], + result: "Resource context + moderation", + label: "COMMENTS / AUTHENTIC GENERATED APP", + }); + await proofFrame("media-proof.webp", media, { + eyebrow: "Storage-to-library proof", + title: ["Upload once.", "Reuse the asset."], + body: [ + "A checked-in fixture moves", + "through the real upload API", + "into the generated library.", + ], + result: "Uploaded file + stored metadata", + label: "MEDIA / AUTHENTIC GENERATED APP", + }); + await proofFrame("route-docs-proof.webp", routeDocs, { + eyebrow: "Registered-route proof", + title: ["See routes", "your stack", "composed."], + body: [ + "The reference is generated", + "from actual client plugins,", + "parameters, and sitemaps.", + ], + result: "Route + plugin + parameter context", + label: "ROUTE DOCS / AUTHENTIC GENERATED APP", + }); await proofFrame("openapi-proof.webp", openapi, { eyebrow: "One-sided plugin proof", title: ["OpenAPI needs", "no client half."], diff --git a/e2e/product-proof/dogfood-data.json b/e2e/product-proof/dogfood-data.json index c1996724..ae8dbbee 100644 --- a/e2e/product-proof/dogfood-data.json +++ b/e2e/product-proof/dogfood-data.json @@ -33,6 +33,31 @@ "name": "Plugin evaluation", "slug": "plugin-evaluation" }, + "cms": { + "typeSlug": "product", + "records": [ + { + "slug": "btst-release-evidence", + "data": { + "name": "Release evidence kit", + "description": "A typed content record managed through the generated CMS surface.", + "price": 49, + "featured": true, + "category": "Electronics" + } + }, + { + "slug": "btst-plugin-catalog", + "data": { + "name": "Plugin catalog", + "description": "A second record that proves the generated list is backed by stored content.", + "price": 29, + "featured": false, + "category": "Electronics" + } + } + ] + }, "comments": [ { "resourceId": "shipping-plugin-catalog", @@ -41,6 +66,31 @@ "status": "approved" } ], + "kanban": { + "name": "BTST Release Board", + "slug": "btst-release-board", + "description": "A generated board backed by the registered Kanban plugin.", + "tasks": [ + { + "title": "Verify plugin boundaries", + "description": "Confirm what BTST supplies and what the application owns.", + "priority": "HIGH", + "column": 0 + }, + { + "title": "Review generated routes", + "description": "Inspect the generated product surfaces before release.", + "priority": "MEDIUM", + "column": 1 + }, + { + "title": "Capture release evidence", + "description": "Keep the checked-in proof tied to the current implementation.", + "priority": "LOW", + "column": 2 + } + ] + }, "media": { "libraryPath": "/pages/media", "fixture": "../fixtures/test-image.png", diff --git a/packages/cli/plugin-decisions.json b/packages/cli/plugin-decisions.json index c6c7c2ac..6270f009 100644 --- a/packages/cli/plugin-decisions.json +++ b/packages/cli/plugin-decisions.json @@ -27,6 +27,66 @@ "demoPath": "https://www.better-stack.ai/p/blog", "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/blog" }, + "ai-chat": { + "topology": "Full-stack", + "releaseStatus": "Preview", + "supplies": [ + "Streaming chat APIs with typed tool, attachment, and lifecycle boundaries", + "Conversation and message models for authenticated history", + "SSR-aware conversation list and chat routes", + "Customizable chat pages, hooks, and prompt UI" + ], + "adopterSupplies": [ + "An AI SDK model provider, credentials, usage policy, and provider billing", + "A database adapter with isolated transactions for authenticated history", + "Authorization rules for authenticated access, tools, and attachments", + "An upload implementation when file attachments are enabled" + ], + "dependencies": [ + "An AI SDK language model", + "A database adapter with isolated transaction support for authenticated persistence" + ], + "externalServices": [ + "The adopter-selected AI model provider receives prompts and generates responses" + ], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/ai-chat", + "demoPath": "https://www.better-stack.ai/playground?plugins=ai-chat&view=preview", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/ai-chat" + }, + "cms": { + "topology": "Full-stack", + "releaseStatus": "Preview", + "supplies": [ + "Content-type and content-item data models with typed CRUD APIs and lifecycle hooks", + "Admin routes for content-type lists, entries, creation, and editing", + "Schema-driven forms generated from adopter-defined Zod content types", + "Client hooks plus customizable and ejectable admin pages" + ], + "adopterSupplies": [ + "Code-defined Zod content types and application-owned public rendering", + "A BTST database adapter", + "An image upload implementation when file fields are enabled", + "Authorization rules when content operations are protected" + ], + "dependencies": [ + "A BTST database adapter", + "Code-defined Zod content types" + ], + "externalServices": [], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/cms", + "demoPath": "https://www.better-stack.ai/playground?plugins=cms&view=preview", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/cms" + }, "form-builder": { "topology": "Full-stack", "releaseStatus": "Preview", @@ -52,6 +112,142 @@ "docsPath": "/plugins/form-builder", "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/form-builder" }, + "ui-builder": { + "topology": "Client-only", + "relationship": "Dependent", + "releaseStatus": "Preview", + "supplies": [ + "Visual page-list, creation, and editing routes", + "A component registry, layer editor, variables, and reusable block support", + "A PageRenderer for application-owned public routes", + "A CMS content-type declaration for storing page layers and status" + ], + "adopterSupplies": [ + "The components and blocks editors may place on a page", + "A public route that loads CMS page data and mounts PageRenderer", + "CMS authorization rules for page records", + "The application shell and deployment" + ], + "dependencies": ["The CMS plugin, added automatically by the CLI"], + "externalServices": [], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/ui-builder", + "demoPath": "https://www.better-stack.ai/playground?plugins=ui-builder&view=preview", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/ui-builder" + }, + "kanban": { + "topology": "Full-stack", + "releaseStatus": "Preview", + "supplies": [ + "Board, column, task, and assignee data models with typed APIs and lifecycle hooks", + "SSR-aware board list, creation, and detail routes", + "Drag-and-drop column and task workflows with priority and assignee UI", + "Customizable hooks and ejectable Kanban pages" + ], + "adopterSupplies": [ + "A database adapter with isolated transaction support for persistent writes", + "Authorization rules plus user search and identity resolution when assignees are enabled", + "Product-specific workflow rules through configuration and lifecycle hooks", + "The application shell and deployment" + ], + "dependencies": ["A database adapter with isolated transaction support"], + "externalServices": [], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/kanban", + "demoPath": "https://www.better-stack.ai/playground?plugins=kanban&view=preview", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/kanban" + }, + "comments": { + "topology": "Full-stack", + "releaseStatus": "Preview", + "supplies": [ + "Threaded comment and reaction data models with typed APIs and lifecycle hooks", + "Embeddable CommentThread and CommentCount components", + "A moderation route for pending, approved, and spam comments", + "Customizable hooks and ejectable moderation UI" + ], + "adopterSupplies": [ + "A BTST database adapter", + "The resource type and identifier that each thread belongs to", + "Authorization rules and authoritative request identity when access is protected", + "A user resolver when author names and avatars should be displayed" + ], + "dependencies": [ + "A BTST database adapter", + "An adopter-owned host resource" + ], + "externalServices": [], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/comments", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/comments" + }, + "media": { + "topology": "Full-stack", + "releaseStatus": "Preview", + "supplies": [ + "Asset and folder data models with typed upload, registration, and library APIs", + "An SSR-aware media-library route with search, folders, and asset actions", + "Embeddable MediaPicker and ImageInputField components", + "Local, S3-compatible, and Vercel Blob storage adapter implementations" + ], + "adopterSupplies": [ + "A database adapter with isolated transaction support for persistent writes", + "A configured storage adapter and its credentials or local upload directory", + "Allowed MIME types, size limits, URL prefixes, and authorization policy", + "The application routes and fields that embed the picker or image input" + ], + "dependencies": [ + "An isolating Prisma, Drizzle, or Kysely database adapter for persistent writes", + "A configured media storage adapter" + ], + "externalServices": [ + "Optional S3-compatible storage or Vercel Blob when the adopter selects those adapters" + ], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/media", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/media" + }, + "route-docs": { + "topology": "Client-only", + "releaseStatus": "Preview", + "supplies": [ + "A generated route-reference page for registered BTST client plugins", + "Route paths, path and query parameters, sitemap entries, and plugin context", + "Parameter-aware navigation to routes in the adopter's application", + "An ejectable Route Docs page over the packaged introspection runtime" + ], + "adopterSupplies": [ + "Registered BTST client plugins whose routes can be inspected", + "A deployment-level access boundary when route details should be private", + "Concrete parameter values before navigating to a dynamic route", + "The application shell and resolved site location" + ], + "dependencies": ["Registered BTST client routes to inspect"], + "externalServices": [], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/route-docs", + "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/route-docs" + }, "open-api": { "topology": "Backend-only", "releaseStatus": "Preview", @@ -78,6 +274,37 @@ ], "docsPath": "/plugins/open-api", "sourcePath": "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/open-api" + }, + "better-auth-ui": { + "topology": "Client-only", + "relationship": "Companion", + "releaseStatus": "Preview", + "supplies": [ + "Auth and account route definitions backed by @btst/better-auth-ui", + "Sign-in, sign-up, recovery, account, security, and settings UI", + "A CLI scaffold that creates one browser client for the existing auth endpoint", + "Framework-native session refresh wiring for the maintained integration paths" + ], + "adopterSupplies": [ + "An existing Better Auth server, schema, migrations, providers, and secrets", + "A Better Auth browser client configured for the adopter-owned endpoint", + "Any optional Better Auth server and client plugins used by the application", + "Deployment, session policy, and separate BTST authorization mapping when needed" + ], + "dependencies": [ + "An existing Better Auth backend and browser client", + "The supported @btst/better-auth-ui and Better Auth package cohort" + ], + "externalServices": [ + "The adopter's existing Better Auth endpoint; BTST does not host it" + ], + "supportedFrameworks": [ + "Next.js 15+ App Router", + "React Router v7", + "TanStack Start" + ], + "docsPath": "/plugins/better-auth-ui", + "sourcePath": "https://github.com/better-stack-ai/better-auth-ui" } } } diff --git a/packages/cli/src/utils/__tests__/plugin-decision-manifest.test.ts b/packages/cli/src/utils/__tests__/plugin-decision-manifest.test.ts index b417dfea..8280c104 100644 --- a/packages/cli/src/utils/__tests__/plugin-decision-manifest.test.ts +++ b/packages/cli/src/utils/__tests__/plugin-decision-manifest.test.ts @@ -25,8 +25,16 @@ describe("published plugin decision manifest", () => { expect(manifest).toEqual({ schemaVersion: 1, plugins: PLUGIN_DECISIONS }); expect(Object.keys(manifest.plugins)).toEqual([ "blog", + "ai-chat", + "cms", "form-builder", + "ui-builder", + "kanban", + "comments", + "media", + "route-docs", "open-api", + "better-auth-ui", ]); await expect( execFileAsync(process.execPath, [tsxCli, generatorPath, "--check"]), diff --git a/packages/cli/src/utils/__tests__/plugin-meta.test.ts b/packages/cli/src/utils/__tests__/plugin-meta.test.ts index dc2884eb..ba8389fd 100644 --- a/packages/cli/src/utils/__tests__/plugin-meta.test.ts +++ b/packages/cli/src/utils/__tests__/plugin-meta.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { PLUGINS } from "../constants"; +import type { PluginKey } from "../../types"; const maintainedFrameworks = [ "Next.js 15+ App Router", @@ -7,23 +8,39 @@ const maintainedFrameworks = [ "TanStack Start", ] as const; -function representativePlugin(key: "blog" | "form-builder" | "open-api") { +const releasedPluginKeys = [ + "blog", + "ai-chat", + "cms", + "form-builder", + "ui-builder", + "kanban", + "comments", + "media", + "route-docs", + "open-api", + "better-auth-ui", +] as const satisfies readonly PluginKey[]; + +function releasedPlugin(key: PluginKey) { const plugin = PLUGINS.find((candidate) => candidate.key === key); if (!plugin) throw new Error(`Missing plugin metadata for ${key}`); if (!plugin.decision) throw new Error(`Missing decision metadata for ${key}`); return { plugin, decision: plugin.decision }; } -describe("representative plugin decision metadata", () => { - it.each(["blog", "form-builder", "open-api"] as const)( +describe("released plugin decision metadata", () => { + it.each(releasedPluginKeys)( "publishes the shared evaluator contract for %s", (key) => { - const { decision } = representativePlugin(key); + const { decision } = releasedPlugin(key); expect(decision.releaseStatus).toBe("Preview"); expect(decision.supportedFrameworks).toEqual(maintainedFrameworks); expect(decision.docsPath).toBe(`/plugins/${key}`); - expect(decision.sourcePath).toContain(`/plugins/${key}`); + expect(decision.sourcePath).toMatch( + /^https:\/\/github\.com\/better-stack-ai\//, + ); expect(decision.supplies.length).toBeGreaterThan(0); expect(decision.adopterSupplies.length).toBeGreaterThan(0); expect(decision).not.toHaveProperty("audience"); @@ -33,8 +50,15 @@ describe("representative plugin decision metadata", () => { }, ); + it("covers the released CLI inventory without roadmap records", () => { + expect(PLUGINS.map((plugin) => plugin.key)).toEqual(releasedPluginKeys); + expect( + PLUGINS.filter((plugin) => plugin.decision).map((plugin) => plugin.key), + ).toEqual(releasedPluginKeys); + }); + it("describes Blog as the complete feature proof with a working live result", () => { - const { plugin, decision } = representativePlugin("blog"); + const { plugin, decision } = releasedPlugin("blog"); expect(decision.topology).toBe("Full-stack"); expect(plugin.backendImportPath).toBeDefined(); @@ -46,7 +70,7 @@ describe("representative plugin decision metadata", () => { }); it("states the complete Form Builder data workflow without inventing a demo", () => { - const { plugin, decision } = representativePlugin("form-builder"); + const { plugin, decision } = releasedPlugin("form-builder"); expect(decision.topology).toBe("Full-stack"); expect(plugin.backendImportPath).toBeDefined(); @@ -64,7 +88,7 @@ describe("representative plugin decision metadata", () => { }); it("keeps OpenAPI backend-only and Scalar optional", () => { - const { plugin, decision } = representativePlugin("open-api"); + const { plugin, decision } = releasedPlugin("open-api"); expect(decision.topology).toBe("Backend-only"); expect(plugin.backendImportPath).toBeDefined(); @@ -80,4 +104,80 @@ describe("representative plugin decision metadata", () => { "The optional Scalar reference loads @scalar/api-reference from jsDelivr", ]); }); + + it("states the AI Chat model, persistence, and ownership boundaries", () => { + const { plugin, decision } = releasedPlugin("ai-chat"); + + expect(decision.topology).toBe("Full-stack"); + expect(plugin.backendImportPath).toBeDefined(); + expect(plugin.clientImportPath).toBeDefined(); + expect(decision.demoPath).toBe( + "https://www.better-stack.ai/playground?plugins=ai-chat&view=preview", + ); + expect(decision.dependencies).toContain( + "A database adapter with isolated transaction support for authenticated persistence", + ); + expect(decision.adopterSupplies).toContain( + "An AI SDK model provider, credentials, usage policy, and provider billing", + ); + }); + + it("separates CMS content modeling from application-owned public rendering", () => { + const { decision } = releasedPlugin("cms"); + + expect(decision.topology).toBe("Full-stack"); + expect(decision.demoPath).toBe( + "https://www.better-stack.ai/playground?plugins=cms&view=preview", + ); + expect(decision.adopterSupplies).toContain( + "Code-defined Zod content types and application-owned public rendering", + ); + }); + + it("keeps UI Builder client-only and dependent on CMS", () => { + const { plugin, decision } = releasedPlugin("ui-builder"); + + expect(decision.topology).toBe("Client-only"); + expect(decision.relationship).toBe("Dependent"); + expect(plugin.clientImportPath).toBeDefined(); + expect(decision.dependencies).toContain( + "The CMS plugin, added automatically by the CLI", + ); + expect(decision.demoPath).toBe( + "https://www.better-stack.ai/playground?plugins=ui-builder&view=preview", + ); + }); + + it("keeps Kanban full-stack while leaving identities and policy to the app", () => { + const { decision } = releasedPlugin("kanban"); + + expect(decision.topology).toBe("Full-stack"); + expect(decision.demoPath).toBe( + "https://www.better-stack.ai/playground?plugins=kanban&view=preview", + ); + expect(decision.adopterSupplies).toContain( + "Authorization rules plus user search and identity resolution when assignees are enabled", + ); + }); + + it("does not invent standalone demos for embedded or infrastructure plugins", () => { + for (const key of ["comments", "media", "route-docs"] as const) { + expect(releasedPlugin(key).decision.demoPath).toBeUndefined(); + } + expect(releasedPlugin("comments").decision.topology).toBe("Full-stack"); + expect(releasedPlugin("media").decision.topology).toBe("Full-stack"); + expect(releasedPlugin("route-docs").decision.topology).toBe("Client-only"); + }); + + it("describes Better Auth UI as a client-only companion, not an auth backend", () => { + const { plugin, decision } = releasedPlugin("better-auth-ui"); + + expect(decision.topology).toBe("Client-only"); + expect(decision.relationship).toBe("Companion"); + expect(plugin.backendImportPath).toBeUndefined(); + expect(decision.dependencies).toContain( + "An existing Better Auth backend and browser client", + ); + expect(decision.demoPath).toBeUndefined(); + }); }); diff --git a/packages/cli/src/utils/constants.ts b/packages/cli/src/utils/constants.ts index 69e5f113..9d3031e5 100644 --- a/packages/cli/src/utils/constants.ts +++ b/packages/cli/src/utils/constants.ts @@ -94,6 +94,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientSymbol: "aiChatClientPlugin", configKey: "aiChat", extraPackages: ["@ai-sdk/openai", "ai"], + decision: PLUGIN_DECISIONS["ai-chat"], }, { key: "cms", @@ -105,6 +106,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientSymbol: "cmsClientPlugin", configKey: "cms", hasSeedData: true, + decision: PLUGIN_DECISIONS.cms, }, { key: "form-builder", @@ -128,6 +130,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientSymbol: "uiBuilderClientPlugin", configKey: "uiBuilder", hasSeedData: true, + decision: PLUGIN_DECISIONS["ui-builder"], }, { key: "kanban", @@ -139,6 +142,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientSymbol: "kanbanClientPlugin", configKey: "kanban", hasSeedData: true, + decision: PLUGIN_DECISIONS.kanban, }, { key: "comments", @@ -149,6 +153,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientImportPath: "@btst/stack/plugins/comments/client", clientSymbol: "commentsClientPlugin", configKey: "comments", + decision: PLUGIN_DECISIONS.comments, }, { key: "media", @@ -162,6 +167,7 @@ export const PLUGINS: readonly PluginMeta[] = [ // Without it installed, Next.js/webpack fails to resolve the dynamic import // even though the code path is never reached when using other storage adapters. extraPackages: ["@vercel/blob"], + decision: PLUGIN_DECISIONS.media, }, { key: "route-docs", @@ -170,6 +176,7 @@ export const PLUGINS: readonly PluginMeta[] = [ clientImportPath: "@btst/stack/plugins/route-docs/client", clientSymbol: "routeDocsClientPlugin", configKey: "routeDocs", + decision: PLUGIN_DECISIONS["route-docs"], }, { key: "open-api", @@ -208,6 +215,7 @@ export const PLUGINS: readonly PluginMeta[] = [ "@better-auth/api-key@1.6.16", "@better-auth/passkey@1.6.16", ], + decision: PLUGIN_DECISIONS["better-auth-ui"], }, ]; diff --git a/packages/cli/src/utils/plugin-decision.ts b/packages/cli/src/utils/plugin-decision.ts index a7c5fed5..bc36f94d 100644 --- a/packages/cli/src/utils/plugin-decision.ts +++ b/packages/cli/src/utils/plugin-decision.ts @@ -42,14 +42,9 @@ export interface PluginDecisionMeta { /** Canonical working demo identifier, when one exists. */ demoPath?: `https://${string}`; /** Canonical public source identifier. */ - sourcePath: `https://github.com/better-stack-ai/better-stack/${string}`; + sourcePath: `https://github.com/better-stack-ai/${string}`; } -type RepresentativePluginKey = Extract< - PluginKey, - "blog" | "form-builder" | "open-api" ->; - const MAINTAINED_FRAMEWORKS = [ "Next.js 15+ App Router", "React Router v7", @@ -80,6 +75,58 @@ export const PLUGIN_DECISIONS = { sourcePath: "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/blog", }, + "ai-chat": { + topology: "Full-stack", + releaseStatus: "Preview", + supplies: [ + "Streaming chat APIs with typed tool, attachment, and lifecycle boundaries", + "Conversation and message models for authenticated history", + "SSR-aware conversation list and chat routes", + "Customizable chat pages, hooks, and prompt UI", + ], + adopterSupplies: [ + "An AI SDK model provider, credentials, usage policy, and provider billing", + "A database adapter with isolated transactions for authenticated history", + "Authorization rules for authenticated access, tools, and attachments", + "An upload implementation when file attachments are enabled", + ], + dependencies: [ + "An AI SDK language model", + "A database adapter with isolated transaction support for authenticated persistence", + ], + externalServices: [ + "The adopter-selected AI model provider receives prompts and generates responses", + ], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/ai-chat", + demoPath: + "https://www.better-stack.ai/playground?plugins=ai-chat&view=preview", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/ai-chat", + }, + cms: { + topology: "Full-stack", + releaseStatus: "Preview", + supplies: [ + "Content-type and content-item data models with typed CRUD APIs and lifecycle hooks", + "Admin routes for content-type lists, entries, creation, and editing", + "Schema-driven forms generated from adopter-defined Zod content types", + "Client hooks plus customizable and ejectable admin pages", + ], + adopterSupplies: [ + "Code-defined Zod content types and application-owned public rendering", + "A BTST database adapter", + "An image upload implementation when file fields are enabled", + "Authorization rules when content operations are protected", + ], + dependencies: ["A BTST database adapter", "Code-defined Zod content types"], + externalServices: [], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/cms", + demoPath: "https://www.better-stack.ai/playground?plugins=cms&view=preview", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/cms", + }, "form-builder": { topology: "Full-stack", releaseStatus: "Preview", @@ -102,6 +149,126 @@ export const PLUGIN_DECISIONS = { sourcePath: "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/form-builder", }, + "ui-builder": { + topology: "Client-only", + relationship: "Dependent", + releaseStatus: "Preview", + supplies: [ + "Visual page-list, creation, and editing routes", + "A component registry, layer editor, variables, and reusable block support", + "A PageRenderer for application-owned public routes", + "A CMS content-type declaration for storing page layers and status", + ], + adopterSupplies: [ + "The components and blocks editors may place on a page", + "A public route that loads CMS page data and mounts PageRenderer", + "CMS authorization rules for page records", + "The application shell and deployment", + ], + dependencies: ["The CMS plugin, added automatically by the CLI"], + externalServices: [], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/ui-builder", + demoPath: + "https://www.better-stack.ai/playground?plugins=ui-builder&view=preview", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/ui-builder", + }, + kanban: { + topology: "Full-stack", + releaseStatus: "Preview", + supplies: [ + "Board, column, task, and assignee data models with typed APIs and lifecycle hooks", + "SSR-aware board list, creation, and detail routes", + "Drag-and-drop column and task workflows with priority and assignee UI", + "Customizable hooks and ejectable Kanban pages", + ], + adopterSupplies: [ + "A database adapter with isolated transaction support for persistent writes", + "Authorization rules plus user search and identity resolution when assignees are enabled", + "Product-specific workflow rules through configuration and lifecycle hooks", + "The application shell and deployment", + ], + dependencies: ["A database adapter with isolated transaction support"], + externalServices: [], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/kanban", + demoPath: + "https://www.better-stack.ai/playground?plugins=kanban&view=preview", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/kanban", + }, + comments: { + topology: "Full-stack", + releaseStatus: "Preview", + supplies: [ + "Threaded comment and reaction data models with typed APIs and lifecycle hooks", + "Embeddable CommentThread and CommentCount components", + "A moderation route for pending, approved, and spam comments", + "Customizable hooks and ejectable moderation UI", + ], + adopterSupplies: [ + "A BTST database adapter", + "The resource type and identifier that each thread belongs to", + "Authorization rules and authoritative request identity when access is protected", + "A user resolver when author names and avatars should be displayed", + ], + dependencies: ["A BTST database adapter", "An adopter-owned host resource"], + externalServices: [], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/comments", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/comments", + }, + media: { + topology: "Full-stack", + releaseStatus: "Preview", + supplies: [ + "Asset and folder data models with typed upload, registration, and library APIs", + "An SSR-aware media-library route with search, folders, and asset actions", + "Embeddable MediaPicker and ImageInputField components", + "Local, S3-compatible, and Vercel Blob storage adapter implementations", + ], + adopterSupplies: [ + "A database adapter with isolated transaction support for persistent writes", + "A configured storage adapter and its credentials or local upload directory", + "Allowed MIME types, size limits, URL prefixes, and authorization policy", + "The application routes and fields that embed the picker or image input", + ], + dependencies: [ + "An isolating Prisma, Drizzle, or Kysely database adapter for persistent writes", + "A configured media storage adapter", + ], + externalServices: [ + "Optional S3-compatible storage or Vercel Blob when the adopter selects those adapters", + ], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/media", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/media", + }, + "route-docs": { + topology: "Client-only", + releaseStatus: "Preview", + supplies: [ + "A generated route-reference page for registered BTST client plugins", + "Route paths, path and query parameters, sitemap entries, and plugin context", + "Parameter-aware navigation to routes in the adopter's application", + "An ejectable Route Docs page over the packaged introspection runtime", + ], + adopterSupplies: [ + "Registered BTST client plugins whose routes can be inspected", + "A deployment-level access boundary when route details should be private", + "Concrete parameter values before navigating to a dynamic route", + "The application shell and resolved site location", + ], + dependencies: ["Registered BTST client routes to inspect"], + externalServices: [], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/route-docs", + sourcePath: + "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/route-docs", + }, "open-api": { topology: "Backend-only", releaseStatus: "Preview", @@ -126,4 +293,31 @@ export const PLUGIN_DECISIONS = { sourcePath: "https://github.com/better-stack-ai/better-stack/tree/main/packages/stack/src/plugins/open-api", }, -} as const satisfies Record; + "better-auth-ui": { + topology: "Client-only", + relationship: "Companion", + releaseStatus: "Preview", + supplies: [ + "Auth and account route definitions backed by @btst/better-auth-ui", + "Sign-in, sign-up, recovery, account, security, and settings UI", + "A CLI scaffold that creates one browser client for the existing auth endpoint", + "Framework-native session refresh wiring for the maintained integration paths", + ], + adopterSupplies: [ + "An existing Better Auth server, schema, migrations, providers, and secrets", + "A Better Auth browser client configured for the adopter-owned endpoint", + "Any optional Better Auth server and client plugins used by the application", + "Deployment, session policy, and separate BTST authorization mapping when needed", + ], + dependencies: [ + "An existing Better Auth backend and browser client", + "The supported @btst/better-auth-ui and Better Auth package cohort", + ], + externalServices: [ + "The adopter's existing Better Auth endpoint; BTST does not host it", + ], + supportedFrameworks: MAINTAINED_FRAMEWORKS, + docsPath: "/plugins/better-auth-ui", + sourcePath: "https://github.com/better-stack-ai/better-auth-ui", + }, +} as const satisfies Record;