> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tuturuuu CMS

> Site editing, publishing, preview, team access, and internal site-template operations for Tuturuuu CMS.

## TL;DR

Tuturuuu CMS now lives in the dedicated `apps/cms` satellite app.

* `apps/cms` owns the CMS authoring UI, workspace picker, overview/content/preview/members routes, and the root `/{wsId}/projects` linking console (reached as `/internal/projects` for the root workspace).
* `apps/web` remains the only backend/API owner for CMS and external-project traffic.
* `apps/cms` rewrites `/api/*` to `apps/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
existing `external-project*` contracts.

## Route Model

The route tree below mirrors `apps/cms/src/app/[locale]/(dashboard)/[wsId]`.
Workspace navigation is defined in
`apps/cms/src/app/[locale]/(dashboard)/[wsId]/navigation.tsx`. Every route is
workspace-scoped under `/{wsId}`; the root workspace uses the `internal` slug
(it resolves to `ROOT_WORKSPACE_ID` via `normalizeWorkspaceId`).

### Root workspace

* `/{wsId}/projects` (reached as `/internal/projects`): internal site-template
  registry, workspace-indexed connection list, and connection audit history.
  The internal workspace is not a bindable content workspace, so its overview,
  content, and `/settings` routes redirect into `/{wsId}/projects`.

### Bound workspaces

* `/{wsId}`: overview / continue-editing home.
* `/{wsId}/content`: primary content operations surface (search, status
  filtering, publishing, reusable content).
* `/{wsId}/content/collections/{collectionId}`: collection (section) detail.
* `/{wsId}/content/entries/{entryId}`: entry (content) detail.
* `/{wsId}/pages`: page-builder surface for landing-style sections.
* `/{wsId}/media`: media library.
* `/{wsId}/products`: product catalog content.
* `/{wsId}/storefront`: storefront configuration.
* `/{wsId}/taxonomy`: taxonomy (terms, categories, tags).
* `/{wsId}/games`: game content surface, shown only when CMS Games is enabled
  for the workspace (`getCmsGamesEnabled`).
* `/{wsId}/preview`: site preview.
* `/{wsId}/members`: workspace member search, invite, removal, role assignment,
  and role/default-permission management.
* `/{wsId}/settings`: redirect-only route. It sends the internal workspace to
  `/{wsId}/projects` and every other workspace to `/{wsId}/members`; CMS has no
  standalone settings screen.

## Root Linking Console

* Treat `/{wsId}/projects` (the root workspace's `/internal/projects`) as 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}/content` for broader content operations: search, status filtering, publishing queues, collection health, and reusable content.
* Use `/{wsId}/pages` for focused landing-style page edits, page readiness, and preview-first section work.
* Use `/{wsId}/media`, `/{wsId}/products`, `/{wsId}/storefront`, and `/{wsId}/taxonomy` for the corresponding media, catalog, storefront, and taxonomy surfaces.
* Use `/{wsId}/games` for game content when CMS Games is enabled for the workspace.
* Use `/{wsId}/members` for routine collaborator management without leaving CMS.
* Keep collection configuration on `/{wsId}/content/collections/{collectionId}` and entry authoring on `/{wsId}/content/entries/{entryId}`.
* Use `/{wsId}/preview` as the delivered-content surface backed by the existing preview delivery route.
* CMS has no standalone settings screen; `/{wsId}/settings` is a redirect-only route to `/{wsId}/members` (or `/{wsId}/projects` on the internal workspace).

## Member Management In CMS

* Workspace member search, invite, remove, and role-assignment controls now have a dedicated `/{wsId}/members` sidebar 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/web` API routes and `@tuturuuu/internal-api` helpers. 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-api` for 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 `null` leaves 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/setup` with 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}-main` project 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 relative `sourceUrl` such 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_projects` or 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_path` values must stay under `external-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/projects` console (the root workspace's `/{wsId}/projects`) for site-template and workspace-link operations.
* Keep bound-workspace collaborator management on the dedicated `/{wsId}/members` route, and do not surface the root projects console inside non-root workspace sidebars.
* Update both `apps/cms/messages/en.json` and `apps/cms/messages/vi.json`, then run `bun i18n:sort` whenever CMS copy changes.
