Help center — Tenantx kernel
This document explains how the in-app help center works in Tenantx: who can read it, how content is stored, how categories are shaped, and how it differs from platform management.
Roles in one sentence
| Actor | What they do |
|---|---|
| End user (tenant) | Browse and search published articles when they have help_center.read. |
| Author (optional tenant) | Some write APIs exist under the authenticated tenant API but are gated by subscription:write and controller checks (e.g. help_center.create / update / delete). In typical kernels, only platform operators curate global content. |
| Platform operator | Full category + article CRUD under /api/platform/help-center/* (requires subscription.admin via platform.admin middleware). |
Always enforce the same rules on the API; sidebar visibility is UI-only.
Three API surfaces
1. Public (no auth)
Under GET /api/help-center/… (no auth:sanctum):
GET /api/help-center/articles/context— contextual article hints for the SPA.GET /api/help-center/articles/{id}— single article by UUID.GET /api/help-center/s/{categorySlug}— category by slug.GET /api/help-center/s/{categorySlug}/{articleSlug}— article by category + article slug (canonical public URLs).
Use these for marketing pages or unauthenticated previews if you wire them; the main app uses authenticated routes for the full UI.
2. Tenant (auth + organization)
Under auth:sanctum, organization, and subscription:read (see backend/routes/api.php):
- Read:
GET /api/help-center/categories,GET /api/help-center/articles, featured/popular, single article routes as exposed. - Feedback:
POST /api/help-center/articles/{id}/helpfuland…/not-helpful. - Writes:
POST/PUT/DELETEcategories and articles (plus publish/unpublish/archive) sit in a group protected bysubscription:write. Controllers should still check Spatie permissions such ashelp_center.create/help_center.update/help_center.deletewhere applicable.
The React app gates the Help Center page with help_center.read (PermissionRoute + useHasPermission).
3. Platform (global operator)
Under auth:sanctum + platform.admin + prefix /api/platform:
GET/POST /api/platform/help-center/categoriesandPUT/DELETE …/categories/{id}**GET/POST /api/platform/help-center/articlesandPUT/DELETE …/articles/{id}**
These ignore tenant org boundaries for global rows (organization_id null). The platform UI lives under /platform and uses platformApi + usePlatformAdminPermissions, not the tenant permission hook.
Where content lives (filesystem + DB)
-
Markdown source (recommended for kernel demos and CI)
- Directory:
backend/resources/help-center/articles/{category-folder}/{lang}/*.md - Kernel convention: ship at least
en(andarwhen you have translated markdown). The DB/APIlanguagecolumn may still acceptps/fafor article bodies (legacy TenantX / multi-locale content); the React app UI isen+aronly — seedocs/I18N.md. HelpCenterCategorySeedercreates one category per top-level folder name (slug = folder name). Metadata (title, description, icon, color, order) is defined inHelpCenterCategorySeeder::folderMeta().HelpCenterArticleSeederloads each.mdfile intohelp_center_articles(global articles:organization_idnull). It soft-deletes previous global articles first, then upserts from disk.
- Directory:
-
Runtime edits
Platform admins can change categories/articles via API/UI; that data lives in PostgreSQL. Re-runningHelpCenterArticleSeederoverwrites global articles from markdown—use a deliberate process in production (export/import or avoid re-seeding content you edited only in DB).
See also backend/resources/help-center/MANIFEST.md for the current kernel folder layout.
Frontend usage (tenant)
- Route:
/help-center(and article routes under/help-center/…). - Hooks:
useHelpCenterCategories,useHelpCenterArticles, etc. (frontend/src/hooks/help-center/useHelpCenter.tsx). - Language: Send the active SPA locale (
enorar) where the API expects it; the client readstenantx-language(and legacyTenantX-languagefallback) for/help-center/requests. - Canonical links inside markdown often use
/help-center/s/{categorySlug}/{articleSlug}.
Visibility and safety
- Articles support visibility (e.g. org users vs staff-only) and published state; the controller filters by permission (
help_center.read,help_center.read_staff, etc.). - Do not expose platform-only actions on tenant routes without mirroring the same checks on the server.
Quick commands
cd backend
php artisan db:seed --class=HelpCenterCategorySeeder
php artisan db:seed --class=HelpCenterArticleSeeder
Requires PostgreSQL for a full demo dataset aligned with other seeders; SQLite may skip some related demo rows.
Related docs
- PERMISSIONS.md — org vs global permissions.
- PLATFORM_ADMIN.md — platform help-center management.
- I18N.md — UI translation vs help article languages.