TL;DR
Tuturuuu CMS now lives in the dedicatedapps/cms satellite app.
apps/cmsowns the CMS authoring UI, workspace picker, overview/library/preview/members routes, and the root/{wsId}/projectslinking console.apps/webremains the only backend/API owner for CMS and external-project traffic.apps/cmsrewrites/api/*toapps/web, so proxy behavior and bot protection stay centralized.
Product Vocabulary
The visible CMS experience is a site/content product, not an implementation console. Bound-workspace UI should say site, site template, connection, content, section, URL path, custom details, media, publishing, preview, people, invitations, and team access. Avoid implementation terms in normal UI copy, including external project, canonical, adapter, binding, slug, schema, metadata, profile data, payload, and JSON. If operators need exact implementation values, show them only in collapsed Developer details panels or internal root-console advanced controls. Keep code, API routes, database objects, migration names, and integration docs on the existingexternal-project* contracts.
Route Model
Root workspace
/internal/projects: internal site-template registry, workspace-indexed connection list, and connection audit history
Bound workspaces
/{wsId}: overview/{wsId}/landing: page-builder surface for landing-only sections/{wsId}/library: content operations surface for non-landing, non-game sections and content/{wsId}/games: game content surface when CMS Games is enabled/{wsId}/library/collections/{collectionId}: section detail/{wsId}/library/entries/{entryId}: content detail/{wsId}/members: workspace member search, invite, removal, role assignment, and role/default-permission management/{wsId}/preview: site preview/{wsId}/settings: legacy compatibility redirect to/{wsId}/members
/{wsId}/content, /{wsId}/collections/..., /{wsId}/admin) is removed instead of redirected.
The internal/root workspace is not a bindable content workspace, so /internal and other root-workspace CMS route variants should redirect to /internal/projects.
Root Linking Console
- Treat
/internal/projectsas a workspace-first control room. - The main left panel is the searchable workspace list.
- Each row shows the current connection state, site type, site template, and most recent change signal.
- The selected workspace panel owns connect and disconnect actions.
- The site-template registry is secondary and stays on the same page for create/edit flows.
- Binding audits stay anchored to the selected workspace instead of living as a detached global feed.
Workspace CMS
- Use
/{wsId}as the concise starting point for continue-editing tasks, launch readiness, attention queues, recent activity, and connected-site context. - Use
/{wsId}/landingfor focused landing-page edits, page readiness, and preview-first section work. - Use
/{wsId}/libraryfor broader content operations: search, status filtering, publishing queues, collection health, and reusable non-landing/non-game content. - Use
/{wsId}/membersfor routine collaborator management without leaving CMS. - Keep collection configuration on collection detail pages and entry authoring on entry detail pages.
- Use
/{wsId}/previewas the delivered-content surface backed by the existing preview delivery route. - The old settings screen is removed because it duplicated overview, library, and members content. Keep
/settingsonly as a compatibility redirect to/{wsId}/members.
Member Management In CMS
- Workspace member search, invite, remove, and role-assignment controls now have a dedicated
/{wsId}/memberssidebar route. - The members surface also absorbs the essentials of the workspace roles page so CMS operators can manage named roles and default permissions without leaving CMS.
- This keeps standalone CMS usable without forcing operators back into the main platform app for routine collaborator changes.
- CMS members data must load through external-project-aware
apps/webAPI routes and@tuturuuu/internal-apihelpers. Reads should authorize by CMS workspace access so app-session users do not hit workspace settings-route 403s; writes still respect member and role management permissions. - Use CMS copy in this area: team access, people, invites, access levels, member defaults, guest defaults, and Advanced access.
Implementation Notes
- Keep CMS as a pure satellite frontend. Do not move API ownership into
apps/cms. - Continue adding or extending client helpers in
packages/internal-apifor CMS-facing API calls. - Keep preview sourced from the existing delivery route instead of introducing a second preview payload contract.
- Backend/database naming remains
external-project*; the product surface is what changed. - Protect CMS-owned product copy with the CMS copy hygiene test, and add explicit admin/developer-detail exceptions only when a staff workflow truly needs an implementation value.
- Translation validation now treats
nullleaves as invalid so missing shared keys fail checks instead of silently passing parity. - External app admin dashboards should call
POST /api/v1/workspaces/{wsId}/external-projects/setupwith their sync manifest before diff/apply. The route uses the existing app-coordination token and requires manage access. If the workspace is already bound to an active canonical project for the same adapter, setup preserves that binding while refreshing the project schema and field definitions; otherwise it creates the canonical{adapter}-mainproject if needed and binds the configured workspace without requiring production Supabase keys in the external app. - External apps can mark manifest assets with
metadata.publicPath,metadata.localAssetPath, or a relativesourceUrlsuch as/media/hero.png. - Before diff/apply, run the public-folder linker so the manifest stores deterministic Drive paths under
external-projects/{adapter}/{collectionSlug}/{entrySlug}/{filename}. - Diff/apply routes are workspace-scoped. They may persist manifest schema into the bound workspace’s collections and field definitions, but they must not update
canonical_external_projectsor other root/canonical registry state. - Before apply, upload those files through the external-project asset app-server upload route. Abort the apply if a local public asset is missing so CMS never receives storage paths for objects that were not uploaded.
- Asset
storagePath/storage_pathvalues must stay underexternal-projects/. Do not point CMS assets at Drive, finance, or other workspace storage namespaces; delivery and admin cleanup only operate on assets that satisfy the CMS namespace invariant.
Team Guidance
- Link into the CMS-native route map directly.
- Prefer the root
/internal/projectsconsole for site-template and workspace-link operations. - Keep bound-workspace collaborator management on the dedicated
/{wsId}/membersroute, and do not surface/internal/projectsshortcuts inside non-root workspace sidebars. - Update both
apps/cms/messages/en.jsonandapps/cms/messages/vi.json, then runbun i18n:sortwhenever CMS copy changes.