Commit b73aeb5
authored
feat: standalone help center with MCP tools and UI polish (#128)
* docs: add help center standalone subdomain design spec
* docs: add help center standalone implementation plan
* feat(db): add schema changes for standalone help center
Add parentId/icon to kb_categories, position/description to kb_articles,
change embedding dimension to 768, add helpCenterConfig to settings, and
create kb_domain_verifications table for custom domain tracking.
* feat(settings): add HelpCenterConfig types, service, and schemas
Add settings infrastructure for the standalone help center feature:
- HelpCenterConfig and HelpCenterSeoConfig interfaces with defaults
- getHelpCenterConfig/updateHelpCenterConfig service functions
- helpCenterConfig in TenantSettings (parsed from DB text column)
- Zod schemas for config and SEO updates
- Server functions (admin-only GET/POST endpoints)
- Updated category schemas (parentId, icon) and article schemas (position, description)
- Barrel export updated with new types and defaults
* feat(help-center): update category/article CRUD for parentId, icon, position, description
Add parentId and icon support to createCategory/updateCategory. Add
position and description support to createArticle/updateArticle. Add
listPublicArticlesForCategory service function and server function.
Update HelpCenterCategory and HelpCenterArticle types to include the
new fields. All new fields are passed through in serialized responses.
* feat(routing): add hostname detection and routing for standalone help center
Add isHelpCenterHost pure helper with 16 unit tests covering custom
domain, convention subdomain (help.{slug}.{baseDomain}), port stripping,
and edge cases. Wire detection into bootstrap, root route context, and
portal guard. Support HELP_CENTER_DEV env var and ?mode=help-center
query param overrides for development.
* feat(help-center): add layout route and landing page
Add the help center pathless layout route (_helpcenter.tsx) and landing
page with hero search and category grid. The layout guards on
helpCenterHost, feature flag, and config.enabled. It injects theme CSS,
branding, i18n, and renders HelpCenterHeader with category tabs.
Components:
- help-center-header: logo, org name, category tabs, compact search
- help-center-search: hero search with 300ms debounced API calls,
dropdown results; compact button placeholder for inner pages
- help-center-category-grid: responsive grid of category cards
- help-center-utils: pure functions for category filtering, active
state detection, content truncation (with tests)
* feat(help-center): add category page with sidebar, breadcrumbs, and subcategory support
- Category layout route loads category by slug, articles, and subcategory articles
- Sidebar component shows category articles with active state and indented subcategories
- Breadcrumbs component renders Help Center > Category > Article trail
- Category index page displays article cards with descriptions and arrow icons
- Pure utility functions (getSubcategories, buildCategoryBreadcrumbs) with full test coverage
* feat(help-center): add article detail page with TOC, prev/next nav, and feedback
TDD'd extractHeadings (TipTap JSON -> TOC) and computePrevNext pure
functions. Article detail route loads via getPublicArticleBySlugFn,
renders rich text content, breadcrumbs, sticky table of contents with
scroll spy, previous/next article navigation, and thumbs up/down
feedback with optimistic updates. Full SEO head tags with OG and
canonical URL.
* feat(settings): restructure admin settings with Portal and Help Center sections
Move Widget settings from Feedback to a new Portal section, add Portal
General page with feature toggles, and create Help Center General/SEO
settings pages gated by the helpCenter feature flag. Old /admin/settings/widget
route redirects to /admin/settings/portal-widget.
* feat(help-center): add Gemini embedding service for KB articles
Generates embeddings via Gemini text-embedding-004 (768 dims) through the
OpenAI-compatible API. Triggers fire-and-forget on article create/update.
* feat(help-center): add hybrid search combining keyword + semantic matching
Adds a hybrid search service that combines tsvector keyword search with
pgvector semantic similarity (0.4/0.6 weighting). Falls back to keyword-only
when embeddings are unavailable. Updates the widget kb-search endpoint and
adds a public searchPublicArticlesFn server function.
* fix(help-center): include category id in kb-search response for backward compat
* feat(help-center): add custom domain verification service and server functions
CNAME-based domain verification so customers can serve their help center
on a custom domain. Includes DNS lookup, pending/verified/failed status
tracking, and server functions for adding, checking, and removing domains.
* feat(help-center): add SEO structured data and sitemap
Add JSON-LD structured data (Article, BreadcrumbList, CollectionPage)
to help center article and category pages, a sitemap.xml route for
search engine crawling, and noindex meta for authenticated help centers.
* refactor(portal): remove old help center routes, update widget links to subdomain
Delete portal help center routes (/help, /help/$category, /help/$category/$article)
and components now replaced by standalone help center on its own subdomain. Add
getHelpCenterBaseUrl helper to build the correct help center URL (custom domain
or convention subdomain), and update the widget help detail "view on portal" link
to navigate to the standalone help center instead of the old portal route.
* fix(help-center): resolve type errors in embedding service and article route
- Cast articleId to HelpCenterArticleId in embedding service eq() call
- Rename shadowed loaderData variable to parentLoaderData in article head()
* fix(help-center): rename _helpcenter to hc for TanStack Router compatibility
TanStack Router's file-based routing doesn't support two pathless layouts
(_portal and _helpcenter) both resolving to /. Renamed to /hc path prefix.
On production subdomains, a reverse proxy maps help.acme.com/* -> /hc/*.
The HELP_CENTER_DEV=true env or helpCenterHost detection in _portal.tsx
redirects to /hc when on the help center subdomain.
* fix(help-center): update all route references and links for /hc prefix
After renaming _helpcenter to hc, all internal references needed updating:
- getRouteApi() calls: /_helpcenter -> /hc
- Article/category links: add /hc prefix
- Breadcrumb URLs: add /hc prefix
- Header logo and tab links: point to /hc
- Tests updated to match new paths
* docs: add help center category management design spec
* docs: add help center category management implementation plan
* feat(help-center): add CategoryNav sidebar with drag-to-reorder
* feat(help-center): add CategoryFormDialog with emoji picker
* feat(help-center): integrate CategoryNav sidebar and inline status filter
* feat(help-center): add inline category creation from article editor
* feat(help-center): add inline category creation to create article dialog
* fix: update tests for domain verification change, fix unused vars lint
* test: add category schema tests for emoji icons, position reorder, form payloads
* fix: track help redirect routes, use branded HelpCenterCategoryId type
* fix: parallelize drag-reorder mutations, fix article serialization consistency
* docs: add MCP help center tools design spec
Covers new scopes (read:help-center, write:help-center), extending
search and get_details tools, 4 new write tools, 1 new resource,
and feature flag gating.
* docs: add MCP help center tools implementation plan
10 tasks covering scopes, feature flag, search/get_details extensions,
4 new write tools, resource, and doc header update.
* feat(mcp): add read:help-center and write:help-center scopes
* feat(mcp): register help center scopes in OAuth provider and consent screen
* feat(mcp): extend search tool with articles entity
* feat(mcp): add help center tools (get_details, create/update/delete article, manage category)
- Expand help-center.service imports (getArticleById, getCategoryById, createArticle, updateArticle, publishArticle, unpublishArticle, deleteArticle, createCategory, updateCategory, deleteCategory)
- Add HelpCenterArticleId and HelpCenterCategoryId to @quackback/ids type imports
- Extend get_details with helpcenter_article and helpcenter_category prefix routing (per-branch scope checking)
- Add create_article tool (draft creation, write:help-center scope)
- Add update_article tool (patch fields + publish/unpublish via publishedAt, write:help-center scope)
- Add delete_article tool (soft-delete, write:help-center scope)
- Add manage_category tool (create/update/delete, write:help-center scope)
- Add getArticleDetails and getCategoryDetails helper functions
* feat(mcp): add help-center/categories resource, refactor scopeGated
* docs(mcp): update tools.ts header to list all 27 tools
* fix(mcp): clarify article status values in search, fix publishedAt description
Add article status values (draft/published/all) to the search tool's
status field description. Clarify that update_article publishedAt
publishes immediately rather than using the provided timestamp.
* feat: refresh OAuth consent screen UX
Group scopes by feature area (Feedback, Changelog, Help Center) with
monochrome Read/Write pills. Remove Card wrapper to match login page
layout. Larger buttons, quieter footer, error state for failed consent.
* fix: align help center category nav with shared filter section styling
Use text-[10px] header size, remove divider, wrap items in mt-2
container to match the changelog/feedback sidebar patterns.
* fix: align all admin left sidebar headers to consistent styling
- Help center: use text-[10px] header, matching FilterSection pattern
- Roadmap: shrink + button from h-7 to h-5, reduce header bottom gap
- Analytics: add "Sections" header label using shared header pattern
- All sidebars now use: text-[10px] font-semibold uppercase tracking-wider,
py-1 header row, mt-2 items wrapper, h-5 w-5 action buttons
* fix: align users sidebar header to shared admin sidebar pattern
Use text-[10px] uppercase header, h-5 w-5 + button, remove divider,
wrap items in mt-2 container to match all other admin left sidebars.
* fix: replace raw select with shadcn Select for category dropdown
Use Radix-based Select component with proper popover, icons, and
styling instead of a native <select> element.
* fix: prefill category select when categories are loaded
Only set Select value when categoryId matches a loaded category,
preventing the placeholder from showing when the value exists but
items haven't rendered yet.
* fix: show category value even before categories list loads
Pass categoryId directly to Select value instead of gating on
categories being loaded. Radix handles unmatched values gracefully
and renders correctly once items load.
* fix: enforce authenticated-only access on help center routes
Check session in beforeLoad when access is set to 'authenticated'.
Redirects unauthenticated users to login. Previously the setting
only affected the robots meta tag but didn't gate actual access.
* refactor: simplify MCP tools and consent screen after review
- Extract articleResult(), categoryResult(), truncateExcerpt(),
requireHelpCenterWrite() helpers to eliminate copy-paste
- Use publish/unpublish return value in update_article instead of
re-fetching
- Pre-derive isSafeUrl booleans in consent legal links
- Drop redundant optional chaining in hc.tsx after null guard
* feat: rename API routes from /api/v1/kb to /api/v1/help-center
Rename to match user-facing product name. Fix serialization bug in
listPublicArticlesForCategoryFn that called serializeArticle on
partial results missing createdAt/updatedAt fields.
* feat: redesign widget help tab with category grid and fix settings
- Move Help tab toggle from Content section to Tabs section alongside
Feedback and Changelog in widget settings
- Remove redundant Content settings card (image uploads handled by Permissions)
- Replace search-only help tab with mini help center: search bar + 2-column
category card grid, with drill-down into category article lists
- Add widget-help-category component for browsing articles within a category
- Fix widget loader to gate help tab on feature flag AND help center enabled
AND widget config (was only checking feature flag)
- Update settings preview to reflect help tab with category grid
* fix: resolve PR #128 review comments and simplify help center settings
- Fix search result links missing /hc prefix (P1 codex finding)
- Fix CNAME target mismatch: UI now shows help-proxy.quackback.app
matching the verification service
- Fix categories.test.ts type errors by casting mock auth contexts
- Fix $articleSlug.tsx route ID comparison type error
- Remove help-center-seo settings page (SEO features enabled by default)
- Simplify domain settings: remove redundant subdomain display, inline
CNAME instructions, cleaner custom domain UX
* fix: remove domain verification status from help center settings
No proxy infrastructure exists yet, so pending/verified badges and
CNAME instructions are premature. Keep custom domain as a simple input.
* fix: cast test mocks in articles.test.ts and remove claude workflow
- Fix articles.test.ts type errors (same as categories.test.ts fix)
- Remove .github/workflows/claude.yml
* fix: update MCP handler test counts for help center tools and resources1 parent a035099 commit b73aeb5
115 files changed
Lines changed: 22510 additions & 1823 deletions
File tree
- .github/workflows
- apps/web/src
- components
- admin
- analytics
- help-center
- settings
- __tests__
- widget
- users
- help-center
- __tests__
- portal/help-center
- widget
- lib
- client/queries
- server
- auth
- domains
- help-center
- __tests__
- settings
- __tests__
- functions
- mcp
- __tests__
- routes
- _portal
- admin
- api
- v1/help-center
- __tests__
- articles
- categories
- widget
- hc
- $categorySlug
- oauth
- widget
- docs/superpowers
- plans
- specs
- packages
- db
- drizzle
- meta
- src/schema
- ids/src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
This file was deleted.
Lines changed: 25 additions & 18 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
69 | 76 | | |
70 | 77 | | |
71 | 78 | | |
| |||
Lines changed: 219 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
66 | 67 | | |
67 | 68 | | |
68 | 69 | | |
69 | | - | |
| 70 | + | |
70 | 71 | | |
71 | 72 | | |
72 | 73 | | |
| |||
0 commit comments