The GroCMS handbook

The GroCMS handbook

The complete public GroCMS handbook, ready to read, print or download.

GroCMS 0.1.0 · Reviewed 15 September 2026

Download all guides

Start here

Getting started

Find your way around the workspace and take your first piece of content from draft to published page.

Your website and your workspace

GroCMS has two sides. Visitors see the published website at the site’s root address. Your team signs in at /login and works under /admin. View site in the workspace header and Your website in the sidebar open the public website. A saved draft in the workspace does not automatically change what visitors see.

The Overview is a starting point for finding content and checking activity. Pages hold lasting information such as About and Contact. Posts hold articles and announcements. Media library holds uploaded assets. The Your site group controls reusable design. The Workspace group covers publishing, people, configuration and these guides.

Sources: Workspace navigation and screen routing; Content editor controls; Initial workspace setup.

Start your first session

  1. Open the address provided by your administrator and sign in with your own email and password. An invitation lets a new team member create their account; there is no open public registration.
  2. Check your name and role at the bottom of the sidebar. Your role determines which records and actions are available. Open your name to manage your password, sessions and authenticator.
  3. Visit Overview, then open Pages or Posts. Search for the item you need before creating another. Some workspaces contain demonstration content; a clean installation starts with draft configuration and no sample articles.
  4. Open an entry and inspect its current status and title. Use the Content or Details tab for fields, and the Visual editor tab when the entry has a custom composition or is a design resource.

Sources: Workspace navigation and screen routing; Account invitation workflow; Content editor controls; Initial workspace setup.

Create and publish your first entry

  1. Choose Pages or Posts and use the creation action. Give the item a clear title and a suitable slug, then add the body and any required fields.
  2. Add media with useful alternative text, select relevant categories for posts, and check SEO & visibility. Public and Private are deliberate choices; publication and visibility are separate.
  3. Save your changes and wait for saving to finish. Layout changes also participate in the editor’s save flow. Do not assume an unsaved field is included in a preview or publication.
  4. Use Preview to inspect the saved draft. Check text, links and narrow-screen layout. Preview is private access to draft content, so treat its link as sensitive.
  5. If you have publishing permission, publish the saved revision. A contributor submits their work for review instead. Approval by a reviewer and publication are separate actions.
  6. Open View site and check the public URL. For an existing published entry, further saved changes remain drafts until you publish again.

For example, changing a published About page’s telephone number saves a new working revision while visitors continue to see the previous number. Publishing that revision switches the public page. Revision history lets you inspect and restore older work; restoring it creates working content to review before publication.

Sources: Content editor controls; Revision and publication service.

Choose the guide for your task

Each guide stands on its own and names the screen, intended audience, procedure and limits. Search documentation by a feature or problem, such as homepage, password, schedule or backup. Group filters narrow the results. Each article has an On this page index, related guides and references to the implementation or official product documentation.

Start with How the CMS works to understand drafts and publication. Read Pages and Posts for editing, then Homepage and Visual editor for design. Administrators should read People, Settings and Account & security. Installation and maintenance instructions are in Setup & operations and involve terminal access rather than ordinary editing controls.

Print this guide prints the current article. The handbook combines all guides for printing or saving as PDF through your browser. Download Markdown provides a portable text copy. These guides describe the delivered application; they are maintained with the application’s source code and are not editable through the Pages screen.

Some installations also enable a public handbook at /docs. It contains an explicitly reviewed set of product guides and has its own search and downloads. Public documentation does not sign you into the CMS or grant access to the workspace. Ordinary installations keep this public feature disabled, so a Page using /docs remains ordinary website content.

Sources: Documentation routes and rendering; Reviewed public guide selection and links.

References

  1. Workspace navigation and screen routing

    Repository path: apps/cms/src/components/admin/shell.tsx

  2. Content editor controls

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

  3. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

  4. Account invitation workflow

    Repository path: apps/cms/src/cms/auth/people.ts

  5. Initial workspace setup

    Repository path: apps/cms/scripts/setup.ts

  6. Documentation routes and rendering

    Repository path: apps/cms/src/components/documentation/article.tsx

  7. Reviewed public guide selection and links

    Repository path: apps/cms/src/cms/documentation/public.ts

Start here

How the CMS works

Understand what saving, publishing, previewing and scheduling actually change.

The editor and website can show different saved versions

GroCMS keeps the version you are working on separate from the version visitors can see. Saving a title, body or layout creates a new saved revision. Publishing chooses a particular saved revision for the website. If you publish an article and then change its introduction, visitors continue to receive the published introduction until someone with permission publishes the later revision. A successful save is therefore evidence that your work is stored, not that it is public.

This distinction also applies to design. Templates, shared sections, menus, brand identity and site settings have working and published versions. You can prepare a new header without changing the current site. Publishing the header makes that design available to the pages that use it. An unpublished edit to a category name, an author profile or a media replacement must not slip into an otherwise published page.

Sources: Resource and revision contracts; Save, publish, restore, preview and schedule services.

Content and design share one resource model

A resource is an item with a continuing identity: a Post, Page, Event, Vehicle, taxonomy term, template, section, menu, brand, settings record or author profile. Its revisions are the saved versions of that item. A revision includes the title and content plus relevant fields, relationships, visibility, layout and search-engine information. References use stable identifiers, so changing a label does not turn the relationship into a different item.

Each resource remembers its working revision and, when published, its published revision. History is preserved rather than rewritten in place. Restoring an older revision creates another working revision containing that older snapshot; it does not erase the intervening history or automatically replace the public version. This lets an editor inspect the restored result before making a publication decision. Retention can eventually remove eligible old history through a separate audited maintenance process.

Sources: Resource and revision contracts; Registered content types; Save, publish, restore, preview and schedule services.

Publication changes related records together

Publishing is more than changing a status label. The server checks your current authority, the exact saved revision, required fields, referenced items and route availability. It then changes the public revision, route records, public search entry, publication record and queued publication effect within one database transaction. Either those changes commit together or they are rolled back. A route collision or missing required dependency should leave the previous website intact.

A short site-level database lock coordinates changes that could otherwise make incompatible decisions at the same time. For example, one person must not withdraw a section while another person publishes a new page that requires it. This coordination is separate from the version check that catches two people saving from the same older revision. On a conflict, compare your local work with the newly saved version; repeatedly forcing the old request is not a reconciliation strategy.

Sources: Save, publish, restore, preview and schedule services; Transactional queue configuration; ORM Transaction Adapters.

A page uses a consistent public view

The public loader reads the page, applicable template and required shared resources from one read-only database snapshot. A publication that finishes during the request cannot make the first half of that request use one public state and the second half use another. PostgreSQL calls this transaction setting repeatable read. The CMS separately enforces which records are eligible to be public; the database isolation setting alone does not decide content permissions.

Archives and search use current public revisions, not whichever revision was edited most recently. Media files live outside the public application assets. The media endpoint checks whether the requested version is referenced by eligible public content or is available to the authenticated viewer. Uploading or replacing an image does not, by itself, publish it. Old revisions continue to point to the old immutable media version until their content is deliberately changed.

Sources: Public snapshot and query loader; Private media access and versioning; PostgreSQL 18: Transaction Isolation.

Preview and scheduling select exact revisions

A preview is a temporary selection of saved revisions layered over the published site. Only the chosen overrides are included; unrelated drafts remain excluded. Preview links expire after thirty minutes and require the account that created them. Treat them as your authenticated review session, not as anonymous links to distribute outside the workspace. Save the relevant work first, then create a new preview when the selected revision or expiry no longer matches your intention.

A schedule records the intended revision, due time and expected publication version. Later draft edits do not silently change the scheduled revision. The separate worker rechecks durable schedule state and current publishing authority before execution. Cancellation, revoked access, a conflicting dependency or a newer manual publication can prevent the old intention from publishing. Temporary infrastructure failures can be retried; a blocked publishing decision needs a person to resolve its stated cause.

Sources: Save, publish, restore, preview and schedule services; Worker execution and retry handling.

Use the right controls for your responsibility

Your role determines what you can create, edit, review and publish. Administrators manage the workspace; editors manage editorial resources; designers manage website design; authors and contributors have narrower ownership-based paths. The server reloads current account authority when processing changes, so an open browser tab does not preserve permissions after they have been revoked. API credentials also have scopes that can further restrict the account behind them.

Editors normally work entirely in the administration screens. Developers register new content types and component contracts in code. Operators maintain the database, media volume, worker, backups and deployment. Keeping these responsibilities clear makes problems easier to diagnose: an unpublished revision needs an editorial decision, a missing worker needs an operational fix, and a new field kind needs a compatible implementation and tests.

Sources: Role and capability policy; Save, publish, restore, preview and schedule services.

References

  1. Resource and revision contracts

    Repository path: apps/cms/src/cms/contracts.ts

  2. Registered content types

    Repository path: apps/cms/src/cms/definitions/index.ts

  3. Save, publish, restore, preview and schedule services

    Repository path: apps/cms/src/cms/services/content.ts

  4. Public snapshot and query loader

    Repository path: apps/cms/src/cms/services/public.ts

  5. Private media access and versioning

    Repository path: apps/cms/src/cms/services/media.ts

  6. Role and capability policy

    Repository path: apps/cms/src/cms/policy/index.ts

  7. Transactional queue configuration

    Repository path: apps/cms/src/cms/jobs/queue.ts

  8. Worker execution and retry handling

    Repository path: apps/cms/src/worker/handlers.ts

  9. PostgreSQL 18: Transaction Isolation

    Repeatable-read background; CMS access policy is implemented in the cited source.

  10. ORM Transaction Adapters

    Explains transaction-bound enqueue; the application pins 12.30.0, while this rolling documentation currently identifies 12.31.0.

Start here

Technology stack

A practical map of the libraries, processes and storage behind this installation.

One application, two long-running processes

The application combines the administration, authenticated APIs and public website in a Next.js App Router project. React supplies the user interface, and TypeScript describes the contracts used across forms, services and stored snapshots. Editors do not need to install these libraries separately: the deployed website already contains the appropriate browser code. Developers use the repository and its committed lockfile to build the matching server and browser output.

The production package runs a web process and a separate worker. Web handles requests; the worker executes scheduled publication and consumes publication-effect jobs. A separate one-off migration command prepares the database before either starts. The Docker web image uses Next.js standalone output, whereas the operations image retains TypeScript tooling for worker and maintenance commands. Both are built from the same dependency lockfile and run as a non-root user.

Sources: Pinned dependencies and commands; Web and operations image definitions; Production process and PostgreSQL configuration; Self-hosting Next.js.

Versions are pinned in the repository

Use these versions as the documented build baseline, not an instruction to replace individual dependencies with whichever version an external tutorial now uses. The Node engine accepts the 24.x series; the production Dockerfile pins a specific Node image. npm ci installs the lockfile rather than resolving a new combination. A future update should change the dependency files deliberately and repeat the relevant verification.

PartPinned baselineResponsibility
Node.js24.x; Docker 24.21.0Server JavaScript runtime
Next.js / React16.3.4 / 19.3.0Application routing and interface rendering
TypeScript6.0.3Compile-time contract checks
Puck0.23.0Visual composition editor
PostgreSQL18.6-bookwormPersistent content, identity and jobs
Drizzle ORM / Kit0.45.2 / 0.31.10Typed SQL access and migration generation
node-postgres / pg-boss8.23.0 / 12.30.0Database connection and durable job processing
Better Auth / Drizzle adapter1.7.4 / 1.7.4Authentication and session persistence
Sharp / sanitize-html / Zod0.35.4 / 2.17.7 / 4.6.1Image normalization, HTML sanitation and validation

Sources: Pinned dependencies and commands; Web and operations image definitions; Production process and PostgreSQL configuration.

PostgreSQL stores decisions as well as content

PostgreSQL holds resources, immutable revisions, taxonomy and media references, routes, publication history, review requests, schedules, account records and queue data. Drizzle expresses the relational schema and provides typed queries. Generated migrations are only part of the integrity model: the migration runner also installs custom pointer constraints, immutable-revision protection, search-vector infrastructure and runtime privilege restrictions. Reading only a generated SQL file would miss those additional contracts.

Published search uses a current-head projection. Publication updates that projection in the same transaction as the public revision, rather than asking search to examine every retained historical body. The public loader then combines eligible content with the relevant template and reference closure. This is a deliberate application design, not an automatic feature provided by choosing PostgreSQL or Drizzle. Preserve it when adding queries, migrations or alternative storage.

Sources: Relational CMS schema; Migration, integrity and privilege setup; Public eligibility and search queries; Drizzle schema declarations.

Editing libraries do not replace CMS policy

Puck supplies the interactive composition workspace. GroCMS supplies its supported components, fields, defaults and renderers, then validates the resulting saved document on the server. The same component configuration supports editing and published rendering. Adding a new visual block therefore requires more than drawing a control: its stored properties, validation, relationships and public rendering must agree. The native rich-text integration belongs to this controlled composition path.

Better Auth supplies the authentication integration, while GroCMS adds invitations, role checks, disabled-account handling and scoped API authority around the application services. A session identifies an account; it does not grant every action. Current authority is checked at the point of use. Likewise, Sharp can normalize an uploaded image, but the CMS decides which media version may be delivered publicly and which retained revisions protect it from deletion.

Sources: Shared Puck component configuration; Server-side content validation; Authentication integration contract; Getting Started; Next.js integration.

Different checks prove different properties

Vitest exercises the domain and real PostgreSQL integration boundaries. Playwright and axe-based checks cover browser behavior and automated accessibility findings. The npm run verify command performs type checking, linting, tests and a production build; it does not automatically reproduce every browser, recovery or load exercise. Those have separate commands and evidence. A build passing without a live database is useful packaging evidence, but it does not prove a running deployment is ready.

The 11 September 2026 engineering run used 20 readers for ten minutes under the documented four-CPU/eight-GiB allocation. The 10,000-record fixture completed 116,090 HTML responses with a 119 ms p95 and no errors. Following query improvements, the 100,000-record fixture completed 29,432 responses without errors, but its 778 ms p95 still missed the 750 ms target. A separate phrase-heavy search workload reached 2.196 seconds p95. These results do not establish a supported 100,000-record tier. A tested local restore likewise does not establish off-host recovery or an ongoing recovery-point commitment. Independent agency installation and real-site trials remain pending.

For an upgrade, start from the pinned baseline, read the affected upstream migration guidance and preserve old stored-document compatibility. Re-run the tests that could detect lost revisions, incorrect permissions, draft exposure, stale schedules or broken media. Record the new image and source revision with the evidence. Package names explain responsibilities; the code and measured checks establish what this installation actually supports.

Sources: Pinned dependencies and commands; Verification and acceptance evidence; Measured performance and limits; Executed operations and recovery evidence.

References

  1. Pinned dependencies and commands

    Repository path: apps/cms/package.json

    Application baseline 9e608fe; the lockfile records the resolved dependency tree.

  2. Web and operations image definitions

    Repository path: Dockerfile

  3. Production process and PostgreSQL configuration

    Repository path: compose.yaml

  4. Relational CMS schema

    Repository path: apps/cms/src/cms/db/schema.ts

  5. Migration, integrity and privilege setup

    Repository path: apps/cms/scripts/migrate.ts

  6. Public eligibility and search queries

    Repository path: apps/cms/src/cms/services/public.ts

  7. Shared Puck component configuration

    Repository path: apps/cms/src/cms/components/config.tsx

  8. Server-side content validation

    Repository path: apps/cms/src/cms/validation.ts

  9. Authentication integration contract

    Repository path: apps/cms/src/cms/auth/README.md

  10. Verification and acceptance evidence

    Repository path: docs/build-status.md

  11. Measured performance and limits

    Repository path: docs/evidence/performance.md

  12. Executed operations and recovery evidence

    Repository path: docs/evidence/operations-runtime.md

  13. Self-hosting Next.js

    Framework background; application-specific packaging comes from Dockerfile.

  14. Drizzle schema declarations
  15. Getting Started
  16. Next.js integration

Start here

Glossary

Plain-language definitions of the terms used in the CMS and these guides.

Content and identity

TermMeaning
ResourceA stable record such as a page, post, template, shared section, menu, brand, settings record, term or author profile. Its identity stays the same across edits.
Content typeA registered definition of fields and behaviour for entries. Posts and Pages are the protected defaults; administrators can create custom types and manage retired types separately.
SlugThe URL-friendly identifier used in a public route. It is not the same as the entry’s display title or immutable resource ID.
Taxonomy / termA classification system, such as Categories or Tags, and one item within it. A post can refer to terms.
Author profile / personAn author profile supplies public attribution. A person is a login account with a role. They can be linked but are separate records.
Media assetAn uploaded image or supported document plus metadata. Content references its stable ID; the file bytes live in managed media storage.

Sources: Core content contracts; Registered content definitions; Database schema.

Editing and publication

TermMeaning
Revision / snapshotAn immutable saved version of a resource’s content and layout.
Working revisionThe current editable version. Saving makes a new revision and moves this pointer.
Published revisionThe version selected for publication. It can differ from the working revision.
Public / PrivateVisibility choices. A private item may have a published revision without being exposed as an anonymous public page.
Pinned revisionThe specific saved version attached to a review, schedule or preview. Later edits do not silently replace it.
PreviewAn authenticated, permission-checked rendering selected by a preview token that can include specified draft revisions. Possessing the link alone does not grant anonymous access or publish the draft.
DependencyAnother record required by content, for example a referenced shared section, menu or media asset. Publication checks these relationships.
ConflictA rejected change because the expected version no longer matches current state, often after another editor saves or publishes.
RestoreRecover an older revision as working content. This does not automatically publish it.

Sources: Core content contracts; Revision and publication workflow.

Website design

TermMeaning
CompositionA saved arrangement of visual blocks and their settings. A page’s own composition overrides inherited template design, even when it is empty.
PuckThe visual-editor library used for the block canvas and component property controls.
TemplateA reusable layout selected for a page, content type or public route context.
ContentBodyA dynamic block that renders the current entry’s rich-text body inside a composition.
Shared sectionA separately managed design resource used by reference in multiple places. A copied set of blocks no longer has that shared link.
QueryLoopThe Content collection block. It selects eligible published entries by content-type key with a limit of 1–24 and an optional heading; its card presentation is defined in code.
Brand tokensThe supported identity, color, font and logo values stored by Brand & theme. Spacing and many component colors remain defined in the stylesheet rather than editable brand tokens.

Sources: Visual component configuration; Public rendering data resolution; Supported brand token controls; Public component styles and theme limits.

Setup and operations

TermMeaning
Web process / workerThe web process handles requests. The separate worker handles queued and scheduled background work.
PostgreSQL / DrizzlePostgreSQL stores the CMS data. Drizzle provides typed database access and migration tooling.
MigrationA controlled database-schema update run with the deployment’s migration role.
API scopeAn action allowed by a particular integration token, intersected with its owner’s current permissions.
Idempotency keyA request identifier used to recognize a retried operation and avoid applying it twice.
SMTP / MailpitSMTP sends account emails. Mailpit is the local mail-capture service for development and testing.
Backup / exportA full recovery backup includes the database and media files. The content JSON export is a smaller portability package.
RPO / RTORecovery point objective describes acceptable data loss in time. Recovery time objective describes acceptable restoration time. Targets require tested operational procedures.

Sources: Operational terminology and recovery; Deployment services.

References

  1. Core content contracts

    Repository path: apps/cms/src/cms/contracts.ts

  2. Registered content definitions

    Repository path: apps/cms/src/cms/definitions/index.ts

  3. Database schema

    Repository path: apps/cms/src/cms/db/schema.ts

  4. Revision and publication workflow

    Repository path: apps/cms/src/cms/services/content.ts

  5. Visual component configuration

    Repository path: apps/cms/src/cms/components/config.tsx

  6. Supported brand token controls

    Repository path: apps/cms/src/components/admin/brand-fields.tsx

  7. Public component styles and theme limits

    Repository path: apps/cms/src/app/globals.css

  8. Public rendering data resolution

    Repository path: apps/cms/src/cms/services/public.ts

  9. Operational terminology and recovery

    Repository path: docs/operations.md

  10. Deployment services

    Repository path: compose.yaml

Start here

Overview

Read your workspace summary, find unfinished work and choose the right next screen.

What Overview is for

Overview is the starting screen after you sign in. It brings together the content you can access, work waiting for review, scheduled publications and shortcuts into the library. Use it to decide what to work on next. It does not change the public website, publish anything or replace the detailed lists behind each number.

The greeting uses your account name. The date describes today in the browser. Recently edited shows up to six recently updated content entries you are allowed to read. Its shortcut opens the full list, newest updates first. These may include other people's work when your role permits it; creation and publication also update this order. Templates, brand settings and author profiles are managed in their own screens rather than appearing as ordinary recent content.

Sources: Overview screen; Overview and workflow queries.

Understand the numbers

LabelWhat it counts
Pieces of contentAccessible Pages, Posts and other registered content entries, excluding trash.
PublishedEntries with a published version, including publications marked private.
DraftsEntries with no published version. A published entry with newer edits still belongs in Published.
ScheduledPending scheduled intentions you can see. Their content may already have an older published version.
Awaiting reviewPending submitted revisions visible to your account, excluding content in Trash. A pending submission becomes available again if its content is restored.
Assets in your libraryUploads visible under the same permissions as your media library, including public assets available for reuse.

These numbers answer different questions and are not all mutually exclusive. A published Post may also have a pending review and a future schedule. The Drafts number is therefore not a count of every unpublished edit. Open a content list and choose Changes to find entries whose working version differs from their published version.

Sources: Overview screen; Overview and workflow queries; Content and publication service.

A practical starting routine

  1. Open Overview and use My drafts for unpublished content created by your login account. Use Awaiting review for pending submissions or Scheduled to publish for future work.
  2. Choose a title in Recently edited to return to that entry's working draft. Check its saved-state message before continuing.
  3. Choose View all content for the searchable list. Use the relevant collection in the sidebar when you already know whether you need a Page, Post, Event or Vehicle.
  4. Choose Create content to open the title and type form. Only types your role can create are offered. Choose Create & open editor to save a new draft and open it; cancelling creates nothing. Designers have a Create shared section action instead.
  5. Use Open your pages for permanent website pages, and Make it yours for the brand workspace if your role permits design work.

Published and Drafts open their corresponding status-filtered lists. My drafts also sets Created by to Me. Search, status, creator and page stay in the URL, so bookmarks, reload, Back/Forward and the editor's return link preserve the view. Recently edited uses the full list's newest-update order, with no date cutoff.

For example, an editor preparing a weekly update might inspect two waiting reviews, confirm tomorrow's scheduled announcement, then reopen a recent Post. An author may see only their own Posts and profile-related work. The differing totals are expected: GroCMS filters access before showing counts and rows.

Sources: Overview screen; Content lists and creation dialogs; Resource editor.

Interpret recent entries and empty screens

Recent titles come from the working draft. The address below a title may still describe its current published route. After changing a title or slug, this difference is useful: it tells you that the latest editing state and the visitor-facing version can be different. Open the entry and use Preview for the saved draft or View published content for the current publication.

A fresh installation starts with one Hello world! Post and one Welcome Page used as the homepage. The recent list can be empty after those placeholders are removed, or because your role does not expose other people's content. If expected work is missing, check the correct collection and Trash filter, then ask an administrator whether your account has the intended access.

The asset count follows your library permissions; it is not a storage-usage report. If loading fails, use Try again; signing in again may be necessary after a session expires or an administrator changes your access.

Sources: Overview screen; Content and publication service; Resource permission policy.

Continue from here

Sources: Overview screen.

Follow up on website enquiries

When the operator enables enquiries, administrators have an Enquiries screen at /admin/enquiries. This is separate from content review. Search by name, email, organisation or message; filter New, Contacted or Closed; and use the page controls to reach older requests. Open a request to read it and update its status as you follow up. Editors and other roles cannot read the inbox.

A visitor's confirmation means their demo or quote request was saved. Email notification is separate: the detail view shows notification state, attempts and any delivery error. Retry is available for a failed notification. The worker sends notifications to the operator's configured address and uses the visitor's validated email as Reply-To. An ambiguous SMTP failure can produce a duplicate message; the saved enquiry remains the record to work from.

There is no automatic enquiry deletion. Administrators can permanently delete a request after confirmation; this removes its stored personal fields, while the audit keeps only the action and record identifier. Deletion cannot remove an email already delivered to a mailbox or a copy already held in a backup. Use the site's privacy and retention process when deciding what to keep.

Sources: Optional enquiry inbox and delivery rules; Administrator enquiry inbox.

References

  1. Overview screen

    Repository path: apps/cms/src/components/admin/dashboard.tsx

    Current labels, shortcuts and six-entry recent-content table.

  2. Overview and workflow queries

    Repository path: apps/cms/src/cms/services/management.ts

    Permission-filtered counts, review decisions, queue search and pagination.

  3. Content lists and creation dialogs

    Repository path: apps/cms/src/components/admin/content-list.tsx

    Search, status filters, selection, pagination and creation controls.

  4. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  5. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  6. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  7. Optional enquiry inbox and delivery rules

    Repository path: apps/cms/src/cms/services/enquiries.ts

    Private demo/quote submissions, administrator access, notification state and deletion.

  8. Administrator enquiry inbox

    Repository path: apps/cms/src/components/admin/enquiries-panel.tsx

Content

Pages

Create permanent website pages, manage their addresses and publish changes deliberately.

When to use a Page

Use Pages for durable parts of the website, such as About, Contact, Services or a programme description. A Page can sit beneath another Page, giving visitors a meaningful address such as /services/training. Posts suit ongoing stories and announcements and have their own Journal collection. Choosing a Page does not automatically place it in the navigation or make it the homepage.

Administrators and editors create, edit and publish Pages. Designers can read ordinary content but cannot rewrite or publish it through their design role. Authors and contributors work with their own Posts rather than managing Pages. If the editor says you have read-only access, its disabled fields are intentional; an administrator must change responsibility or access.

Sources: Content types and taxonomies; Resource permission policy.

Create and fill in a Page

  1. Open Pages and choose New Page. On an empty list, Create Page opens the same dialog.
  2. Enter a recognisable Title, then choose Create & open editor. The new entry is a draft.
  3. In Content, fill in the title, Address / slug, Excerpt and Body. Use the body toolbar for supported formatting and links. Internal links open in the current tab; use the browser's Open in new tab command or Ctrl/Cmd-click when you deliberately want another tab.
  4. In Organization, choose a Parent page only when the address should sit beneath another Page. Select an appropriate Template or leave the normal fallback in place.
  5. Choose a Featured image if the design uses one. Search the selection dialog and move between result pages to find older assets.
  6. Check SEO & visibility, wait for the saved-state message, then Preview. Publish when the saved version is ready for visitors.
FieldPurpose
TitleThe page's editorial name and default heading/search-title source.
Address / slugThe final address segment, such as training. A parent supplies preceding segments.
ExcerptA short introduction available to listings, search presentation and connected components.
BodyThe main written content, distinct from a visual composition or shared template.
SEO title / descriptionOptional search-appearance wording; the preview falls back to the title and excerpt.
VisibilityPublic permits anonymous website delivery after publication; Private excludes public routes.

Sources: Content lists and creation dialogs; Resource editor; Reference selection dialog.

Parents, addresses and navigation

A parent relationship affects the published address. For example, publish Services with the slug services, then publish Training beneath it with the slug training. The child resolves at /services/training. Publish required parents before children. GroCMS prevents circular parent relationships and refuses an address already claimed by another live resource or a reserved application route.

Saving a different parent or slug only changes the draft. Publishing that change moves the page, updates the paths of published descendants and records redirects from previous addresses. A child's unrelated draft slug or parent change does not become public just because its parent moves. It still needs its own publication.

Page hierarchy and navigation are separate. Moving Training beneath Services does not edit the Navigation menu's ordering. To place a link in the menu, edit and publish the menu. Likewise, choose the homepage in Site settings and publish those settings; naming a Page Home does not assign the homepage by itself.

Sources: Content and publication service; Published-content integration tests; Content types and taxonomies.

Save, preview and recover work

Autosave creates a working revision after a pause. Save changes is available when unsaved edits remain. The current website continues using its published revision. A disabled Preview or Publish button usually means saving, conflicting changes, unresolved date input or an unavailable component needs attention first. Preview shows the saved draft and requires your own signed-in account; it is not an anonymous approval link.

Leaving unsaved work through administration links offers Stay, Save and leave, or Discard unsaved changes. Saving must succeed before navigation continues. A temporary recovery copy is kept in the current browser tab, scoped to your account and site. After a reload or Back/Forward navigation, GroCMS checks your access before offering recovery. If the server revision advanced, compare or download the tab copy rather than silently replacing newer work. Explicit logout clears recovery. Browser storage and mobile exit warnings are not a durable backup.

Publish and Schedule publication open saved-revision checks before confirmation. The panel shows content/dependency problems, a readable revision comparison and direct published references visible to your account. It does not preflight route availability, descendant URLs or complete rendering impact. Final publication rechecks current permissions, dependencies, conflicts and URLs; intervening changes can still block it.

To create an individual layout, choose Add a custom page composition. This opens the full-window Visual editor in the current tab. Back to content returns to the entry's fields. Ordinary writing can stay in Body and use the site's published template. Avoid adding a custom composition simply to change a sentence; it introduces a separate layout to maintain.

If another edit wins first, choose Download my changes before Load latest, then reconcile the text. Revision history compares readable text, fields, references, SEO and layout blocks between saved versions. Formatting-only changes are indicated separately; large values have a download fallback. Restore as working draft creates a new draft without immediately replacing the public page or rewinding shared categories, templates or sections. Comparison never merges or restores automatically.

Sources: Resource editor; Content and publication service; Editor browser journeys; Published-content integration tests.

Find, withdraw and troubleshoot Pages

The list searches working titles. Published includes entries with a published version, Drafts means no published version, Changes means newer working edits, and Trash shows removed entries. A displayed draft slug is not proof that the public route exists. Use the published-content link in the editor to check the actual page.

Unpublish content removes public delivery while retaining the draft and history. Move to trash also hides the entry from ordinary lists. Restore returns a trashed Page to editing; publication is a separate action. Required dependencies can block withdrawal, so resolve the named dependent content instead of repeatedly retrying.

For several Pages, select entries on the current list page, choose a bulk action and Review action. Check each result: permission or dependency failures can leave some entries unchanged while others succeed. Export selected downloads the selected working snapshots, not a whole-site backup.

Sources: Content lists and creation dialogs; Bulk actions; Content and publication service.

References

  1. Content types and taxonomies

    Repository path: apps/cms/src/cms/definitions/index.ts

    Pages, Posts, Events, Vehicles and their allowed classifications.

  2. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  3. Content lists and creation dialogs

    Repository path: apps/cms/src/components/admin/content-list.tsx

    Search, status filters, selection, pagination and creation controls.

  4. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  5. Reference selection dialog

    Repository path: apps/cms/src/components/admin/reference-picker.tsx

    Search, taxonomy selector, multiple selection and older result pages.

  6. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  7. Published-content integration tests

    Repository path: apps/cms/tests/integration/public.test.ts

    Page moves, redirects, publication isolation, taxonomy queries and historical restore.

  8. Editor browser journeys

    Repository path: apps/cms/tests/editor-browser.ts

    Actual autosave, conflict recovery, rich text, media replacement and older selections.

  9. Bulk actions

    Repository path: apps/cms/src/components/admin/bulk-actions.tsx

    Per-entry decisions, saved-revision publication and selected-snapshot downloads.

Content

Posts

Write and organise stories, understand authorship and choose publication or review.

What a Post represents

Posts hold stories, perspectives and announcements. The current website gives them the Journal collection, with individual addresses such as /journal/new-studio. Unlike Pages, Posts do not form a parent-and-child page tree. They can use Categories and Tags to connect related writing, and an author profile can supply the public byline.

Administrators and editors manage the team's Posts. Authors create, edit and publish their own Posts. Contributors write and submit their own unpublished Posts but cannot publish them. Once a contributor's Post has a published version, the current policy no longer grants that contributor editing access to it. Ask an editor to make subsequent changes or review the account's intended role.

Sources: Content types and taxonomies; Resource permission policy; Resource editor.

Write your first Post

  1. Open Posts and choose New Post, or Create Post on an empty list. Enter a working title and choose Create & open editor.
  2. In Content, refine Title and Address / slug. Write an Excerpt that introduces the story and put the full article in Body.
  3. Use the body toolbar for headings, emphasis and lists. To insert a named link, select its text, choose Link, enter a safe destination and choose Apply link.
  4. Choose a Featured image when your layout needs one. Add Categories & tags in Organization; the dialog's Taxonomy selector switches between the allowed groups.
  5. Check Author profile, SEO & visibility and the saved-state message. Preview the saved article before deciding to Publish or Submit for review.

The default Post definition has no extra structured detail fields. Its core writing fields are enough for an ordinary article. Body is the canonical article text; a custom visual composition is optional. A designer can supply a shared template that displays the title, byline, image and body consistently across Posts.

Sources: Content lists and creation dialogs; Resource editor; Reference selection dialog.

Choose the supporting information

ControlWhat to decide
ExcerptA short introduction, not a second copy of the full body.
Featured imageThe exact library image version the published article should use.
Author profileThe public identity for the byline; this is separate from the login account that owns the entry.
Categories & tagsShared classifications selected from the groups allowed for Posts.
TemplateAn optional compatible layout override; the normal site template works when none is chosen.
SEO & visibilitySearch-title/description wording and whether a publication is public or private.

Authors and contributors may select only their own published profile, or clear attribution. New content automatically uses their own published public profile when one exists. Administrators and editors can assign other profiles. Changing a byline does not transfer ownership of the Post or grant that profile's person permission to edit it.

Some fields remain restricted even on an otherwise editable Post. Authors and contributors cannot change visibility, template or parent references. The server rejects those changes. If the work needs a different layout or privacy setting, ask an editor. Contributors also lack library upload/browsing capability, so an editor may need to handle the images.

Sources: Resource editor; Content and publication service; Content types and taxonomies; Authority and media integration tests.

Choose what happens after saving

Saving updates the working draft; publishing chooses a saved revision for the website. A revised headline, body, slug or classification stays private until publication, even when an older version is already live. Preview is tied to your account and expires after 30 minutes. It cannot be shared as a public link with someone who has no access.

A contributor sees Submit for review. That action pins the exact saved revision. Later edits do not alter the submission; submit again when the replacement is ready. A person with publication capability sees Publish in the normal editor instead of a separate submission button. Approval is not a universal prerequisite for an author or editor who already has permission to publish.

For example, submit an announcement on Monday, then draft a new quotation on Tuesday. The reviewer can publish Monday's approved version while Tuesday's quotation remains in the working draft. If timing matters, an authorised publisher can schedule a saved revision rather than relying on someone opening the website at the intended time.

Sources: Resource editor; Content and publication service; Two-role review browser journey; Published-content integration tests.

Resolve common writing problems

Watch Saving changes, Unsaved changes and Saved before leaving. When another editor has saved first, automatic saving stops rather than overwriting their work. Download my changes preserves your local snapshot; Load latest replaces the editor with the current saved version. Reapply only the changes you still intend after comparing them.

If the article is missing from Journal, check that it is published, public and outside Trash. If your draft headline is visible in administration but visitors see the old one, that is expected draft isolation. If Categories or Author profile are unavailable, publish the required linked records first through an authorised editor.

Use Changes to find published Posts with later edits and Revision history to recover earlier writing. Unpublish content withdraws the article; Move to trash also removes it from the ordinary list. Bulk actions apply to the named selection on the current page and report individual failures. Read every result before assuming the whole selection changed.

Sources: Resource editor; Editor browser journeys; Content lists and creation dialogs; Bulk actions.

References

  1. Content types and taxonomies

    Repository path: apps/cms/src/cms/definitions/index.ts

    Pages, Posts, Events, Vehicles and their allowed classifications.

  2. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  3. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  4. Content lists and creation dialogs

    Repository path: apps/cms/src/components/admin/content-list.tsx

    Search, status filters, selection, pagination and creation controls.

  5. Reference selection dialog

    Repository path: apps/cms/src/components/admin/reference-picker.tsx

    Search, taxonomy selector, multiple selection and older result pages.

  6. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  7. Authority and media integration tests

    Repository path: apps/cms/tests/auth-authority.integration.test.ts

    Own profiles, media versions, page traversal, private references and account revocation.

  8. Two-role review browser journey

    Repository path: apps/cms/tests/review-browser.ts

    Contributor submission and editor publication of the exact reviewed revision.

  9. Published-content integration tests

    Repository path: apps/cms/tests/integration/public.test.ts

    Page moves, redirects, publication isolation, taxonomy queries and historical restore.

  10. Editor browser journeys

    Repository path: apps/cms/tests/editor-browser.ts

    Actual autosave, conflict recovery, rich text, media replacement and older selections.

  11. Bulk actions

    Repository path: apps/cms/src/components/admin/bulk-actions.tsx

    Per-entry decisions, saved-revision publication and selected-snapshot downloads.

Content

Media library

Upload, find and replace images, documents and fonts without changing existing published uses.

What the library stores

The Media library stores images, PDF documents and WOFF2 font files used by content and site design. Uploading a file creates a reusable asset with its own identity. It does not automatically put that asset onto a page or make it publicly downloadable. A content entry, composition or design resource must refer to the chosen asset version.

Administrators, editors, authors and designers have media capability; contributors do not. Administrators and editors can browse site media. Other permitted roles can browse their own assets and eligible publicly used assets. Only administrators and designers can upload WOFF2 fonts. Seeing a public asset does not automatically grant the right to replace its metadata.

Sources: Media library screen; Media storage and access rules; Resource permission policy.

Upload and find files

  1. Open Media library and choose Upload files.
  2. Choose one or more JPEG, PNG, WebP, PDF or WOFF2 files. Keep each file within the stated 15 MB limit; font uploads also require the appropriate role.
  3. Choose Add to library and wait for the result. If one file fails, inspect the refreshed library before retrying: earlier files in that batch may already have uploaded.
  4. Search by the asset's name and use the previous/next media page controls for older uploads. The library shows 50 results per page.
  5. Open an asset card to inspect its type, size, upload date, dimensions when available, Asset URL and Media ID.

Accepted images are normalised to WebP, rotated according to their image metadata and reduced to fit within 2,400 pixels without enlargement. Very large pixel dimensions or malformed image data can be rejected even when the file size is small. Keep an original outside the CMS when you need its original format or full resolution for print.

Copy URL gives you the delivery address, while Copy ID gives the internal asset reference used by integrations. Ordinary authors should select assets through Featured image, Image or font controls rather than pasting identifiers into text. PDF delivery is a download, not an embedded document viewer.

Sources: Media library screen; Media storage and access rules.

Edit a name, alternative text or file

  1. Open the asset and choose Edit / replace.
  2. Set Name to a useful library label. Alternative text describes meaningful image content for people who cannot see it.
  3. Leave Replacement file (optional) empty to keep the exact file bytes with the new metadata, or choose a replacement file.
  4. Choose Create new version. The result has a different Media ID, even when only the name or alternative text changed.
  5. Open each entry that should use the replacement, select the new asset, save and publish that entry when ready.

This deliberate extra selection protects existing work. Changing the alternative text of a photograph does not silently rewrite a published article or its history. Existing references continue to use the previous version's name, alternative text and bytes. The new version starts private and is not an automatic replacement everywhere the old file appears.

For example, replace a poster containing last year's date with the corrected poster. The old event page remains reproducible until you choose the new poster in the event's draft and publish it. If only the asset name needs tidying, the new version still needs to be selected where you want that new metadata to apply.

Sources: Media replacement dialog; Media storage and access rules; Authority and media integration tests.

Understand private and public delivery

Anonymous visitors can fetch an asset only while an eligible current public publication refers to it. Your authenticated access may let you preview a private upload, so a URL working in your own browser does not prove that it works for visitors. A newly created replacement will fail for anonymous visitors until a public use selects its new ID.

If a file is used by both a public and a private entry, the public use makes that exact file available publicly. Marking one referencing entry private does not conceal bytes still used elsewhere publicly. Withdrawing the last public use removes anonymous delivery for subsequent requests; it cannot recall a file someone already downloaded.

Sources: Media storage and access rules; Authority and media integration tests.

Selection and upload problems

An image picker filters to image files and a font picker filters to fonts before pagination. A PDF therefore will not appear as a valid featured image. Previously selected older assets are resolved by their exact ID even when they are outside the visible result page. Search another page before assuming an older upload has disappeared.

Replacement is allowed for the owner or an administrator/editor with site access. A designer editing someone else's private upload may receive an access error. Unsupported SVG, HTML and other active file formats are outside the upload allowlist. If copying fails because the browser blocks clipboard access, select the displayed ID or URL and copy it manually.

Sources: Media library screen; Media replacement dialog; Media storage and access rules; Editor browser journeys.

References

  1. Media library screen

    Repository path: apps/cms/src/components/admin/media-library.tsx

    Batch upload, search, pages and media details; no delete button is provided.

  2. Media replacement dialog

    Repository path: apps/cms/src/components/admin/media-version-form.tsx

    Name, alternative text and optional replacement file create a new version.

  3. Media storage and access rules

    Repository path: apps/cms/src/cms/services/media.ts

    File validation, normalisation, immutable versions, private delivery and retained-reference deletion protection.

  4. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  5. Authority and media integration tests

    Repository path: apps/cms/tests/auth-authority.integration.test.ts

    Own profiles, media versions, page traversal, private references and account revocation.

  6. Editor browser journeys

    Repository path: apps/cms/tests/editor-browser.ts

    Actual autosave, conflict recovery, rich text, media replacement and older selections.

Content

Categories & tags

Create reusable classifications and connect published content without duplicating it.

Categories, tags and terms

A classification connects related content. A taxonomy is the group, such as Categories or Tags; a term is an individual entry in that group, such as Research or Community. One published Post can belong to several terms without being copied into several separate articles. Term pages provide a way for visitors to discover related published content.

An editorial convention is to use Categories for broad subjects and Tags for more specific topics. Agree useful names with the team before creating many similar entries. The application does not infer these meanings from a word: a term called News only belongs to Categories if you create it in that taxonomy.

Content typeAvailable classifications
PostsCategories and Tags.
EventsCategories and Tags.
VehiclesManufacturers and Tags.
PagesNo taxonomy assignments in the supplied definition.

Sources: Content types and taxonomies; Public content and archive selection.

Create and publish a term

  1. Open Categories & tags and choose New term, or Create term when the list is empty.
  2. Enter the Title and choose the Taxonomy: Category, Tag or Manufacturer. Then choose Create & open editor.
  3. In Details, refine Title and Address / slug. Add Description to explain the subject or introduce its archive.
  4. Review SEO & visibility, save and Preview where appropriate. Choose Publish to make the term available as a public classification page.
  5. Return to the relevant Post, Event or Vehicle and select that term in its Categories & tags control. Save and publish the content separately.

Administrators and editors manage and publish terms. Authors and contributors can read terms for classification but cannot create, rename or publish them. Designers can read classifications while working with content display. A missing New term or Publish control therefore does not mean that creating classifications is broken; it may be outside your role.

Sources: Content lists and creation dialogs; Resource editor; Content and publication service; Resource permission policy.

Select terms on content

In a content editor's Organization area, choose or change Categories & tags. The selection dialog has Search entries, a Taxonomy selector when more than one group is available, checkboxes and previous/next result pages. Select the required entries, switch taxonomy if needed, then choose the Use selected button, which includes the number of selected entries. Existing selections can span the available taxonomy groups.

The picker shows a term's saved title and status, so it can include a draft term you are allowed to read. Selecting a draft term does not publish it. An eligible public term must be published before public content can depend on it. If publication reports an unavailable or unpublished classification, an editor should resolve that term first.

For example, a Post about an exhibition could use Arts as its Category and Exhibition as a Tag. An Event about the same exhibition can use those same terms. Vehicles instead offer Manufacturers and Tags. The server rejects a classification belonging to a taxonomy that the content type does not support.

Sources: Reference selection dialog; Resource editor; Content and publication service.

How changes affect visitors

Each term has a working draft and a separate published version. Renaming a term or editing its Description stays private until that term is published. Changing a Post's selected terms also stays private until the Post is published. This lets you prepare a classification change without unexpectedly moving a live article between public archives.

Published Category pages use addresses such as /category/research; Tags use /tag/research and Manufacturers use /manufacturer/example. The same word in a different taxonomy is a separate classification. Archives select eligible published public content and avoid duplicate entries when several matching relationships lead to the same item.

Sources: Content and publication service; Public content and archive selection; Published-content integration tests.

Keep classifications useful

Search the list before adding a near-duplicate such as Community event when Community events already exists. Search examines working titles; the Type column identifies the taxonomy. Published, Drafts, Changes and Trash filters have the same meanings as other resource lists, and previous/next pages reach older terms.

A term may be impossible to withdraw while published content depends on it. Reclassify those entries and publish the changes first, then withdraw the old term. Merely removing it from a current draft does not alter the live dependency. Restoring an older article revision also does not rewind the term's separately published wording.

If a term archive looks empty, confirm that both the term and its assigned content are published and public. A draft assignment is not enough. If the description appears differently than expected, the active taxonomy/archive template controls its presentation. Classifications supply content and relationships; templates decide how the archive is drawn.

Sources: Content lists and creation dialogs; Content and publication service; Published-content integration tests.

References

  1. Content types and taxonomies

    Repository path: apps/cms/src/cms/definitions/index.ts

    Pages, Posts, Events, Vehicles and their allowed classifications.

  2. Public content and archive selection

    Repository path: apps/cms/src/cms/services/public.ts

    Published taxonomy descendants, profile archives and public visibility.

  3. Content lists and creation dialogs

    Repository path: apps/cms/src/components/admin/content-list.tsx

    Search, status filters, selection, pagination and creation controls.

  4. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  5. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  6. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  7. Reference selection dialog

    Repository path: apps/cms/src/components/admin/reference-picker.tsx

    Search, taxonomy selector, multiple selection and older result pages.

  8. Published-content integration tests

    Repository path: apps/cms/tests/integration/public.test.ts

    Page moves, redirects, publication isolation, taxonomy queries and historical restore.

Content

Authors

Manage public names and biographies separately from staff login accounts and content ownership.

Public identity and login identity

Authors manages public author profiles: the name, biography and profile page that can accompany published content. People manages login accounts, roles and access. They are separate parts of GroCMS. Creating a profile does not invite someone, set a password or give them editorial permission. Changing an account's name is not the same as publishing a revised public biography.

A Post also has an owner: the login account that created the resource. Selecting a different Author profile changes public attribution, not that ownership. For example, an editor may prepare an article with a colleague's byline while the editor remains its creator. The byline does not transfer access to the colleague's login.

Sources: Content and publication service; Resource editor; Resource permission policy.

Create your own profile

  1. Open Authors. Choose New profile, or Create profile if the list is empty.
  2. Enter the public name as Title and choose Create & open editor.
  3. In Details, set a clear Address / slug, a short Excerpt and the full biography in Body.
  4. Check the saved-state message. Use Preview to inspect the saved profile when your role permits it.
  5. As an author or contributor, choose Submit for review. An editor or administrator can assess and publish the profile.
FieldMeaning for a profile
TitleThe public author name used when the profile is displayed.
Address / slugThe profile address segment, normally under /authors/.
ExcerptA short introduction that the active design may use.
BodyThe biography written with the supported rich-text controls.
SEO & visibilitySearch presentation and public/private publication settings, subject to role restrictions.

An author or contributor can create one active profile for their own account. If a second creation fails, find the existing profile rather than making another spelling of the same person. The restriction concerns active, non-trashed profiles. It is not a general limit of one profile for the entire site.

Sources: Content lists and creation dialogs; Resource editor; Content and publication service; Profile and older-page browser journeys.

Who can change a profile

Administrators and editors manage profiles across the site and control publication. Authors and contributors can create, read, edit, preview and submit their own profile; they cannot publish it. Designers can read profiles to understand their presentation but see read-only fields rather than biography-editing controls.

For self-service editing, let the author create the profile while signed in to their own account. A profile created by an administrator belongs to that administrator's resource ownership; the current Authors screen has no ownership-transfer control. An administrator-created profile is therefore not automatically self-editable by a person whose name happens to match its title.

If a team member cannot find or edit their expected profile, first distinguish a public attribution problem from an account permission problem. People can verify their login role. Authors can verify which profile exists. Do not solve the issue by sharing another person's password or assuming that matching email/name text grants ownership.

Sources: Resource permission policy; Content and publication service; Authority and media integration tests; Profile and older-page browser journeys.

Use the profile on content

After an editor publishes a public profile, it can be selected in a content entry's Author profile control. Authors and contributors may choose their own published public profile or clear attribution. Administrators and editors may assign other eligible profiles. New content automatically selects the creator's own published public profile when one is available; existing articles are not all reassigned automatically.

For example, create a profile titled Naledi Dlamini, write and submit its biography, and have an editor publish it. A later new Post created by that account can default to Naledi's profile. If the profile is still a draft, publish it first instead of expecting a draft biography to be displayed publicly with the Post.

The public profile route gathers eligible published content attributed to the profile. Its visible layout depends on the site's template. A published profile can be present even when there are no public attributed articles yet. Assigning an author in a draft Post does not move the Post into that public profile listing until the Post is published.

Sources: Resource editor; Content and publication service; Public content and archive selection; Authority and media integration tests.

Revise and recover a biography

Saving a new name or biography creates a profile draft and preserves the current public version. Submit the revised profile for editorial publication. The unchanged public byline and biography are intentional: profile changes have their own approval/publication decision rather than silently changing every published consumer during typing.

Revision history can restore an older profile snapshot as a new working draft. It does not publish that snapshot immediately. A profile needed by published content may be protected against withdrawal; change the dependent content first. If an author cannot remove their own profile, ask an editor because self-profile access does not include every lifecycle action.

Finally, distinguish presentation from missing data. A template may show only the profile title and related articles, while another displays the biography. Preview and inspect the published page before rewriting fields to compensate for a design choice. The profile supplies identity; the template controls which parts visitors see.

Sources: Resource editor; Content and publication service; Published-content integration tests; Authority and media integration tests.

References

  1. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  2. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  3. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  4. Content lists and creation dialogs

    Repository path: apps/cms/src/components/admin/content-list.tsx

    Search, status filters, selection, pagination and creation controls.

  5. Profile and older-page browser journeys

    Repository path: apps/cms/tests/admin-pagination-browser.ts

    Author profile creation and body save/reload, designer read-only access and older workflow entries.

  6. Authority and media integration tests

    Repository path: apps/cms/tests/auth-authority.integration.test.ts

    Own profiles, media versions, page traversal, private references and account revocation.

  7. Public content and archive selection

    Repository path: apps/cms/src/cms/services/public.ts

    Published taxonomy descendants, profile archives and public visibility.

  8. Published-content integration tests

    Repository path: apps/cms/tests/integration/public.test.ts

    Page moves, redirects, publication isolation, taxonomy queries and historical restore.

Content

Review queue

Inspect the submitted version, request changes and publish exactly what was approved.

What a review contains

A review is a request to assess one exact saved revision of an entry. It is not a live window onto whatever the author happens to be typing now. This makes an editorial decision reproducible: the title, body, fields and layout you approve remain identifiable even if newer work has been saved since submission.

Approval and publication are separate actions. Approving a review records the decision, but does not change the public site. Publish reviewed revision deliberately publishes that approved saved version. The normal content editor's Publish button instead targets its current saved working revision, so choose the review dialog when your intention is to publish the approved version.

Sources: Review and schedule screens; Overview and workflow queries; Content and publication service.

Submit work for assessment

  1. Open the entry, finish the changes you want assessed and wait for Saved. Resolve errors or conflicting saves first.
  2. Choose Submit for review when that control is available. Contributors use it for their unpublished Posts; authors and contributors also use it for their own profiles.
  3. Continue editing only with the understanding that later saves do not alter the submitted revision.
  4. If the newer revision should replace the pending submission, save it and submit again. The previous pending review becomes superseded.

The normal editor shows Publish to someone who already has publication capability, rather than offering a separate Submit button alongside it. A review is not enforced as a prerequisite for every permitted publisher. The current permission model also does not enforce that the submitter and reviewer must always be different people; teams that require independent approval should make that responsibility explicit.

Sources: Resource editor; Resource permission policy; Content and publication service; Two-role review browser journey.

Find the right review

Open Review queue, use Search titles and choose Search, or narrow the State selector. Previous page and Next page reach older entries. Refresh reloads the current search. The title comes from the submitted revision, so searching for a title introduced only in a later draft may not find the older submission.

StateMeaning
pendingWaiting for an authorised decision.
approvedThe named revision was approved; it may still need publication.
changes-requestedA reviewer requested revisions, with a note explaining what to improve.
supersededA newer submission replaced a previously pending review.

You see submissions you are allowed to read and either submitted yourself or have authority to publish. Editors do not receive designer-only template reviews. Designers can make decisions for design resources they can publish. A contributor can see their eligible submission without receiving the power to approve or publish it.

Sources: Review and schedule screens; Overview and workflow queries; Resource permission policy.

Inspect, preview and decide

  1. Choose Inspect revision on the relevant row. Read the submitted title, revision date and state.
  2. Start with What changed. Read the highlighted text, settings and added, removed, moved or changed layout blocks. Compare from/to identifies the exact saved versions by title and date. Expand Read the full submitted text to read the complete body and summary.
  3. Notice the warning if newer working edits exist. Open latest working draft is a separate link and is not the submitted version.
  4. Choose Create private preview, then Open submitted preview for the submitted version rendered through the site. The preview belongs to your signed-in account.
  5. For a pending review, write a useful Review note and choose Request changes, or choose Approve revision when the saved version is ready. Approval remains disabled until the selected comparison loads; it records a decision and does not publish.
  6. After approval, choose Publish reviewed revision when you intend to release it. Review the saved-revision checks and choose Publish saved revision. Confirm the message that this reviewed revision is currently published.

Removed text is struck through and added text is underlined. Settings use readable values and layout changes identify each block without requiring saved JSON. Link destinations are visible in the comparison. Reference names are current names available to your account, not historical names stored in the revision; technical details retain exact identifiers. Use the private preview for formatting placement and complete visual appearance. Long or malformed comparisons are marked incomplete and complete JSON downloads remain available.

For example, a contributor submits a 600-word report and then starts adding an unverified quotation. The editor can review and publish the submitted report without accidentally publishing that quotation. The newer working draft remains available, and visitors continue to see the precise revision chosen for publication.

Sources: Review and schedule screens; Overview and workflow queries; Two-role review browser journey.

Resolve review problems

Request changes requires a non-empty note in the interface. Describe the change concretely, such as checking a date or shortening an introduction. The decision's note appears on the review row. After making changes, the writer should create a new saved submission; editing alone does not reopen a decided review.

A review may stop accepting a decision if another reviewer has already acted or the entry moved to trash. Refresh instead of assuming the first decision failed. Publication can still be rejected after approval if permissions, the current publication or required dependencies changed. Approval is an editorial decision, not a promise that later publication checks will be bypassed.

A private preview expires after 30 minutes and is not transferable to an anonymous colleague. Create a fresh preview while signed in if it expires. If the queue looks empty, clear the state/search filters, inspect later pages and confirm your resource access. No matching reviews and no permission to see someone else's review are different situations.

Sources: Review and schedule screens; Overview and workflow queries; Content and publication service.

References

  1. Review and schedule screens

    Repository path: apps/cms/src/components/admin/operations.tsx

    Exact submitted-revision inspection, decisions, publication and cancellation controls.

  2. Overview and workflow queries

    Repository path: apps/cms/src/cms/services/management.ts

    Permission-filtered counts, review decisions, queue search and pagination.

  3. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  4. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  5. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  6. Two-role review browser journey

    Repository path: apps/cms/tests/review-browser.ts

    Contributor submission and editor publication of the exact reviewed revision.

Content

Publishing schedule

Release an exact saved revision later, interpret times and recover blocked scheduled work.

What scheduling does

Scheduling records an intention to publish an exact saved revision at a future instant. It does not arrange to publish whatever draft happens to be newest at that time. This is useful for an announcement, event page or prepared design update whose release time is known in advance. An existing published version can remain visible while the replacement waits.

The background worker processes the intention without needing a visitor to open the site. Closing your browser does not cancel it. However, the worker must be running and able to reach the database. If the operator pauses or stops it, due work cannot complete until processing resumes; the scheduled time is not a guarantee independent of the application's operation.

Sources: Resource editor; Content and publication service; Publication and worker integration tests.

Schedule a saved entry

  1. Open the entry you have permission to publish. Finish its content and required relationships, then wait for Saved.
  2. In Publishing, choose Schedule publication. The control is disabled while there are unsaved changes.
  3. Set Date and time in the timezone shown by the dialog. Choose a future time and resolve any offset choice or invalid-time warning.
  4. Review the reminder that the currently saved revision will publish. Choose Schedule publication in the dialog to record the intention.
  5. Open Publishing schedule, find the row and confirm its title, due time and pending state.

Scheduling requires the same resource-specific capability as publication. An author may schedule their own Post; a contributor cannot schedule publication. Designers may schedule design resources they can publish, but not ordinary content merely because they can read it. Required fields and dependencies are checked when scheduling, then checked again when the worker executes.

Sources: Resource editor; Local date and time input; Content and publication service; Resource permission policy.

Read local time and daylight-saving choices

The input uses your browser's local timezone and shows its name. Site settings timezone does not override this input. GroCMS stores an exact instant so that two people in different timezones refer to the same scheduled event, even when their clocks show different hours. Read the displayed timezone rather than assuming everyone sees Johannesburg time.

A daylight-saving change can make a local clock time occur twice or not exist at all. For a repeated time, choose the offered UTC offset identifying the intended occurrence. For a time inside a skipped interval, choose a valid alternative. GroCMS prevents saving an unresolved time instead of silently guessing.

Sources: Resource editor; Local date and time input; Review and schedule screens.

Read the queue and its states

Search titles and choose Search to find the saved scheduled title. Filter by State, use Previous page or Next page for older work, and Refresh to reload current results. Open content takes you to the latest working draft; it does not silently replace the schedule's pinned revision with that draft.

StateMeaning and next step
pendingWaiting for its due time or worker processing. Check the due time and worker if overdue.
publishedThe saved target was published successfully.
cancelledCancelled deliberately or superseded by a later schedule/publication/lifecycle change.
blockedAuthority or current publication state changed; review the entry and create a new schedule.
failedProcessing could not complete within the retry policy. Read the error and involve the operator if necessary.

The optional Note field in the entry's action dialog is not currently shown or stored as a schedule description. Put essential editorial instructions in an appropriate review note or communicate them through the team's agreed process; do not rely on that optional field as a scheduling brief.

Sources: Review and schedule screens; Overview and workflow queries; Content and publication service; Publication and worker integration tests.

Edit, cancel or replace a schedule

Later saves remain a working draft and do not retarget the schedule. For example, schedule an announcement for Friday, then draft a longer version on Thursday: Friday still publishes the originally scheduled revision. To release the longer version instead, save it and schedule that saved revision again. The previous pending schedule becomes cancelled.

Use the row's cancel control for a pending intention when it should not run. Cancellation does not withdraw content that already published; use Unpublish content for that separate task. A newer manual publication, trash action or other publication lifecycle change cancels an older pending intention so it cannot unexpectedly overwrite the new decision.

Execution rechecks the scheduler's current account and publication rights. Disabling that person, removing their capability or changing required publication conditions can prevent release. Correct the reported issue, inspect the latest saved content and create a new schedule rather than repeatedly retrying an old assumption. Temporary worker failures may retry automatically, but the interface does not provide a universal Retry job button.

Sources: Review and schedule screens; Content and publication service; Publication and worker integration tests.

References

  1. Resource editor

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Content fields, permissions, autosave, history, publication and scheduling dialogs.

  2. Content and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Draft isolation, route rules, profile ownership, exact review/schedule targets and recovery.

  3. Publication and worker integration tests

    Repository path: apps/cms/tests/integration/publication.test.ts

    Pinned scheduling, cancellation, restart, retries and dependency protection.

  4. Local date and time input

    Repository path: apps/cms/src/components/admin/local-datetime-input.tsx

    Local time, daylight-saving gaps and explicit ambiguous-time choices.

  5. Resource permission policy

    Repository path: apps/cms/src/cms/policy/index.ts

    Administrator, editor, author, contributor and designer capabilities.

  6. Review and schedule screens

    Repository path: apps/cms/src/components/admin/operations.tsx

    Exact submitted-revision inspection, decisions, publication and cancellation controls.

  7. Overview and workflow queries

    Repository path: apps/cms/src/cms/services/management.ts

    Permission-filtered counts, review decisions, queue search and pagination.

Content

Languages and translations

Add website languages, prepare translations and understand which draft, revision, links and publication you are changing.

Add a website language

GroCMS starts with English (en). With one configured language, translation controls and language filters stay hidden. An administrator can open Settings → Languages to add another language. This configures website content; administration labels remain English.

If website languages cannot load, use the displayed Try again action. Lists remain readable, but creation waits and the visual preview waits for its writing direction; GroCMS does not silently replace a selected language with English. A failed refresh retains previously confirmed languages and an already-open canvas. Existing resource drafts keep their identity and can still be saved.

  1. Enter a standard code such as fr, af, ar or pt-BR, a visible language name, and Left to right or Right to left.
  2. Select Add language. Configuration is saved immediately; it does not translate, create or publish any entries.
  3. Open an existing entry and use Translations, or choose the language when creating a separate new entry.

The screen is add-only: the existing default language is fixed, and there are no rename, direction-change or removal controls. Re-adding an existing code does not update it. An existing route or redirect under the new prefix blocks configuration; arrange a deliberate URL move before claiming that prefix. The current limit of 30 configured languages, including English, is a configuration bound, not a tested content or traffic capacity.

Sources: Language configuration and prefix validation; Administrator language setup; Localization implementation and operations guide.

Find an entry and switch its language

Use the Language filter in a content list to find a particular language; All languages shows accessible entries together with their language and status. Search, status, ownership, page and language stay in the URL and in the editor's return link. A new independent entry defaults to the list language, or English from All languages. Use Translations on an existing entry when you want to connect a new version to that entry.

Language appears in both the ordinary editor and the full-window Visual editor. It opens an existing translation as a different entry. If the source has unsaved changes, choose Stay, Save and leave, or Discard unsaved changes and leave. Save and leave waits for the latest save and keeps you in place if a field, recovery prompt, conflict or request failure needs attention. Discard cannot undo a save that the server already accepted.

The destination has its own draft and visual-editor history. Autosave and temporary browser-tab recovery stay attached to the original resource ID, not the group of translations. Recovery is not a durable backup or a cross-device translation workspace.

Sources: Resource editor sessions and recovery; Translation editing controls; Localization implementation and operations guide.

Copy a saved revision, then translate it

  1. Finish and save the source entry. Resolve recovery, unfinished fields and save conflicts before copying.
  2. Open Translations, select a missing language and choose Create [language] translation. Your role must allow editing the source and creating that resource kind.
  3. GroCMS opens a new draft copied from the exact saved source revision. Translate the title, body, excerpt, SEO, block text, captions and other authored values.
  4. Review its slug, links and dependencies. Save, preview, then publish or submit this language version for review.

Creation pins the current saved source revision. If someone saves a newer source first, reload and review before retrying. If the destination version already exists, it is opened without overwriting it. A translation in Trash must be restored instead of duplicated.

Sources: Translation editing controls; Translation creation and revision ownership; Typed translation reference remapping.

Prepare related content before publication

When copying, GroCMS replaces typed references with corresponding accessible destination-language resources where they already exist. Required same-language relationships still apply. Translate parent Pages or hierarchical terms before their children, and categories/tags before the content that uses them. Translate the home Page before its Site settings, then publish the Page before publishing settings that select it.

Templates, shared sections, menus, brand, settings and profiles can have translations too. A template, shared section, menu or profile reference can intentionally remain shared when a counterpart is unavailable, subject to normal publication rules. Public rendering can reuse eligible default-language brand/template design. This does not make an unavailable translated article fall back to the English article.

Images retain their IDs, bytes and shared media-library metadata. Translate a block's own alternative text or caption where that control is provided; use a separate media asset if global library metadata must differ by language. Literal button URLs, HTML links and manually entered menu addresses remain exactly as authored; /contact does not automatically become /fr/contact. Creating a related translation later does not rewrite the references already saved in another entry. Inspect the actual navigation and content before publication.

Sources: Translation creation and revision ownership; Typed translation reference remapping; Localized public rendering and search.

Review, schedule and restore one language at a time

Each language variant has an immutable resource ID and separate working/published revision pointers. The translation group connects the variants; it is not an editing target. Revision rows explicitly carry the language and ownership constraints keep pointers attached to matching revisions.

Readable revision comparisons and Restore revision apply to the current language only. Restoring creates another draft in that language. Review submissions and schedules keep the exact resource and saved revision: approving or scheduling French does not approve or schedule English. Subsequent draft edits do not retarget a schedule.

Publish dependencies in a useful order and resolve the specific error if publication is blocked. When setting up a translated home, publish its Page, select that Page in the translated Site settings, publish those settings, then check the language root and its menus.

Sources: Translation creation and revision ownership; Resource editor sessions and recovery; Locale variant migration.

Check URLs, direction and search

English keeps existing URLs such as /, /about and /journal. Additional languages use lower-case prefixes such as /fr, /fr/about, /ar and /pt-br. Each variant can use its own slug. Public language alternatives use eligible published versions; drafts and private versions are not anonymous alternatives.

The public page and visual preview use the configured content language and direction, including RTL. Administration and some built-in fallback public labels remain English, and documentation keeps its authored language. Check the result with real translated content rather than assuming all interface text changes with the language.

Search and listings select the requested content language. English uses PostgreSQL English text search; other languages use the simple configuration without language-specific stemming. Test your real languages and queries before making search-quality promises. The default feed is /feed.xml; a language feed uses a query such as /feed.xml?locale=fr.

Sources: Language configuration and prefix validation; Localized public rendering and search; Localization implementation and operations guide.

Upgrade and exchange content deliberately

An existing installation needs the locale migration and a matching release for every web process, worker, setup/seed command, importer and other content producer. Take a verified database-and-media backup, stop all producers that share that database, migrate using the recorded installation procedure and verify before resuming. Existing content becomes English without changing its text or existing English URLs. A failed migration is not a reason to reset volumes or restart incompatible older producer code.

The administrator native content export is gcms-native version 3 and retains language configuration, resource/group identities and revision locales. It excludes authentication data and media bytes and is not a complete recovery backup. The separate grocms-site-v1 installation manifest remains default-language only and rejects resource-level locale/translationGroupId fields. Create translations through the CMS after initializing that manifest. No universal importer or automatic multilingual manifest installer is implied.

Sources: Localization implementation and operations guide; Locale variant migration; Default-language site manifest contract.

References

  1. Localization implementation and operations guide

    Repository path: docs/localization.md

  2. Language configuration and prefix validation

    Repository path: apps/cms/src/cms/services/localization.ts

  3. Administrator language setup

    Repository path: apps/cms/src/components/admin/languages.tsx

  4. Translation editing controls

    Repository path: apps/cms/src/components/admin/translations.tsx

  5. Resource editor sessions and recovery

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

  6. Translation creation and revision ownership

    Repository path: apps/cms/src/cms/services/content.ts

  7. Typed translation reference remapping

    Repository path: apps/cms/src/cms/translations.ts

  8. Localized public rendering and search

    Repository path: apps/cms/src/cms/services/public.ts

  9. Locale variant migration

    Repository path: apps/cms/drizzle/0006_locale_variants.sql

  10. Default-language site manifest contract

    Repository path: apps/cms/scripts/site-manifest.ts

Website design

Homepage

Understand what controls the front page, change its layout, and keep its story cards current.

What controls the front page

The homepage is the website address ending in /. Its appearance can come from a dedicated home template, a Page selected in Site settings, or the built-in fallback. In the reference website, the home template supplies the opening message and story collection. Editing a Page called Home does not automatically make that Page the front page; its title is a label, not a routing instruction.

Start by identifying the existing published home template and the Homepage selection in Settings. Treat these as two related decisions: the selected Page supplies content fields, while the chosen composition supplies the arrangement. Header navigation, footer content, and brand styling are resolved separately around the main content.

Sources: Public page selection and resource resolution; Public website frame and theme application; Reference website content.

The exact selection order

  1. At /, a published Site settings record can select a Homepage Page. That Page becomes the current content record.
  2. If that Page has its own custom composition, the custom composition wins. This includes a composition whose canvas has no blocks.
  3. Without a Page composition, an explicitly selected Template on the Page wins over automatic template matching.
  4. Without an explicit Template, the homepage checks the home template first, then the applicable single/page templates and index fallback. With no suitable layout, the built-in renderer provides a fallback.

Sources: Public page selection and resource resolution; Public website frame and theme application.

Change the opening message and layout

  1. As an administrator or designer, open Templates and select the existing home template. Confirm that Template matching → Template key is home.
  2. Open Visual editor. Select the Hero component to edit its Introductory line, Heading, Supporting text, Button label, and Button link in Block settings. Use a real destination such as /journal when that is your site's archive path.
  3. Select or add a Section to adjust Paper, Soft, or Dark tone and Compact, Comfortable, or Generous spacing. Put connected content or text inside its drop area.
  4. Wait for the saved state, open Preview, and inspect the result. Return to the editor and Publish when the saved version is ready.

The small component canvas is useful for arrangement; the full Preview is the better place to judge the complete page with its navigation and footer. A draft update does not replace the current public homepage. Publishing the template changes every route that uses it, so keep home-specific material in the home template rather than the general index fallback.

Sources: Resource editor and design resource fields; Puck integration and editor configuration; Configured website components; Role and resource permissions.

Where homepage cards come from

A Content collection component is a connected query, not a list of manually typed cards. For the journal, set Content type key to post and choose a limit from 1 to 24. Its title is the section heading. Each card takes its title, excerpt, featured image, and destination from the corresponding eligible published record. Updating those fields in Posts changes the source; publish the post to change its public card.

On a normal home composition, the loader retrieves recent eligible records of the requested type, ordered by their selected revision date with a stable identifier tie-break. This is not a custom ordering or category-filter control. Use the archive for paginated browsing. Typing posts instead of the actual type key post will not select the intended collection.

Sources: Configured website components; Public page selection and resource resolution; Built-in layout patterns.

Use a specific Page as the homepage

An administrator or editor can prepare and publish the Page. An administrator or designer can then open Settings → Site settings → Manage settings, choose it in Homepage, save, and publish the settings record. The Page is a required dependency, so publish it before publishing settings that point to it. The page's separate public address can still exist; selecting it for / does not rename its slug.

Coordinate these roles when a designer is responsible for layout and an editor is responsible for Page copy. Designers can manage design resources but cannot edit Page content under the current policy. Editors can manage Pages but cannot manage templates or site settings. An administrator can complete the whole change.

Sources: Settings navigation; Resource editor and design resource fields; Revision and publication service; Role and resource permissions.

If the homepage does not change

  • Check which resource you published. Publishing a Page does not publish its selected template, brand, menu, or settings record.
  • Check for a custom Page composition or explicit Template that takes precedence over home.
  • If cards are missing, verify the type key and each post's publication and public visibility. A draft or withdrawn post is not a public card.
  • If the layout appears but a body is missing, include Content body; a Hero's supporting text is a separate field.
  • If a color stays unchanged, check the published Brand & theme revision and its saved overrides. Selecting defaults does not clear a saved color or custom font.

Sources: Public page selection and resource resolution; Resource editor and design resource fields; Revision and publication service; Website component styles.

References

  1. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  2. Public website frame and theme application

    Repository path: apps/cms/src/app/site-view.tsx

    Header, footer, default layouts, archive listings, brand colors, and WOFF2 font application.

  3. Reference website content

    Repository path: apps/cms/scripts/seed.ts

    Initial home template, shared resources, brand, navigation, and example content.

  4. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

  5. Puck integration and editor configuration

    Repository path: apps/cms/src/cms/editor/composition-editor.tsx

    Available canvas sizes, native rich text, remote resource pickers, patterns, and read-only behavior.

  6. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  7. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

  8. Built-in layout patterns

    Repository path: apps/cms/src/cms/editor/patterns.ts

    Welcome, article, and two-column layouts; copied components receive independent identifiers.

  9. Settings navigation

    Repository path: apps/cms/src/components/admin/settings.tsx

    Settings overview and the Manage settings route to the site settings record.

  10. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  11. Website component styles

    Repository path: apps/cms/src/app/globals.css

    Responsive columns, typography, public theme variables, section tones and hero decoration.

Website design

Visual editor

Arrange the available components, connect content, and understand the limits of the canvas.

What the visual editor changes

Visual editor opens a full-window workspace in the current browser tab. It arranges a resource's composition: an ordered set of components and their settings. Pages, templates, and shared sections expose this action. Other content can gain a composition through Add a custom page composition. Back to content returns to the entry's fields without discarding unsaved work; browser Back and Forward also switch between views. Puck supplies the canvas, nested slots and rich text; GroCMS determines components, permissions, saving and public behaviour.

A composition is separate from the entry's Title, Excerpt, and Body. A Rich text block contains its own text. Content body displays the entry's stored rich-text Body. Choose the latter when one template should show different articles; choose a Rich text block for a fixed introduction or callout that belongs to the layout.

Sources: Puck integration and editor configuration; Resource editor and design resource fields; Configured website components; Slot field; Rich Text Editing.

Build and inspect a layout

  1. Open the resource and select Visual editor. Choose a component from Layout, Content, or Connected content, and place it on the canvas or inside a container's drop area.
  2. Select a component to edit its fields. Reorder, duplicate, or remove components using the editor's available controls. Changes are saved through the CMS's normal autosave process.
  3. Open Patterns and choose Welcome & latest stories, Editorial article, Two-column story, Three feature cards, or Questions & answers, then select Insert a copy. This appends blocks and can be undone; it does not replace the existing layout.
  4. Inspect Phone, Tablet, and Desktop canvas sizes. These are 375, 768, and 1280 pixels respectively. Open the full saved Preview before publishing.

Pattern copies receive new component identities. Editing the copy will not change the original pattern. The menu can also offer recent shared sections as copies; a copied section becomes independent. To retain a live connection, use a Shared section component instead.

Sources: Puck integration and editor configuration; Built-in layout patterns; Resource editor and design resource fields; Editor browser verification.

Keyboard and tablet editing

Wide workspaces show Blocks and Outline on the left, the canvas in the centre, and Block settings on the right. Smaller windows show one sidebar at a time; phones use bottom panel navigation. Select a named block in Outline and choose Edit block settings to focus its inspector. Back to Outline returns to the selected block. Ordinary selection keeps focus in place. Panel widths provides keyboard controls and a reset action. Help explains the workspace controls.

Use Move up, Move down, Duplicate block and Delete block without dragging. Move into places the selected block at the end of another container. Add a block offers a component type and destination. A container cannot move into itself or its descendants. Deleting a container removes its nested blocks too; Undo can restore that change during this editor session. Normal autosave and revision history remain separate.

Tab and Shift+Tab move between controls; Enter or Space activates a button. Separate canvas drag handles keep text and links outside draggable buttons. Preview zoom changes magnification, while Phone, Tablet and Desktop change the website preview width independently of editor panels. A zoomed-out canvas scales its handles, so use the full-size Outline controls for precise touch work.

Undo and Redo survive switches between content and visual editing in the same open resource. The temporary cache holds up to 100 history entries within 8 MiB; large layouts can retain fewer entries. Reopening restores selection and the device width, with zoom recalculated to fit. Reloading, private Preview, changing resources or accounts, or replacing a draft starts a new session. Saved revisions and tab recovery remain available separately. The workspace header shows the real save state, and its publication controls act on saved revisions. Return to the editor in private Preview reopens the originating visual workspace.

In rich text, select text and press Ctrl+K (Command+K on macOS) to insert or edit a link. Alt+F10 moves into formatting controls. Apply, Cancel and Escape in the link dialog return focus and the selection to the text. Interactive preview inspects the current composition without editing; open the separate saved Preview before publishing.

Sources: Puck integration and editor configuration; Resource editor and design resource fields; Website component styles.

Layout and content controls

ComponentControls and result
SectionA nested drop area; Paper, Soft, or Dark tone; Compact, Comfortable, or Generous spacing. An optional anchor gives the section a destination such as #features: begin with a lowercase letter, use lowercase letters, numbers or hyphens, and keep it unique within the composition. main-content is reserved.
ColumnsA nested drop area with Two or Three columns. Child components fill the grid; responsive styles stack them on narrow screens.
HeroEyebrow, title, supporting text, primary and secondary button labels and links. An empty label hides that button. Choose Editorial, Split, or Stacked layout, optional image and alternative text, and Asterisk or None decoration.
StackGroup related blocks vertically, for example a feature heading, explanation and button. Choose Small, Normal or Large gap; Left or Center alignment; and Plain or Panel surface. A Stack fits inside Columns to make each column a complete card.
Rich textFormatted text in the Text field, including supported headings and links. It has its own content rather than borrowing the entry Body.
ImageSearch and choose a library image, then set Alternative text and an optional caption. Natural fit displays the image at its usual proportions; Contain keeps the complete image within its allotted area. The component uses the library alternative text when its own value is empty.
ButtonA label and Link destination, with Primary, Secondary or Text appearance. Use a safe web address, local path, section anchor, or supported link scheme.
Site logoDisplays the shared brand identity. Choose Follow section, Light background or Dark background, Small/Medium/Large size and an optional link. It uses the published brand's official logo, custom image or text choice; do not recreate the official wordmark in Rich text.
Contact formA fixed enquiry form with editable heading, explanation and submit label. The installation must enable enquiries before this component can be published. It offers demo and quote requests; the recipient is controlled by the operator. Forms are disabled in private previews so testing a draft does not submit an enquiry.

Blocks expose the supported layout, typography, spacing and responsive controls from the shared native component catalogue. Design Studio can associate reviewed, parsed and scoped CSS with a native design revision. It does not execute uploaded scripts or introduce a second page renderer. Brand & Theme remains responsible for shared identity.

Sources: Configured website components; Puck integration and editor configuration; Website component styles.

Connected content controls

ComponentWhat it reads
Content titleThe current entry's title and excerpt, with its content type as the small label.
Content bodyThe current entry's canonical rich-text Body, rendered as formatted content.
Content detailsAvailable author information, content type, and the selected published revision's date.
Content collectionA title, exact Content type key, and limit of 1–24. Cards come from eligible published content.
Site navigationA selected published Navigation resource, or the site default when no menu is bound. Optional featured button text and destination add one clear action beside the menu.
Shared sectionA selected published shared section, rendered wherever this component appears.

Connected blocks can look incomplete in a design canvas without a representative current entry. Check the public Page or a saved Preview before replacing them with fixed text. The full website also supplies global header and footer content outside the main composition; adding another navigation block inside the body may intentionally or accidentally create a second navigation area.

Sources: Configured website components; Public page selection and resource resolution; Puck integration and editor configuration.

Nesting and document limits

Section, Columns and Stack accept nested children. A composition may contain at most 200 components, its nesting-depth value must not exceed eight, and its serialized layout must remain within 500,000 characters. Shared-resource references have separate depth and cycle checks. An Image or Shared section must have a selected resource before publication. Optional section anchors have a maximum of 80 characters and must not repeat within the same composition.

Unknown components are preserved in saved drafts but cannot be published. The editor offers a preserved-data view instead of silently replacing an unsupported layout. Restore the renderer or a compatible earlier revision. Splitting a large composition into reusable sections can improve organization, but it does not permit recursive references or bypass publication checks.

Sources: Content and composition validation; Revision and publication service.

Saving, access, and recovery

Wait for autosave to finish before Preview or Publish. If another person saved a newer revision, the conflict notice keeps your local draft and offers Download my changes and Load latest. Preserve your work before loading the newer version. A saved draft remains separate from the published version.

Editing controls follow the resource's permissions. Administrators and designers manage templates and shared sections; administrators and editors manage Pages. A designer viewing content they cannot edit receives a read-only view. If deleting all blocks unexpectedly produces an empty public page, remember that an empty custom composition still overrides the inherited template; use Revision history to recover the intended arrangement.

Sources: Resource editor and design resource fields; Role and resource permissions; Editor browser verification.

References

  1. Puck integration and editor configuration

    Repository path: apps/cms/src/cms/editor/composition-editor.tsx

    Available canvas sizes, native rich text, remote resource pickers, patterns, and read-only behavior.

  2. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

  3. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  4. Slot field

    Framework background only: a slot is a nested drag-and-drop area. GroCMS limits come from its own validation.

  5. Rich Text Editing

    Framework background only. GroCMS provides its own configured controls and canonical HTML persistence.

  6. Built-in layout patterns

    Repository path: apps/cms/src/cms/editor/patterns.ts

    Welcome, article, and two-column layouts; copied components receive independent identifiers.

  7. Editor browser verification

    Repository path: apps/cms/tests/editor-browser.ts

    Save/reload evidence for canonical rich text, slots, copied layouts, brand tokens, menus, and remote selection.

  8. Website component styles

    Repository path: apps/cms/src/app/globals.css

    Responsive columns, typography, public theme variables, section tones and hero decoration.

  9. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  10. Content and composition validation

    Repository path: apps/cms/src/cms/validation.ts

    Layout size, nesting, supported components, safe links, menu limits, color validation, and resource references.

  11. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  12. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

Website design

Templates

Build reusable page layouts and understand which template a public route selects.

A layout shared by many entries

A template defines the arrangement for a kind of public page. It does not duplicate each article's writing. For example, a single:post template can contain Content title, Content details, and Content body; the same arrangement then reads the current post's fields. Updating and publishing that template changes the shared presentation while leaving the posts' stored bodies intact.

The template's Title helps colleagues find it in Templates. Template matching → Template key determines its automatic role. A template slug is not a public page route. Create a Page when you need an address such as /about; create a template when you need a layout that can be selected for that Page or a class of pages.

Sources: Public page selection and resource resolution; Configured website components; Resource editor and design resource fields.

Create or update a template

  1. Open Templates. Edit the existing record for the role you need, or create a new template with a descriptive title such as Article layout.
  2. In Details, choose its Template key. Open Visual editor and insert the Editorial article pattern for a content-led starting point, or assemble your own components.
  3. Use Content title and Content body for values that should change with each entry. Add fixed Rich text only when every entry should display that same wording.
  4. Save, Preview, and inspect the intended type of public page. Publish referenced menus or shared sections first, then publish the template.

A template preview needs suitable content context to demonstrate connected fields. A placeholder does not necessarily mean the component is broken. Check a representative published entry with the template applied. For event or vehicle pages, the public frame also renders their structured details; the current visual controls do not provide a separate configurable component for every individual field.

Sources: Resource editor and design resource fields; Puck integration and editor configuration; Built-in layout patterns; Revision and publication service.

Template keys available in the interface

KeyUse
homeThe homepage's automatic template candidate at /.
pageThe fallback specific to ordinary Pages.
single:postIndividual posts.
single:eventIndividual events.
single:vehicleIndividual vehicles.
archiveArchive and taxonomy listing fallback.
searchThe search page's main composition; its search form and result listing are supplied separately.
404The missing-page composition; the response remains a missing-page response.
indexThe broad fallback when a more specific automatic match is unavailable.

The resolver also understands additional type-specific archive and taxonomy keys, but the current Template key dropdown exposes the choices above. Do not expect to type arbitrary new keys into that select. Extending the interface or configuring additional supported keys is a developer/API task.

Sources: Resource editor and design resource fields; Public page selection and resource resolution; Public website frame and theme application.

Why a different layout may win

For an entry, its own custom composition takes precedence over every template. If there is no custom composition, a Template explicitly selected in Organization takes precedence over automatic matching. Otherwise, a post checks single:post, single, then index; a Page checks single:page, page, then index. At the configured homepage, home is inserted ahead of those automatic candidates.

An empty custom composition is still a composition. Removing every block does not make a Page inherit a template again. Restore a revision without the custom composition, or ask an authorized developer to clear it through the API. Only one template can be published for a given key: publishing a second one produces a conflict. Edit the existing template rather than expecting a new record to outrank it.

Sources: Public page selection and resource resolution; Public website frame and theme application; Resource editor and design resource fields; Revision and publication service.

Templates and the surrounding website

Global header and footer sections sit outside the selected main composition. Archive and search result grids are also rendered by the public frame and retain their own pagination. Adding a Content collection inside an archive template adds another collection; it does not replace the existing result list or become its filtering control.

For a practical post template, place Content title, Content details, and Content body inside a Paper Section with Generous spacing. Add a Shared section below for a reusable editorial sign-off. Keep a promotional Hero on a home template if it should appear only on the front page, rather than placing it in index where it could affect unrelated routes.

Sources: Public website frame and theme application; Public page selection and resource resolution; Configured website components.

Permissions, publication, and troubleshooting

Administrators and designers can create, edit, preview, publish, and withdraw templates. The Editor role does not manage these design resources under the current policy. Publishing a template publishes its saved revision, not unsaved typing and not the drafts of its dependencies. Existing pages that use the template pick up its new published layout without republishing their body text.

  • If nothing changes, inspect the entry's custom composition and explicit Template selection before changing the automatic key.
  • If publication reports a required linked resource, publish that public dependency first; selecting a draft does not publish it automatically.
  • If writing disappears, add Content body rather than retyping the article into a Rich text block.
  • To undo a layout change, use Revision history → View revision → Restore as working draft, inspect it, then publish the restored draft.

Sources: Role and resource permissions; Revision and publication service; Resource editor and design resource fields.

References

  1. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  2. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  3. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

  4. Puck integration and editor configuration

    Repository path: apps/cms/src/cms/editor/composition-editor.tsx

    Available canvas sizes, native rich text, remote resource pickers, patterns, and read-only behavior.

  5. Built-in layout patterns

    Repository path: apps/cms/src/cms/editor/patterns.ts

    Welcome, article, and two-column layouts; copied components receive independent identifiers.

  6. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  7. Public website frame and theme application

    Repository path: apps/cms/src/app/site-view.tsx

    Header, footer, default layouts, archive listings, brand colors, and WOFF2 font application.

  8. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

Website design

Shared sections

Reuse one published section across layouts while keeping deliberate copies independent.

One section, multiple places

A shared section is a separate resource containing a composition. A Shared section component points to that resource and renders its published composition wherever it is used. This is useful for a standard introduction, recurring contact information, a site-wide call to action, or other material that should stay consistent across layouts.

A copied pattern is different. Patterns → Insert a copy adds independent blocks to the current resource. Changes to those blocks do not change the source section, and later changes to the source do not update the copy. Decide whether the wording should stay synchronized before choosing between a live Shared section component and a pattern copy.

Sources: Configured website components; Public page selection and resource resolution; Built-in layout patterns.

Create a reusable section

  1. Open Shared sections and create a section with a title colleagues will recognize, such as Contact the editorial team.
  2. Open Visual editor. Add a Section for spacing and tone, then place Rich text and Button components inside it. For example, introduce the team and link the button to /about.
  3. Keep the content suitable for every place that will use it. A fixed Rich text block repeats the same wording; Content body instead reads the current page or article body.
  4. Wait for saving to finish, inspect Preview, and publish the section. It must be published before it can be selected through the live shared-section picker.

The section's Title and slug identify the resource in the CMS. Creating a section does not create a standalone public page at that slug. Place it in a template or Page composition to make it part of a visitor's journey.

Sources: Resource editor and design resource fields; Puck integration and editor configuration; Configured website components; Revision and publication service.

Place and update a live section

  1. Open the receiving Page or template's Visual editor and add Shared section from Connected content.
  2. Choose the Shared section field, search for the published resource, and use the selected entry. The chooser supports later result pages; older sections are not limited to the canvas's recent samples.
  3. Position the component in the layout, save, preview, and publish the receiving resource.
  4. For a later shared wording change, edit the source in Shared sections and publish that source. Every live reference resolves its current published version.

The link remains a resource reference, not a frozen copy of the source's original text. Draft changes to the source remain private until that source is published. Conversely, publishing a receiving Page does not publish an unfinished source section on your behalf. A private or unavailable required dependency blocks publication rather than becoming public accidentally.

Sources: Puck integration and editor configuration; Searchable reference selection; Configured website components; Public page selection and resource resolution; Revision and publication service.

References, nesting, and safe removal

A shared section follows the same composition rules as other layouts: only Section and Columns have child slots, a composition is limited to 200 components and the configured eight-level nesting-depth check, and serialized layout data is limited to 500,000 characters. Shared references have an additional maximum-depth check and cannot create a cycle.

Never point a section back to itself, directly or through another section. A chain such as A → B → A is recursive, even when the individual canvases look small. The publication service rejects recursive required references, and rendering also has a defensive depth guard. Before retiring a section, replace or remove its references and publish the receiving layouts; do not use deletion as a way to hide a still-required component.

Sources: Content and composition validation; Revision and publication service; Configured website components.

Permissions and troubleshooting

Administrators and designers manage Shared sections. An editor may be able to change a receiving Page while being unable to edit its source design resource. Coordinate the source change with someone who has design permissions. If a read-only view appears, it reflects the current resource permission rather than a failure of the canvas.

  • If the picker cannot find a section, confirm it is published and public, then search its title and check later result pages.
  • If a source update does not reach a Page, verify the Page contains a Shared section reference rather than a copied pattern.
  • If a block shows a placeholder in Preview, check its selected resource and publication state.
  • To reverse a shared change, restore the appropriate source revision as a working draft, inspect it, and publish it. The live references then use that restored published content.

Sources: Role and resource permissions; Resource editor and design resource fields; Puck integration and editor configuration; Revision and publication service.

References

  1. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  2. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  3. Built-in layout patterns

    Repository path: apps/cms/src/cms/editor/patterns.ts

    Welcome, article, and two-column layouts; copied components receive independent identifiers.

  4. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

  5. Puck integration and editor configuration

    Repository path: apps/cms/src/cms/editor/composition-editor.tsx

    Available canvas sizes, native rich text, remote resource pickers, patterns, and read-only behavior.

  6. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  7. Searchable reference selection

    Repository path: apps/cms/src/components/admin/reference-picker.tsx

    Remote search, pagination, selected entry resolution, and published-only choices.

  8. Public website frame and theme application

    Repository path: apps/cms/src/app/site-view.tsx

    Header, footer, default layouts, archive listings, brand colors, and WOFF2 font application.

  9. Reference website content

    Repository path: apps/cms/scripts/seed.ts

    Initial home template, shared resources, brand, navigation, and example content.

  10. Content and composition validation

    Repository path: apps/cms/src/cms/validation.ts

    Layout size, nesting, supported components, safe links, menu limits, color validation, and resource references.

  11. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

Website design

Navigation

Create menu links, bind a menu to the website, and keep destinations working as content changes.

References

  1. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

  2. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  3. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  4. Searchable reference selection

    Repository path: apps/cms/src/components/admin/reference-picker.tsx

    Remote search, pagination, selected entry resolution, and published-only choices.

  5. Content and composition validation

    Repository path: apps/cms/src/cms/validation.ts

    Layout size, nesting, supported components, safe links, menu limits, color validation, and resource references.

  6. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  7. Puck integration and editor configuration

    Repository path: apps/cms/src/cms/editor/composition-editor.tsx

    Available canvas sizes, native rich text, remote resource pickers, patterns, and read-only behavior.

  8. Public website frame and theme application

    Repository path: apps/cms/src/app/site-view.tsx

    Header, footer, default layouts, archive listings, brand colors, and WOFF2 font application.

  9. Website component styles

    Repository path: apps/cms/src/app/globals.css

    Responsive columns, typography, public theme variables, section tones and hero decoration.

  10. Brand foundations form

    Repository path: apps/cms/src/components/admin/brand-fields.tsx

    Color and font controls, logo selection, and validated brand token import/export.

  11. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

  12. Editor browser verification

    Repository path: apps/cms/tests/editor-browser.ts

    Save/reload evidence for canonical rich text, slots, copied layouts, brand tokens, menus, and remote selection.

Website design

Brand & theme

Set the website's identity, colors, fonts, and logo, with clear limits on what these controls change.

What belongs in the brand resource

Brand & theme controls your public website's name, tagline, logo, colors, fonts, site icon and default social image. Its saved working draft is separate from the published identity visitors see. The GroCMS administration and sign-in screens use the product's official identity independently; changing your website's brand does not rename articles or restyle the administration workspace.

New starter drafts use the official GroCMS Concept 05 identity: the supplied wordmark, white and navy surfaces, blue actions and locally hosted Inter. Existing customer sites retain their saved choices. You can keep this starting point, replace its colors and fonts, use a custom logo or display the site name as text. The official logo is an image asset, not a typed heading with a decorative mark.

Administrators and designers can manage brand resources. The Editor role manages editorial content rather than this design configuration. Edit the site's existing brand record. Only one brand can be published at a time: attempting to publish another brand produces a conflict. There is no active-brand switch that makes a newly created draft replace the existing published identity.

Sources: Brand foundations form; Official GroCMS brand defaults; Shared public brand resolver; Public website frame and theme application; Public page selection and resource resolution; Role and resource permissions; Revision and publication service.

Change the identity and colors

  1. Open Brand & theme and select the existing record. Its main Title is the administrative label; the Name field under Brand foundations supplies the public brand name.
  2. Set Name and Tagline. Name supplies the text-only identity and custom-logo description. A tagline remains separate copy; it is not added inside the official logo.
  3. Choose Brand defaults. GroCMS official fills missing settings while keeping saved overrides. To deliberately replace current colors and built-in font choices, select Use GroCMS palette and fonts; this leaves your name, tagline, custom assets and logo display choice intact.
  4. Set the color pickers or six-digit hex inputs as needed, for example #1857D9 for an accessible blue action. A saved custom font continues to override its built-in family.
  5. Choose Logo display: Official GroCMS logo, Custom image or Site name as text. Choosing an image in Logo selects Custom image. You can return to Official GroCMS logo without deleting the retained custom asset.
  6. Optionally choose Site icon and Default social image. Use a square icon and a landscape social image. Save, inspect Preview and representative pages, then publish the brand.

Site navigation, the default footer and the Site logo layout component share this identity. A custom footer containing its own Rich text is ordinary content: replace a typed identity with Site logo when you want it to follow the brand. The component offers light/dark background variants and three sizes. Custom images keep their original design; the component does not redraw them for another background.

The published icon and default social image feed website metadata. An entry's featured image takes precedence over the site's default social image. Official defaults are supplied when appropriate; selecting a draft image alone does not make it public. Publish the brand to expose its selected media. Browser and social-network caches may take time to refresh after a publication.

Sources: Brand foundations form; Official GroCMS brand defaults; Shared public brand resolver; Site icon and social image selection; Public website frame and theme application; Configured website components; Content and composition validation.

Understand the shared colors

ControlCurrent public effect
AccentThe shared action color used by primary public buttons and related controls; the official starting value is #1857D9.
BackgroundSets the site's base paper color and places using the paper/background variables.
TextSets the base inherited text color where a component does not declare its own color.
Surface, Muted text and BorderControl secondary panels, quieter text and separating lines wherever components use the shared website theme.
Dark surface and Action hoverControl dark section surfaces and the action color shown when a visitor points at a primary button.
Section tonePaper, Soft and Dark select coordinated surfaces from the shared public theme. Inspect text and logo contrast in each tone you use.

The public shell and visual-editor canvas resolve the same saved theme settings. The supplied GroCMS logo keeps its official artwork colors; a photo, custom logo or authored illustration is not recolored by these controls. There is no arbitrary CSS box or unlimited per-block palette. Hero's Asterisk option remains an optional illustration, separate from the product identity.

Review contrast after changing colors, especially white button text on the Accent color. The form validates color syntax, not every possible contrast pairing. Check the actual public layout rather than assuming a valid hex code guarantees readable text.

Sources: Official GroCMS brand defaults; Shared public brand resolver; Public website frame and theme application; Website component styles; Configured website components.

Choose built-in or uploaded fonts

Heading font and Body font offer Inter — GroCMS official, Editorial serif, Modern sans serif and Monospace. Inter is supplied locally with the product, so using it does not contact a font service. Existing serif, sans and monospace choices retain their Georgia/Times, Arial/Helvetica and Courier New fallback stacks. These settings apply where components use the shared heading and body fonts.

  1. To use a custom font, upload a WOFF2 file through Media library with an administrator or designer account.
  2. Return to the brand and use Choose custom heading font or Choose custom body font. Search and select the uploaded font asset.
  3. Publish the brand after saving. A selected custom font takes precedence over the corresponding built-in family, which remains a fallback.
  4. Remove the custom-font selection to return to the selected built-in family.

The implementation declares one uploaded face for each heading/body role. There are no controls for variable-font axes or separate uploaded files for every weight and italic style. Font loading uses the browser's normal fallback-and-swap behavior. A file with the wrong media type is rejected as a brand font.

Sources: Brand foundations form; Shared public brand resolver; Official GroCMS brand defaults; Public website frame and theme application; Website component styles; Media validation and immutable versions; Revision and publication service.

Import or export brand tokens

Expand Import or export brand tokens. Export tokens downloads brand-tokens.json containing the current draft's supported brand fields. Import tokens reads a GroCMS brand export and applies its values to this draft; it does not publish immediately. The importer accepts the gcms-brand format, version 1, and files up to the current 64 KB limit.

Version-one exports support the current preset, logo mode, shared colors, built-in fonts and selected logo/font/icon/social-image identifiers. Older version-one GroCMS exports remain supported. The downloadable design-pack brand-tokens.json uses a different design-document structure: it is not a CMS token export and cannot be imported here directly.

A token file transfers settings, not image or font bytes. Referenced assets must already exist in the destination library and be accessible. Unsupported keys, invalid colors or unsupported fonts are rejected. Review the imported fields, wait for saving, then preview and publish through the normal workflow.

Sources: Brand foundations form; Shared public brand resolver; Revision and publication service; Editor browser verification.

If the change does not appear

  • Check that the brand was published, not only saved, and that you edited the existing selected brand resource.
  • If a font stays unchanged, check for an overriding custom-font selection and confirm the selected asset is WOFF2.
  • If replacing a media file created a new version, select that new asset in the brand. Existing references deliberately retain their old asset identifiers.
  • If selecting GroCMS official leaves existing colors in place, those values are saved overrides. Use GroCMS palette and fonts to replace them deliberately, then review before publishing.
  • If the logo seems unchanged, check Logo display. An explicit Official GroCMS logo choice takes precedence over a retained custom asset; selecting that asset again chooses Custom image.
  • For an unwanted live change, restore an earlier brand revision as a working draft, inspect it, and publish the restored version.

Sources: Public page selection and resource resolution; Public website frame and theme application; Resource editor and design resource fields; Media validation and immutable versions; Website component styles.

References

  1. Brand foundations form

    Repository path: apps/cms/src/components/admin/brand-fields.tsx

    Color and font controls, logo selection, and validated brand token import/export.

  2. Official GroCMS brand defaults

    Repository path: apps/cms/src/cms/brand/preset.ts

    Approved Concept 05 assets, accessible action colors, official site defaults and product interface tokens.

  3. Shared public brand resolver

    Repository path: apps/cms/src/cms/brand/theme.ts

    Saved overrides, legacy font choices, custom assets, logo display and supported version-one tokens.

  4. Site icon and social image selection

    Repository path: apps/cms/src/cms/brand/metadata.ts

    Published custom icon and social-image selection, official fallbacks and preview metadata behavior.

  5. Public website frame and theme application

    Repository path: apps/cms/src/app/site-view.tsx

    Header, footer, default layouts, archive listings, brand colors, and WOFF2 font application.

  6. Public page selection and resource resolution

    Repository path: apps/cms/src/cms/services/public.ts

    Homepage and template precedence, published resource selection, connected collections, menus, and shared dependencies.

  7. Role and resource permissions

    Repository path: apps/cms/src/cms/policy/index.ts

    Design resources belong to administrator and designer capabilities; content permissions differ.

  8. Configured website components

    Repository path: apps/cms/src/cms/components/config.tsx

    The actual component labels, editable fields, slot definitions, and rendering behavior.

  9. Content and composition validation

    Repository path: apps/cms/src/cms/validation.ts

    Layout size, nesting, supported components, safe links, menu limits, color validation, and resource references.

  10. Website component styles

    Repository path: apps/cms/src/app/globals.css

    Responsive columns, typography, public theme variables, section tones and hero decoration.

  11. Media validation and immutable versions

    Repository path: apps/cms/src/cms/services/media.ts

    Supported uploads, WOFF2 handling, access checks, and replacement versions.

  12. Revision and publication service

    Repository path: apps/cms/src/cms/services/content.ts

    Immutable revisions, required published dependencies, cycle checks, preview selection, and publication actions.

  13. Editor browser verification

    Repository path: apps/cms/tests/editor-browser.ts

    Save/reload evidence for canonical rich text, slots, copied layouts, brand tokens, menus, and remote selection.

  14. Resource editor and design resource fields

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

    Native controls, autosave, publication actions, permissions, template keys, homepage settings, and navigation link editing.

Workspace

People & permissions

Invite team members, choose the right role, change access and distinguish login accounts from public authors.

What People manages

People manages the accounts that can sign in to the CMS: their email, role, enabled state and sessions. Only an administrator can manage people. Authors is a separate screen for public bylines and biographies. Creating a public author profile does not create a login, and inviting a person does not automatically publish their biography.

Access is checked on the server for each operation. A visible sidebar link does not grant permission. The current account role, the type of resource and its ownership all matter. API scopes add a further restriction when an integration makes the request.

Sources: Role and ownership policy; People screen; Authentication and current-account resolution.

Choose a role by responsibility

RoleWhat it can doImportant boundary
AdminManage workspace content, design, people and credentials, and view audit records.Use individual accounts so changes can be attributed; Activity log does not provide an edit-audit-record action.
EditorManage and publish non-design content, including pages, posts, terms and public profiles.Does not manage templates, shared sections, menus, brand or site settings.
AuthorCreate, edit and publish their own posts; prepare and submit their own public profile.Cannot manage other people’s posts, pages or design; some post fields remain restricted.
ContributorCreate and edit their own unpublished posts, then submit for review; prepare their own profile.Cannot publish or upload media, and cannot edit a post once it has a published revision.
DesignerManage and publish templates, shared sections, menus, brand and site settings.Reads permitted ordinary content but cannot edit Pages or Posts.

Authors and contributors can read terms for classification, but cannot manage the taxonomy itself. Their public profile can be submitted for review, not self-published. The media service also applies ownership and public-reuse rules; broad content permission is not a promise that every private upload is visible. Consult the Media library guide when collaborating on assets.

Sources: Role and ownership policy; Content ownership and protected fields; Media access policy.

Invite someone

  1. Open People and the invitation form. Enter the person’s email and select the role that matches their work. Contributor is the initial selection.
  2. Choose Send invitation. The application emails a one-use invitation that expires after 72 hours. Production email delivery requires working SMTP configuration.
  3. The recipient opens the link, enters their name and a password of 12–128 characters, then accepts. They sign in using that account on this installation.
  4. Check Your team for the new account. Pending invitations appear in their own paginated list. Cancel invitation revokes an unused link.

If an invitation expires, send a fresh invitation. Creating a replacement revokes older pending invitations for that email. If sending fails, the failed invitation is revoked. The inviting account must still be an enabled administrator when the invitation is accepted. During local development, mail normally arrives in Mailpit rather than a real inbox.

Sources: People screen; Invitation and access-change service; Account forms.

Change or remove access

  1. Use Find a person, enter a name or email, and choose Search people. Search applies to the whole matching dataset before pagination; use the separate people and invitation page controls.
  2. To change responsibility, choose a new role beside the person and select Save role. Existing sessions are signed out so stale permissions do not persist.
  3. Use Disable account to stop sign-in and revoke sessions. Enable account restores the ability to sign in. Disabling does not delete the person’s content.
  4. Use Sign out sessions when browser access should be reauthenticated without disabling the account. Subsequent requests using those sessions require a new sign-in. This action does not revoke API keys; manage integration credentials separately.

You cannot use this screen to demote or disable your own administrator account, and the system protects the last enabled administrator. Arrange a second administrator before handing over control. An enabled account with an unexpectedly limited screen should first have its role and the record’s ownership checked; repeatedly signing in will not grant additional authority.

Sources: People screen; Invitation and access-change service; Role and ownership policy.

References

  1. Role and ownership policy

    Repository path: apps/cms/src/cms/policy/index.ts

  2. People screen

    Repository path: apps/cms/src/cms/auth/people-panel.tsx

  3. Invitation and access-change service

    Repository path: apps/cms/src/cms/auth/people.ts

  4. Account forms

    Repository path: apps/cms/src/cms/auth/forms.tsx

  5. Authentication and current-account resolution

    Repository path: apps/cms/src/cms/auth/server.ts

  6. Content ownership and protected fields

    Repository path: apps/cms/src/cms/services/content.ts

  7. Media access policy

    Repository path: apps/cms/src/cms/services/media.ts

Workspace

Activity log

Trace recorded content, publication and administration actions and use event details to investigate changes.

What the log records

Activity log presents audit events written by the CMS as your team changes the workspace. Examples include content creation and saving, publication decisions, scheduling, API-key administration and people-management actions. It gives administrators a timeline of recorded changes, with structured details where the operation supplies them.

The log is scoped to the current site and requires the audit permission, which is administrator-only. It is not a visitor analytics dashboard, a count of page views or a guarantee that every browser action or authentication event is logged. A missing event does not prove that someone never opened a screen.

Sources: Audit filtering and pagination; Audit permission; Content audit events; People audit events.

Find and inspect an event

  1. Open Activity log from the Workspace group, or choose View activity log in Settings.
  2. Enter an action keyword in Search actions and choose Search. Search matches recorded actions; it is not a universal search across every value in event-detail JSON.
  3. Use Previous page and Next page to move through results. The total and page count refer to the filtered results. Select Refresh to retrieve recent events.
  4. Expand Event details beneath a row to inspect its JSON when details are present. Read IDs, versions, reasons or outcomes alongside the action and timestamp.
  5. Where an event references a resource, use Open content to inspect that record. Compare its Revision history or publishing state with the event you are investigating.

The heading converts action separators into readable words. The details preserve structured values, which are especially useful when two records have similar titles or when newer edits exist. The screen does not provide a separate author/date-range filter or an undo-event action. If a support request needs a precise event, include the action, time and relevant resource or revision ID.

Sources: Activity log interface; Audit filtering and pagination.

Investigate an unexpected page change

Suppose the homepage looks different after a team member publishes a shared header. Locate the publication event and open its referenced content. Inspect the header’s published revision and compare it with its working revision. The changed page may be a consumer of the shared header rather than the resource that was directly edited. The Templates and Shared sections guides explain this relationship.

For an article that did not change when expected, compare the schedule or review’s revision ID with the resource’s published revision. A newer working draft does not replace the revision pinned to an earlier approval or schedule. Review the relevant queue’s error or state as well as the audit record before deciding what to publish next.

Sources: Content audit events; Activity log interface.

Keep investigation separate from recovery

An audit entry is evidence of an operation, not a content snapshot you can restore. Use Revision history to restore content into a working revision, then review and publish it. Use a verified database-and-media backup for whole-installation disaster recovery. The workspace JSON content export is not a complete backup and does not replace the database containing audit history.

The Activity log interface has no dedicated bulk-download or retention-settings form. Operators who need longer-term audit retention must manage database backups and any external retention policy at the deployment level. Share only the details needed for support: event payloads may identify people, records or unpublished work.

Sources: Activity log interface; Workspace export payload; Backup and recovery runbook.

References

  1. Activity log interface

    Repository path: apps/cms/src/components/admin/operations.tsx

  2. Audit filtering and pagination

    Repository path: apps/cms/src/cms/services/management.ts

  3. Audit permission

    Repository path: apps/cms/src/cms/policy/index.ts

  4. Content audit events

    Repository path: apps/cms/src/cms/services/content.ts

  5. People audit events

    Repository path: apps/cms/src/cms/auth/people.ts

  6. Workspace export payload

    Repository path: apps/cms/src/app/api/cms/[...path]/route.ts

  7. Backup and recovery runbook

    Repository path: docs/operations.md

Workspace

Settings

Understand the settings hub, select the homepage and distinguish saved site preferences from deployment configuration.

The Settings hub

Settings groups common administration destinations. Site settings opens the existing site-settings record when one is available. Brand & theme controls the public visual identity. Languages lets administrators add website languages; open Languages and translations in Documentation for the editing workflow. People & access manages accounts. API keys creates integration credentials. Export workspace downloads a content package. System updates manages GroCMS core releases on enrolled installations. Activity & accountability opens the audit log.

Each destination still enforces its own permissions. Administrators manage these destinations; core update actions also require a recent sign-in and an installation-owner grant. Designers can edit and publish design resources, including site settings and brand, but cannot manage people, API keys, exports or audit history. Editors manage ordinary content rather than design configuration. A card appearing on the hub is not evidence that your role can use its destination.

Sources: Settings hub; Design and administrator permissions.

Update GroCMS core

Open System updates in the administration sidebar to inspect the installed build and Latest release check. The version label alone does not confirm that this website has the latest changes. The How to update GroCMS section gives instructions for this installation; it opens automatically for externally managed sites.

On managed installations, an owner-authorized administrator must have signed in within the previous 15 minutes to check, test or install updates. Administrator access alone does not grant update authority. Opening this screen reads stored status; Check for updates makes a fresh request to the configured, signed GroCMS release catalogue. It does not install anything or check GitHub or npm. A failed check can retain older releases; an empty list or missing connection is not proof that GroCMS is up to date.

  1. Choose Check for updates and inspect Latest release check and the last successful check time. Read the available release notes. Review update checks compatibility; inclusion in the catalogue alone does not guarantee that a release can be installed here. Resolve its assessment blockers.
  2. Close the review and choose Test on a copy for the release, review its assessment, then choose Start rehearsal. It verifies isolated data and retains the installed release, but also pauses the website during copying and candidate verification. Plan a maintenance window; duration depends on site size. Wait for the result before continuing.
  3. Review update again, then choose Install now or enter a future time and choose Schedule installation. Times use your browser's local time. The manager requires a verified recovery backup and rechecks compatibility before replacing the application. A changed installation can require another review. Review reinstall of this version follows the same checks and does not reset your database.
  4. Open recovery and progress page after submitting and keep it available while the application restarts. Wait for verification, check Update history and verify the website. Cancel scheduled installation is available while scheduled or queued. If a result is uncertain, inspect progress before submitting again; ask your installation operator to resolve Recovery required.

Notification only is the default. The clearly labelled daily catalogue check can be disabled; manual checks remain available. Automatic installation is an opt-in policy limited to eligible maintenance and security releases within the selected time zone, days and window. Failed automatic releases pause for manual review.

Sources: Core update management screen; Core update authority and request contracts; System updates guide.

Edit site settings

  1. Open Settings and select Manage settings. If no record exists, the Site settings list lets an authorized user create one.
  2. Open the existing canonical record rather than creating competing settings records. Only one settings resource per language can be published; attempting to publish another in that language produces a conflict. There is no active-record switch in the interface.
  3. In its fields, enter Site name, choose a Page in Homepage if that is how your root page should be supplied, and set Site timezone as appropriate. The picker can include drafts, but the selected Page must be published before the settings can be published.
  4. Save, review and publish the settings revision. Saving alone does not activate the change. Check the published root page and linked navigation afterwards.
FieldMeaning in this build
Site nameA saved settings value. Public brand text is supplied by Brand & theme; this field is not a universal rename of all visible branding.
HomepageA reference to a published Page used by public root-page resolution. Its own composition and template selection still determine the layout.
Posts archive pathA visible stored field, currently not used to change public routes. Archive paths come from the registered content-type routeBase. Changing this field alone does not move the post archive or rewrite navigation.
Site timezoneA stored site preference, defaulting to Africa/Johannesburg. Schedule entry currently uses the browser timezone; changing this field does not change every clock or reinterpret existing schedules.

A home template may still supply the root layout when the selected page inherits its design. A page with a custom composition, even an empty composition, overrides that inherited template. Read Homepage before switching the homepage or replacing a layout so you know which resource is actually supplying the visible design.

Sources: Site settings fields and save flow; Public homepage and configuration selection; Settings hub; Settings publication validation; Registered public archive routes.

Settings follow the same publication rules as content

Settings and brand are versioned resources. Their working and published revisions can differ, so an unfinished change can remain a draft while the current site continues to work. Revision history helps recover earlier values. Publishing validates references, including the selected homepage, against what can be used in the public site.

For a safe homepage change, prepare and publish the destination page first, then publish the settings change. Test the root URL, header links and footer links. If the result is wrong, inspect the page composition and template before assuming the settings did not save. A publication error about a dependency needs that referenced resource corrected or published; repeated clicks will not resolve it.

Sources: Settings publication validation; Public homepage and configuration selection.

What belongs in server configuration

The Settings screen does not configure the database connection, public server origin, SMTP credentials, authentication secret, Docker ports, media storage directory or background worker. Operators set those through environment files and deployment tooling. Passwords and API secrets should never be pasted into a page, brand field or site name.

Changing from localhost to a real domain requires updating the deployment origin and configuring a reverse proxy and HTTPS, not just editing Site name. Likewise, email invitations and resets require SMTP setup outside this screen. The setup guides include the supplied commands and explain which process uses each configuration value.

Sources: Production services and environment; Environment configuration template.

References

  1. Settings hub

    Repository path: apps/cms/src/components/admin/settings.tsx

  2. Core update management screen

    Repository path: apps/cms/src/components/admin/system-updates.tsx

  3. Core update authority and request contracts

    Repository path: apps/cms/src/cms/api/updates.ts

  4. System updates guide

    Repository path: docs/system-updates.md

  5. Site settings fields and save flow

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

  6. Public homepage and configuration selection

    Repository path: apps/cms/src/cms/services/public.ts

  7. Settings publication validation

    Repository path: apps/cms/src/cms/services/content.ts

  8. Registered public archive routes

    Repository path: apps/cms/src/cms/definitions/index.ts

  9. Design and administrator permissions

    Repository path: apps/cms/src/cms/policy/index.ts

  10. Production services and environment

    Repository path: compose.yaml

  11. Environment configuration template

    Repository path: .env.example

Workspace

Account & security

Sign in, recover access, change your password, manage sessions and set up an authenticator with recovery codes.

Sign in to the correct workspace

Open /login on the installation you were invited to use and enter your email and password. The CMS uses email-and-password authentication with optional authenticator verification. Your account is created by an administrator’s invitation or the operator’s first-administrator setup, not by public self-registration.

There is no shared universal administrator password in the application. Use the credentials generated for your installation or the password you chose when accepting an invitation. A developer server and a production preview may have different databases. Check the full address, including the port, before concluding that a valid password has stopped working.

Select Forgot password on the sign-in screen if you need recovery. The acknowledgement deliberately does not reveal whether an account exists. For an eligible enabled account, the application sends a reset link that expires after one hour. A disabled account requires administrator help; password reset does not re-enable it. Repeated requests may be rate-limited.

Sources: Sign-in, reset and MFA forms; Authentication configuration; Provisioning and account state; Better Auth: Email & Password.

Change your password and review sessions

  1. Choose your name at the bottom of the sidebar to open Account. This screen shows your name, email and role; it does not provide an ordinary edit-name or change-email form.
  2. Under password controls, enter your current password and a new password of 12–128 characters, then choose Update password. The other sessions are signed out.
  3. Inspect the signed-in sessions. Device descriptions come from browser information and are approximate; use dates and your knowledge of your devices to identify them.
  4. Sign out a session you no longer need, or sign out all other sessions. Use Sign out of GroCMS to end this browser’s session.

An administrator can also revoke sessions from People. Changing a person’s role or disabling their account invalidates existing sessions. If you are unexpectedly asked to sign in again after an access change, that is the intended behaviour.

Sources: Account security interface; Provisioning and account state.

Enable an authenticator

  1. Open Account and the authenticator setup controls. Confirm your current password and choose Set up authenticator.
  2. Copy the displayed setup key into an authenticator application using its manual time-based account setup. This interface provides a key rather than a QR-code scanning screen.
  3. Save the recovery codes somewhere you can reach if you lose the phone. They are sensitive credentials and each can be used once.
  4. Enter the six-digit code currently shown by your authenticator and select Verify and enable. Confirm that you have saved the recovery codes.
  5. At your next sign-in, enter the password and the requested authenticator code. If the device is unavailable, choose Use a recovery code and enter an unused code.

The application uses Better Auth’s two-factor capability with time-based codes and recovery codes. Enabling MFA is a per-account action; the People screen shows whether an authenticator is enabled. The current interface does not offer a workspace-wide policy to require MFA for every account.

Sources: Account security interface; Sign-in, reset and MFA forms; Authentication configuration; Better Auth: Two-Factor Authentication.

Resolve common access problems

ProblemWhat to check
No reset or invitation emailCheck the address and spam folder. Ask the operator to check SMTP delivery. Development Mailpit captures mail locally and does not send it to a real inbox.
Authenticator code rejectedCheck the device clock and use the current code before it changes. Try an unused recovery code if the device is unavailable.
Invitation no longer worksAsk an administrator for a fresh invitation. It may have expired, been cancelled, been replaced or already been accepted.
Correct account cannot access a screenCheck the account role and ownership rules. Authentication establishes identity; it does not grant all workspace permissions.
Lost authenticator and all recovery codesContact the installation administrator/operator. The UI does not supply an unauthenticated bypass or a universal emergency code.

To disable your own authenticator while you still have access, use the account screen’s disable controls and confirm your password. Treat setup keys, recovery codes, preview links and session tokens as private. The documentation deliberately contains no real account passwords or installation secrets.

Sources: Account security interface; Sign-in, reset and MFA forms; Authentication configuration; Provisioning and account state.

References

  1. Account security interface

    Repository path: apps/cms/src/cms/auth/security-panel.tsx

  2. Sign-in, reset and MFA forms

    Repository path: apps/cms/src/cms/auth/forms.tsx

  3. Authentication configuration

    Repository path: apps/cms/src/cms/auth/server.ts

  4. Provisioning and account state

    Repository path: apps/cms/src/cms/auth/people.ts

  5. Better Auth: Email & Password

    Library background; the GroCMS configuration determines its actual password and recovery rules.

  6. Better Auth: Two-Factor Authentication

    Library background for time-based codes and recovery codes; see local source for the enabled interface.

Workspace

API keys & content export

Connect an application with scoped credentials and understand exactly what a workspace export contains.

Create a credential for a specific integration

API keys let trusted software use the authenticated CMS API without an interactive browser session. Creating and revoking keys is an administrator function. A key is associated with its owner and a set of action scopes. Requests must satisfy both the current owner’s permission rules and the key’s scopes; a scope is not an independent grant of administrator authority.

  1. Open API keys from Settings. Choose the creation action and enter a recognizable name such as Internal content importer.
  2. Select only the required actions: read, create, edit, publish, unpublish, preview or media. Read is selected initially. Write integrations generally also need read because returned resource views are permission-checked.
  3. Choose an expiry. The interface offers 7, 30, 90, 180 or 365 days and initially selects 90 days.
  4. Create the key and copy the complete token immediately into the integration’s secret storage. The token is shown once; the server stores a hash and identifying prefix, not a recoverable plaintext copy.
  5. Use Revoke when the integration is retired or a token may be exposed. If the original token is lost, create a replacement and revoke the old one.

Sources: API key controls and export link; CMS API routes and export implementation; Bearer credential resolution and API request authentication; Permission and scope intersection.

Use the API deliberately

The CMS REST interface is under /api/cms. Integrations authenticate with an Authorization header containing Bearer followed by the token. Keep the token in a server-side environment variable or secret store, never in public browser JavaScript, a URL query string or a source-code commit. The example below describes the request shape and uses a placeholder.

http
GET /api/cms/resources?kind=content&type=post&page=1&pageSize=20 HTTP/1.1
Host: your-cms.example
Authorization: Bearer <your-private-api-token>

Read the API contract before writing content. Saves include the expected working revision to detect conflicting edits. Publication actions name the exact target revision and expected publication version, with an idempotency key for safe retries. A conflict response calls for reloading current state and resolving the difference rather than blindly replaying an outdated body.

The server returns structured errors for invalid input, forbidden actions and conflicts. Use the returned error and the contract to decide whether to correct the payload, request additional authority or reload the record. The administrative API is not an anonymous public content feed. Revoked or expired credentials, a disabled owner or changed owner permissions can stop previously working requests.

Sources: REST API contract; CMS API routes and export implementation; Bearer credential resolution and API request authentication; Permission and scope intersection.

Download the workspace content package

  1. As an administrator, open Settings and select Download export under Export workspace.
  2. Save the JSON file in a location appropriate for unpublished and private content. The package is a workspace content snapshot, not only a copy of the visible website.
  3. Check the format and version before processing it. The native format is gcms-native, version 3, including language configuration, translation identities, revision locales, type definitions and exact version pins, component release/publication evidence, instance pins and catalogue state. Use the included IDs and manifests to preserve references when building migration tooling. This is separate from the default-language-only grocms-site-v1 installation manifest.

The export includes site resources, retained revisions, route records, content-type and taxonomy definitions, revision-to-term relationships, resource and media reference manifests, and media metadata such as filenames, alternative text, hashes, dimensions and storage keys. Private and trashed resources may be included. A repeatable-read database transaction keeps the exported tables consistent with one snapshot.

The package excludes login accounts, passwords, sessions, API secrets, invitations, preview tokens, review and schedule records, audit events, background jobs, and actual media file bytes. It is therefore not a complete disaster-recovery backup. These omissions also mean it cannot reproduce the full operational history of the workspace.

Export selected in a content list downloads selected-content.json with format gcms-selected-snapshots, version 1. It includes the selected entries on the current list page and their loaded working revisions, not all retained revisions or a full workspace package. This download is available for entries the account can read. The separate Export button and Settings → Download export request the administrator-only full content package.

Sources: CMS API routes and export implementation; REST API contract; Selected-content export format and scope; Content list selection and full-export permission.

Know the import and backup boundaries

There is no general Upload workspace JSON restoration screen in the current CMS. The export supports inspection, portability and developer-led migration; it does not imply an implemented one-click importer. Brand token import is a different, limited operation for theme values. For a full restore, use the documented PostgreSQL and media-volume backup procedure.

Before writing an integration that changes many records, test on a separate installation with a backup and realistic references. Publishing may reject missing dependencies, occupied routes or stale revisions even if a draft save succeeded. Keep import credentials separate from routine reading credentials so a reader does not accidentally acquire publication rights.

Sources: REST API contract; CMS API routes and export implementation; Backup operations.

References

  1. API key controls and export link

    Repository path: apps/cms/src/components/admin/settings.tsx

  2. CMS API routes and export implementation

    Repository path: apps/cms/src/app/api/cms/[...path]/route.ts

  3. Bearer credential resolution and API request authentication

    Repository path: apps/cms/src/cms/http.ts

  4. Permission and scope intersection

    Repository path: apps/cms/src/cms/policy/index.ts

  5. REST API contract

    Repository path: docs/api-contract.md

  6. Selected-content export format and scope

    Repository path: apps/cms/src/components/admin/bulk-actions.tsx

  7. Content list selection and full-export permission

    Repository path: apps/cms/src/components/admin/content-list.tsx

  8. Backup operations

    Repository path: docs/operations.md

Workspace

Content types and extensions

Build custom collections, bind fields and release reusable layouts through the administrator interface.

Content types describe structured collections

A content type defines the common shape and behavior of a collection. Posts and Pages are the default collections, protected from retirement and deletion. They share title, body, excerpt, visibility, media and publication behavior, while custom types can add scalar fields and permitted taxonomies. Upgraded installations retain legacy Events and Vehicles under Retired types, with entries and history preserved and website content withdrawn.

Administrators can create custom types in Content types, add supported scalar fields, save a definition draft and review its activation assessment. Activation makes that exact version available to forms, APIs and routes. Built-in definitions remain read-only. After activation, stored keys, field kinds and route capabilities are fixed; labels, help text, order, optional fields, appended choices and relaxed constraints can change compatibly.

TypePublic pathDistinct behavior
Posts/journalArchive, search, categories and tags
PagesRoot and nested pathsParent hierarchy; no ordinary type archive

Sources: Installed type and taxonomy registry; TypeDefinition and supported scalar fields; Content type builder and catalogue.

Draft and activate a collection

Choose Create content type as an administrator. Set labels, the permanent type key and route base, supported taxonomies and public/archive/search behavior. Add fields, defaults and validation limits, then choose Save draft, Check impact, Activate saved version and Activate. The route base must be unique and avoid reserved application paths. Existing editors receive a conflict if a definition changes while they are editing; their values are retained for review.

typescript
{ key: "recipe", label: "Recipes", singular: "Recipe",
  routeBase: "recipes", archive: true, hierarchical: false,
  public: true, searchable: true,
  fields: [
    { key: "preparation", label: "Preparation", type: "text", required: true },
    { key: "minutes", label: "Minutes", type: "number", required: true }
  ],
  taxonomies: ["category", "tag"],
  description: "Recipes with preparation notes and cooking time." }

This example shows the definition shape used by the administrator services. The existing resource API, forms and public loader handle the activated collection. A source-code declaration alone does not register a custom type in an existing database. Relationships, repeaters, computed fields, new taxonomies and specialized indexed queries remain developer extensions.

Sources: Installed type and taxonomy registry; TypeDefinition and supported scalar fields; Content-type and component extension contract.

Retire, restore or permanently delete a collection

Retire type withdraws a collection and its entries from the website while keeping its entries, translations and history. Review the impact and resolve listed dependencies before confirming. Open Retired types and View retained content to inspect its read-only entries. Restore type enables editing again; it does not republish entries or reinstate cancelled publishing schedules. Review and publish entries separately.

Delete permanently removes the type's definitions and all its authored entries, translations, trash and revision content. Resolve current draft, published, scheduled and available reusable-component dependencies, check again and type the exact permanent key to confirm. Shared media, other types, historical snapshots belonging to other resources and audit/publication evidence are retained. The deleted key remains reserved. Posts and Pages are protected. These actions require an administrator session and are unavailable to API keys.

Historical references in other resources may remain after deletion. Their JSON stays unchanged. Deleted entry and type references show notices; original URL links may stop working. Choose Load for repair to copy a historical revision into an unsaved draft based on the current working revision. Autosave pauses, including after tab recovery. Remove or replace deleted references and choose Save changes; unresolved references cannot be saved or restored. Publishing is a separate step.

A changed impact assessment requires fresh review and confirmation. Retrying after a lost response reuses the same operation. Permanent deletion cannot remove copies already stored in earlier exports or backups.

Sources: Content type builder and catalogue; Content type retirement and permanent deletion; Archive route registration.

Validation and presentation are separate decisions

Supported fields include text, number, boolean, calendar date, datetime, select, rich text, typed links, media, single or ordered multiple relationships, and bounded scalar lists. A select declares its allowed options. Relationships target one declared kind/type in the entry language. Lists and multiple relationships allow at most 100 items; models allow at most 50 fields. Posts and Pages accept compatible optional custom fields. Required fields may remain empty in a saved draft but must be valid before publication; unknown field keys are rejected. Date-time values represent instants with an offset, with the interface helping the editor choose a local time. Cross-field rules, such as an event ending after it starts, belong in server validation rather than only in form controls.

Add Content field to a visual composition and choose a type, field and compatible text, number, currency, date or yes/no format. Bindings read the current entry, using its language and the site timezone. Required missing values block publication; optional fields can use a fallback. Use current-entry bindings in content or single:TYPE templates (page for pages). Unscoped shared sections and archive/index templates cannot use them in this release. Numeric fields do not automatically add range filters or specialized sorting.

Sources: TypeDefinition and supported scalar fields; Field, composition and reference validation; Component rendering and fields; Content-type and component extension contract.

Register routes and preserve role boundaries

Definition activation registers archive routes for the configured languages in the same transaction. The seedRoutes command below remains a setup or repair operation for an authorized operator. Route bases are fixed after activation; changing one needs a reviewed migration and redirect plan. Keep private environments and project names aligned with the intended target.

powershell
docker compose --env-file .env.production.local --project-name gcms run --rm --no-deps migrate node --import tsx --input-type=module -e "const {seedRoutes}=await import('./apps/cms/src/cms/services/content.ts'); const {SITE_ID}=await import('./apps/cms/src/cms/contracts.ts'); const {pool}=await import('./apps/cms/src/cms/db/client.ts'); try { await seedRoutes(SITE_ID); } finally { await pool.end(); }"

Administrators and editors can manage registered editorial types through the existing policy. Authors and contributors currently have a narrower own-Post path; adding Recipes must not silently broaden their permissions. If those roles should manage the new collection, update both capability checks and SQL visibility filters with matching tests. Author profiles are a separate resource kind with their own ownership rules, not a content type added to this registry.

Sources: Archive route registration; Capability rules; SQL visibility rules; Content-type and component extension contract.

Treat stored contracts as long-lived data

Each content revision pins its exact definition version. Restoring history preserves that pin and does not rewrite the original snapshot. Component instances similarly pin immutable releases. Administrators build Components from supported blocks, expose typed inputs and publish a release. Inserting materializes defaults. Releasing v2 leaves v1 instances unchanged; a reviewed upgrade changes only a consuming draft, with undo and a separate publication decision. Image inputs use literal media selections because scalar fields are not typed image references.

For relational changes, update the Drizzle schema, generate SQL, review it and verify a fresh database plus an upgrade copy. Preserve custom migration constraints and runtime grants. For components that contain media or resource identifiers, extend reference extraction and authorized rendering as well as the visible editor. Otherwise publication, deletion protection and public media access cannot reliably understand the relationship. Run draft/save/publish/reload, invalid-input, role and public-rendering cases before considering the extension complete.

powershell
npm run db:generate
npm run typecheck
npm run test:integration
node scripts/verify-extension.mjs

Archive hides a component from new insertion without changing pinned instances. Unpublishing or trashing a component with public consumers is rejected, and released revisions and media remain retained. The historical extension exercise predates the database registry; use the current content-builders integration suite for activation and release-pin behavior. Generate migrations only for relational changes and retain the exact version evidence in backups and restores.

Sources: Relational schema; Field, composition and reference validation; Content-type and component extension contract; Executed generic extension exercise; Drizzle schema declarations.

References

  1. Installed type and taxonomy registry

    Repository path: apps/cms/src/cms/definitions/index.ts

  2. TypeDefinition and supported scalar fields

    Repository path: apps/cms/src/cms/contracts.ts

  3. Content type builder and catalogue

    Repository path: apps/cms/src/components/admin/type-builder.tsx

  4. Content type retirement and permanent deletion

    Repository path: apps/cms/src/cms/services/type-lifecycle.ts

  5. Content-type and component extension contract

    Repository path: docs/developer-guide.md

  6. Field, composition and reference validation

    Repository path: apps/cms/src/cms/validation.ts

  7. Component rendering and fields

    Repository path: apps/cms/src/cms/components/config.tsx

  8. Archive route registration

    Repository path: apps/cms/src/cms/services/content.ts

  9. Capability rules

    Repository path: apps/cms/src/cms/policy/index.ts

  10. SQL visibility rules

    Repository path: apps/cms/src/cms/policy/query.ts

  11. Relational schema

    Repository path: apps/cms/src/cms/db/schema.ts

  12. Executed generic extension exercise

    Repository path: docs/evidence/extension-exercise.md

  13. Drizzle schema declarations

    Schema and migration-generation background; CMS compatibility rules are application-specific.

Setup & operations

Local setup

Install a development workspace, create the first account and start both application processes.

Start from a fresh development workspace

Local development needs the repository, Node.js 24, npm and Docker with its Linux engine available. Run commands from the repository root. The complete application lives in apps/cms, while root npm commands select the workspace and preserve root environment, media and credential paths. There is one root package-lock.json. This procedure prepares a new local installation; it is not the upgrade path for an existing site. If the workspace already contains private environment files or authored content, preserve them and inspect its current state instead of repeating initialization. Editors who only need to work on an existing website can use its administration URL without setting up a development machine.

The infrastructure file starts only this project's PostgreSQL and Mailpit services. The application runs on the host so code edits can be picked up by the development server. Docker's health-based startup conditions distinguish a running process from a service ready to accept connections; the commands below wait for the infrastructure before applying migrations. A reachable Docker CLI with an unavailable Linux engine is not sufficient.

powershell
node --version
npm --version
docker version
npm ci
node scripts/init-local.mjs
docker compose --env-file .env.infrastructure.local -f compose.dev.yaml up -d --wait

Sources: Local installation and verification; Supported Node engine and npm scripts; Private local environment generator; Control startup and shutdown order in Compose.

Understand the generated private configuration

The initializer generates random database and authentication secrets and creates .env.infrastructure.local plus .env.local. It refuses to replace existing files. The first file configures Docker infrastructure; the second configures the host application. Both are ignored by Git. Do not paste their contents into issue reports, screenshots or documentation. For the standard local path, the initializer already puts the matching database URL into both files, so there is no need to copy a password through the terminal.

GroCMS is the product name. Existing GCMS_* environment variables, gcms database and project names, and gcms_* role and test-database identifiers stay unchanged for compatibility. Follow the identifiers in these commands instead of renaming existing configuration, data, backups or tokens. grocms.com is the product website; PUBLIC_URL and BETTER_AUTH_URL must identify the site you actually installed.

Local serviceAddressPurpose
Development websitehttp://localhost:3100Public pages and /admin
PostgreSQL127.0.0.1:55432gcms database; local migrations use its owning role
Mailpit SMTP127.0.0.1:51025Captures invitation and recovery email
Mailpit inboxhttp://localhost:58025Read captured development messages

These are local addresses. The default production Compose web port is 3000; installations can choose another port. Do not change origins casually between localhost and another hostname while diagnosing login: authentication and request-origin checks expect the configured application origin. Media for host development is stored under .data/media, independently of Docker's production media volume.

Sources: Private local environment generator; Development PostgreSQL and Mailpit services.

Migrate, then create the first administrator

powershell
npm run db:migrate
npm run setup

Migration prepares the application and queue schema, constraints and indexes. Setup creates the first administrator, registers routes and publishes a minimal website: one Hello world! Post, one Welcome Page as the homepage, official GroCMS branding with its bundled logo, Inter and approved colours, a basic content template and site settings. No sample images, author profiles, taxonomy terms or promotional layouts are installed. Edit or remove these placeholders through normal administration. With the normal local command, the random account password is written to the ignored .local/administrator.json. Open that file privately, move the credential into your password manager and remove the temporary file once it is safely stored.

Setup creates the first administrator only when no account exists; subsequent users join through invitations. Repeating setup requires the recorded owner's current credentials and preserves existing content, including edited or removed placeholders. To choose the richer Fieldnotes reference demo instead, use the command below in place of the initial setup command. Design-only mode prepares three unpublished design drafts before seeding. The demo accepts only an empty content site or those exact untouched drafts; it refuses to replace the published minimal starter or other authored content.

powershell
npm run setup -- --design-only && npm run seed:demo

Sources: Application and queue migration runner; First account and installation setup; Starter resource creation; Optional demo and untouched-starter guard.

Keep web and worker running separately

powershell
npm run dev

Open http://localhost:3100/admin and sign in with the account created by setup. Keep that terminal open. Start another terminal in the same repository and run the worker command below. The web server handles editing and public page requests, while the worker executes due publication jobs. A schedule can be saved successfully while the worker is stopped; that does not mean it has been executed. Verify the worker is ready before relying on a scheduled publication.

powershell
npm run worker

Invitation and password-recovery messages appear in the Mailpit inbox. Mailpit is a local capture service, so an email appearing there does not establish delivery to an external mailbox. To pause work, stop the two host processes with their terminal interrupt controls, then use the infrastructure stop command. That preserves PostgreSQL and mailbox volumes for the next session. Starting them again does not require setup or demo seeding.

powershell
docker compose --env-file .env.infrastructure.local -f compose.dev.yaml stop

Sources: Supported Node engine and npm scripts; Separate worker process; Development PostgreSQL and Mailpit services.

Create the isolated test database before running tests

The integration suite must use gcms_test, not the authored development database. The test initializer checks the bundled loopback database address, creates a separate database if necessary, writes a distinct private test environment and applies migrations there. Existing mismatched test configuration is preserved and rejected rather than silently redirected. This separation lets the tests exercise real accounts, revisions and publication without contaminating the reference website.

powershell
node scripts/init-test.mjs
npm run verify

The verification command covers TypeScript, lint, Vitest and the production build. Browser suites are separate and require their browser binaries plus a running local reference site. Read the current verification instructions before running fixture-based browser or extension exercises against a populated workspace. If installation fails, record the command, error and service status without environment secrets, and use the troubleshooting guide to identify the failing layer before changing configuration.

powershell
npx playwright install chromium firefox
npm run test:e2e

Sources: Isolated test database initializer; Supported Node engine and npm scripts; Local installation and verification.

References

  1. Local installation and verification

    Repository path: README.md

  2. Supported Node engine and npm scripts

    Repository path: apps/cms/package.json

  3. Private local environment generator

    Repository path: scripts/init-local.mjs

  4. Development PostgreSQL and Mailpit services

    Repository path: compose.dev.yaml

  5. Application and queue migration runner

    Repository path: apps/cms/scripts/migrate.ts

  6. First account and installation setup

    Repository path: apps/cms/scripts/setup.ts

  7. Starter resource creation

    Repository path: apps/cms/scripts/starters.ts

  8. Optional demo and untouched-starter guard

    Repository path: apps/cms/scripts/seed.ts

  9. Separate worker process

    Repository path: apps/cms/src/worker/index.ts

  10. Isolated test database initializer

    Repository path: scripts/init-test.mjs

  11. Control startup and shutdown order in Compose

Setup & operations

Production setup and upgrades

Configure and operate the single-host Docker package while preserving authored content and media.

Choose the supported deployment profile

The supported package runs on one Docker Linux host with PostgreSQL, a Next.js web service, a separate worker and persistent private media. An operations image supplies migration, setup and maintenance commands. This guide is for the person responsible for that host and its configuration. A successful local Docker rehearsal demonstrates the package, not that a domain, certificates, external mail delivery, backups and monitoring have been commissioned for a public service.

Normal production Compose binds web to 127.0.0.1:3000. The standard developer server uses localhost:3100. Use the port and origin actually configured for the target installation. Keep the existing Compose project name, database volume and media volume when upgrading. A different project name creates a different installation rather than magically finding the old website's data.

Sources: Production services and environment; Standalone and operations images; Deployment and operational policy.

Create private configuration once

powershell
node scripts/ops/init-production-env.mjs --url https://cms.example.org

Replace the example origin with the intended website origin. The generator creates .env.production.local and refuses to overwrite an existing file. Edit it privately to configure PUBLIC_URL, an immutable release tag, the bind address and port, site timezone, SMTP settings and the worker's paused state. Generated secrets are distinct for database administration, migration, runtime access and authentication. Do not place real values in these guides or pass them in command-line arguments.

The database has no published host port in this profile. The initialization role creates a schema-owning migration role and a restricted runtime role. Web and worker use runtime credentials; migrations use the owner. Runtime access cannot update or delete immutable revision history. Changing a password in an environment file does not change the password of an existing PostgreSQL role. Coordinate real credential rotation with the database and application rather than regenerating the environment.

Next.js distinguishes server configuration from NEXT_PUBLIC_ values exposed to browser bundles. Keep credentials in server-only configuration. GroCMS's Docker context excludes private environment files and runtime media, and the containers receive deployment settings at startup. The supplied nginx example is a starting point for a real TLS hostname; configure it for the actual host before directing internet traffic to the application.

Sources: Production environment generator; Production services and environment; Initial production database roles; Self-hosting Next.js.

Prepare and bootstrap a new installation first

For an empty installation, build the images, start the database and run migrations before account setup. The initial site must exist before the worker can record its health heartbeat. Starting the deployment helper before bootstrap therefore fails worker readiness on a fresh database. Existing installations should skip bootstrap and follow the controlled upgrade section below. Use the same environment, project and release tag throughout.

powershell
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml build web worker
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml up --detach --wait --wait-timeout 120 db
docker compose --env-file .env.production.local --project-name gcms --file compose.yaml run --rm --no-deps migrate

Prepare an ignored .env.bootstrap.local containing GCMS_BOOTSTRAP_EMAIL, GCMS_BOOTSTRAP_NAME and a unique GCMS_BOOTSTRAP_PASSWORD of at least twelve characters. These are application account credentials, not the database administrator password. The setup helper reads the private file and passes values through the child process environment. Production setup requires a supplied password and refuses to create another initial administrator once any account exists.

powershell
node scripts/ops/setup.mjs --env-file .env.production.local --credentials-file .env.bootstrap.local --project gcms

Ordinary setup publishes one Hello world! Post, one Welcome homepage, official GroCMS branding with its bundled logo, Inter and approved colours, a basic content template and settings. There are no sample images, authors, taxonomy terms or marketing layouts. Invite additional people through the administration afterward. For a deliberate fresh demonstration site, add --demo true to the initial setup helper invocation as shown below; it prepares unpublished design drafts before seeding. The demo refuses to replace an initialized minimal site or authored content. Repeating ordinary setup preserves existing content. Store the bootstrap credential securely and remove its temporary file under the host's secret-handling procedure.

powershell
node scripts/ops/setup.mjs --env-file .env.production.local --credentials-file .env.bootstrap.local --project gcms --demo true

Sources: Private production bootstrap helper; First administrator and minimal starter site; Demo seed protection; Deployment lock and migrations; Production services and environment.

Start the initialized site and control later upgrades

After bootstrap, run the deployment helper to start and check the complete installation. For an existing installation, first take and verify a database-and-media backup, prevent concurrent deployments or maintenance writers, and review the release's migrations. Keep the existing private environment and project. Do not bootstrap or seed during an upgrade.

powershell
node scripts/ops/deploy.mjs --env-file .env.production.local --project gcms

Before any build or service change, the helper resolves Compose configuration and checks the whole project inventory. Duplicate service slots, retained recovery containers, uncertain identities or unhealthy running services require separate operator maintenance; the helper does not restart Docker, discard legacy objects or rotate credentials. After this read-only gate passes, it builds web and operations images, starts and waits for PostgreSQL, stops this project's web and worker, runs migrations, then starts and verifies the application services. The migration runner holds its deployment lock across application integrity setup and queue migration. A failed migration leaves application services stopped so incompatible code is not casually placed back in service. Diagnose that failure against the preserved database; do not remove its volume to obtain a green startup.

Migrations 0004 and 0005 rebuild derived public metadata and search indexes. The generated search column can rewrite the projection, and transactional index creation can block reads and publication writes. Rehearse large installations on a disposable copy with a verified backup, a maintenance window and sufficient temporary disk and database log space. Retain the prior compatible application image; do not drop derived tables or reverse schema changes during an uncertain migration.

Sources: Controlled deployment helper; Deployment lock and migrations; Production services and environment.

Verify the running site before routing traffic

powershell
docker compose --env-file .env.production.local --project-name gcms ps
docker compose --env-file .env.production.local --project-name gcms logs --tail 100 web worker

Container health is the first check. The web liveness endpoint is /api/health; /api/ready also checks database/schema access and the configured media location. Test real login, public pages and a permitted media request at the target origin. Check that the worker is ready rather than intentionally paused. Verify one controlled scheduled publication and actual SMTP delivery through the configured provider. Captured development mail is not evidence of production delivery.

Before enabling a proxy cache or CDN, test withdrawal, preview isolation, cookies and response headers through that exact path. The supplied profile does not rely on shared page-response caching. Keep backups, compatible release images and protected recovery configuration together operationally, even though secrets are stored separately from the archive. Record who owns alerts, upgrades and recovery. The verified local package is a sound starting point; these host-specific responsibilities establish whether the public installation is ready to operate.

Sources: Production services and environment; Readiness endpoint; Worker readiness and paused mode; Verified production installation; Deployment and operational policy.

Enable only the public features this installation needs

GCMS_PUBLIC_DOCS_ENABLED and GCMS_ENQUIRIES_ENABLED both default to false. Set a switch to true only for the installation that should expose that feature. Public documentation uses /docs, with public guide search and downloads. Enabling it is refused when existing content, an archive or a redirect already claims /docs or a descendant URL; move those claims deliberately before enabling the feature. Signed-in workspace documentation remains available separately.

Enquiries also require GCMS_ENQUIRIES_TO to contain one valid recipient address. Publish a Contact form component on the intended Page and configure SMTP for the installation. The form saves a fixed demo or quote request; the separate worker handles notification. Test captured mail locally and verify real delivery with the chosen provider before public launch. A visitor cannot change the configured recipient.

Separate local installations need separate databases, media, authentication secrets and origins. Different localhost ports share browser cookie scope, so give an additional installation its own GCMS_AUTH_COOKIE_PREFIX. Leaving this optional prefix unset preserves existing cookies. These switches are deployment configuration; they are not editable through Pages and do not enable open registration.

Sources: Validated installation feature switches; Public documentation route protection; Private enquiry processing.

References

  1. Production services and environment

    Repository path: compose.yaml

  2. Validated installation feature switches

    Repository path: apps/cms/src/cms/installation.ts

  3. Public documentation route protection

    Repository path: apps/cms/src/cms/services/content.ts

  4. Private enquiry processing

    Repository path: apps/cms/src/cms/services/enquiries.ts

  5. Standalone and operations images

    Repository path: Dockerfile

  6. Deployment and operational policy

    Repository path: docs/operations.md

  7. Production environment generator

    Repository path: scripts/ops/init-production-env.mjs

  8. Initial production database roles

    Repository path: ops/postgres/001-roles.sh

  9. Controlled deployment helper

    Repository path: scripts/ops/deploy.mjs

  10. Deployment lock and migrations

    Repository path: apps/cms/scripts/migrate.ts

  11. Private production bootstrap helper

    Repository path: scripts/ops/setup.mjs

  12. First administrator and minimal starter site

    Repository path: apps/cms/scripts/setup.ts

  13. Demo seed protection

    Repository path: apps/cms/scripts/seed.ts

  14. Readiness endpoint

    Repository path: apps/cms/src/app/api/ready/route.ts

  15. Worker readiness and paused mode

    Repository path: apps/cms/src/worker/index.ts

  16. Verified production installation

    Repository path: docs/evidence/final-production-install.json

  17. Self-hosting Next.js

    Server/browser environment distinction and reverse-proxy background.

Setup & operations

Backup and restore

Protect database and media together, rehearse recovery and resume schedules deliberately.

Protect the complete installation

A usable recovery set includes the database, immutable media files, compatible application code or images, and the protected configuration needed to run them. The database contains content history, publication pointers, routes, permissions, accounts and pending work. It does not contain the image and document bytes stored in the private media volume. A content export is useful for portability and inspection, but it excludes authentication, jobs and media bytes and is not the operations backup described here.

The included backup helper uses a maintenance window. It stops the target project's running web and worker, creates a custom PostgreSQL dump, archives media and restarts the exact containers it paused. PostgreSQL's dump provides a database snapshot; it cannot synchronize unrelated filesystem changes by itself. Ensure no separately running scripts, deployments or external writers are changing this installation while the database and media are being captured.

Backup, deployment, setup, restoration and local marketing maintenance commands share a project operation lock in the workspace. A concurrent command fails instead of overlapping the operation. Their read-only preflight refuses ambiguous recovery containers before service actions or backup-health database receipts. If a killed or timed-out process leaves a lock file, confirm that its recorded process and Docker operation have finished before removing that specific lock. Backups validate both archives, restart exact original containers and verify web readiness plus a fresh worker heartbeat before writing a completed manifest. An intentionally paused worker must return to its paused state. Docker accepting a start command alone is not successful recovery; a failed or partial run has no completed manifest.

Sources: Database and media backup helper; Recovery policy and retention commands; PostgreSQL 18: SQL Dump.

Create and retain a completed backup

powershell
node scripts/ops/backup.mjs --env-file .env.production.local --project gcms --output backups/RELEASE_BACKUP

Choose a new output directory for each run. The helper writes database.dump, media.tar.gz and a manifest containing file checksums, database version, source image information and the backup completion time. An incomplete run has no valid completed manifest. Check the command result and the restarted services before treating the run as successful. Reusing the same directory or manually declaring a partial archive complete defeats the verification boundary.

Store an encrypted off-host copy and verify that the copy is available and readable. Keep production secrets and host configuration in a protected recovery store separate from the manifest. The archive still contains sensitive content and account records even though it omits environment secrets. Restrict access to the backup directory, including Windows ACLs where applicable. Retain the application release associated with the backup rather than assuming the newest code can safely read every older schema.

Sources: Database and media backup helper; Archive checksums and operations guards; Recovery policy and retention commands.

Restore into a new isolated project

Prepare a private .env.restore.local with the recovery configuration, a separate loopback inspection port and GCMS_WORKER_PAUSED=true. Choose a fresh project name beginning gcms-restore-. The restore helper refuses an existing target's containers or volumes and verifies checksums before creating the new database. It leaves a failed attempt isolated for diagnosis. Select another fresh target for a retry instead of deleting unfamiliar data to satisfy the guard.

powershell
node scripts/ops/restore.mjs --backup backups/RELEASE_BACKUP --project gcms-restore-check --env-file .env.restore.local

The helper initializes database roles, restores in one transaction, preserves archived table privileges and checks that the runtime role cannot mutate immutable revisions. It restores media into a new volume with the application's ownership. Only the database starts. Web and worker remain stopped, so an overdue schedule cannot publish simply because the database has reappeared. The PostgreSQL 18 image uses a version-specific data layout; use the supplied volume definition rather than copying an older image tutorial blindly.

Sources: Fresh-target restore helper; Archive checksums and operations guards; PostgreSQL 18: SQL Dump; PostgreSQL official Docker image.

Inspect before resuming work

Select the compatible application image and verify the target origin and port before starting the web service. The --no-deps flag in the inspection command avoids automatically starting its worker dependency path. Log in to the restored site, compare working and published revisions, inspect routes and search, and check representative media checksums. Confirm restricted runtime grants and review the pending schedule records against the intended recovery point.

powershell
docker compose --env-file .env.restore.local --project-name gcms-restore-check up -d --no-deps web

An operator may also start a worker explicitly in paused mode to check database connectivity; paused readiness is not evidence that jobs are executing. Reconcile overdue intentions and any external effects that may already have happened before deciding to cancel, reschedule or resume them. Only after verification should the operator configure the final hostname and SMTP, remove the deliberate pause and switch traffic. The local rehearsal verified matching revision pointers, media bytes and a held overdue schedule, rather than merely importing an empty table.

Sources: Fresh-target restore helper; Paused worker behavior; Full content and media recovery verification.

Separate recovery targets from measured guarantees

The planning targets are a fifteen-minute recovery point and a four-hour recovery time. The completed local content-and-media restore finished well within four hours for its small fixture. That does not prove an off-host restore or the same duration at the 100,000-record stress size. Record real archive size, transfer time, import duration and verification time for the installation you operate, and rehearse the complete process on a replacement environment.

A backup starting every fifteen minutes cannot by itself promise a fifteen-minute recovery point when creation and transfer take extra time. The start interval plus maximum delay until a verified off-host copy is available must fit the target; a ten-minute interval with a five-minute completion-and-transfer bound is one conditional example. Failed runs also need detection and escalation. The repository does not install a scheduler or continuous PostgreSQL point-in-time recovery. Those remain explicit operational choices.

Sources: Recovery policy and retention commands; Full content and media recovery verification; Measured dataset and capacity limits.

Retain useful history without endangering live content

Revision retention is a separate audited maintenance operation, not a substitute for backup. Its default preview keeps revisions younger than thirty days and the newest twenty per resource, and considers at most five hundred eligible revisions per batch. Working and published heads, review and schedule references, and unexpired preview selections stay protected. Runtime credentials cannot delete immutable history, so the command requires maintenance authority and the matching private media location.

powershell
node --env-file=.env.maintenance.local --import tsx scripts/retention.ts --site SITE_UUID --operator OPERATOR_NAME

Inspect the dry-run result before adding --apply. Physical media cleanup follows the committed retention audit, allowing interrupted file cleanup to resume without making live database references disappear. Backup retention policy must be considered separately: deleting old live history does not remove it from previously retained archives. Operators should document both policies, the people allowed to run them and the recovery evidence supporting them.

Sources: Audited retention and interrupted cleanup; Recovery policy and retention commands.

References

  1. Database and media backup helper

    Repository path: scripts/ops/backup.mjs

  2. Fresh-target restore helper

    Repository path: scripts/ops/restore.mjs

  3. Archive checksums and operations guards

    Repository path: scripts/ops/common.mjs

  4. Recovery policy and retention commands

    Repository path: docs/operations.md

  5. Paused worker behavior

    Repository path: apps/cms/src/worker/index.ts

  6. Full content and media recovery verification

    Repository path: docs/evidence/full-content-restore.json

  7. Measured dataset and capacity limits

    Repository path: docs/evidence/performance.md

  8. Audited retention and interrupted cleanup

    Repository path: scripts/ops/retention.ts

  9. PostgreSQL 18: SQL Dump

    Database snapshot, restore and role prerequisites; filesystem coordination is provided by the CMS helper.

  10. PostgreSQL official Docker image

    PostgreSQL 18 storage layout and initialization behavior.

Setup & operations

Troubleshooting

Identify whether a problem belongs to editing, permissions, publication or the running services.

Start with the action and the exact outcome

Record what you were trying to do, the item involved, the time and the visible error. Distinguish an unsaved browser change from a saved draft, and a saved draft from a published revision. A missing public change can be expected when only the working version has changed. If the error includes a request identifier, preserve it for the operator to correlate with logs. Do not include passwords, cookies, API tokens or full private environment files in the report.

Keep the editor open while resolving unsaved work. Copy important local text before navigating or refreshing if the interface reports a failed save. A server-side conflict means another accepted version has become the current base. Compare against that revision and deliberately reconcile your changes; blind retries with the old expected revision should continue to fail. Saving the same local input over somebody else's work is not the intended conflict recovery path.

Sources: Structured CMS errors; Request errors and authenticated API boundary; Local save state and conflict recovery.

Resolve publishing and permission errors

ResultLikely meaningNext step
VALIDATIONA field, date, component or identifier is invalidUse the message to repair the saved content; publish requirements may be stricter than draft requirements
CONFLICTWorking revision or publication state changedReload the current server version and reconcile before issuing a new decision
DEPENDENCYA required target is missing, unpublished or incompatibleInspect references and publish or replace the required target through an authorized workflow
FORBIDDENCurrent account or API scope cannot perform the actionAsk an administrator to review the actual role and intended responsibility
UNKNOWN_COMPONENTA saved layout uses an unsupported blockPreserve the draft and ask a developer to restore compatibility or migrate it

An open tab does not preserve an old role after access changes. A designer may inspect editorial content without being permitted to edit it, while an editor does not automatically own design publication. Hiding or enabling a button is not the final authority: the server checks each command. For a route collision, choose the intended unique path or plan an authorized route change; publishing should not overwrite another record's route.

Sources: Draft and publication validation; Publication, preview and schedule rules; Current role capabilities.

Check the selected revision and media access

A preview link can fail because it expired, because a different account opened it or because it names a revision that is no longer valid for that request. Preview selections expire after thirty minutes. Sign in as the creator and generate a fresh preview from saved work. A preview is not an anonymous sharing link, and viewing one does not publish its selected drafts. Compare the preview's chosen revisions with the versions actually saved in the editor.

For a missing image, first check the selected media version and its usage. Uploads and replacements begin without public references. Publishing content that uses the new version is a separate step; older published revisions continue to use their older media identifier. If both authorized administration access and public delivery fail for a known retained file, the operator should inspect the configured media volume and readiness rather than replacing immutable bytes manually. A public 404 can also be the correct result after withdrawal or for private content.

Sources: Publication, preview and schedule rules; Immutable media and access eligibility; Published and preview content eligibility.

Separate a blocked intention from a stopped worker

Inspect the schedule's state, selected revision, due time, timezone and recorded reason. A later draft edit does not change the pinned revision. A newer manual publication, canceled intent, revoked publishing account or changed dependency can make the schedule stale or blocked. Resolve that editorial condition and create the intended new schedule. Do not change timestamps directly in production tables to bypass the state machine.

If valid due work remains pending, the operator should confirm that the separate worker is running, can reach the queue schema and is not deliberately paused for recovery. In development it needs its own npm run worker terminal. Production supplies a worker container. Temporary execution failures use retry metadata and preserve pending state while retries remain; deterministic publication failures are blocked visibly. Worker heartbeat health confirms connectivity, but only a real completed schedule proves the publication path ran.

Sources: Worker process and health; Retry and blocked-state handling; Publication, preview and schedule rules; Queue setup and retry configuration.

Inspect the correct environment without reinitializing it

Operators should first identify the environment. Development uses port 3100 and the separate gcms-dev infrastructure; ordinary production defaults to port 3000. Additional local installations use their own configured ports and cookie prefixes. A different URL may simply be a different database and account set. If Docker cannot connect, check its Linux engine before changing application configuration. If a port is occupied, identify the owning process instead of stopping unrelated projects.

powershell
docker compose --env-file .env.infrastructure.local -f compose.dev.yaml ps
docker compose --env-file .env.production.local --project-name gcms ps
docker compose --env-file .env.production.local --project-name gcms logs --tail 100 web worker db

A live web process can still report /api/ready as unavailable when database schema or media access is wrong. Missing tables after a release point to migration or target-database configuration; inspect the deployment result. A failed controlled migration intentionally leaves web and worker stopped. Existing environment files and initial database roles are not reset by rerunning initialization. In particular, changing a Docker password variable does not rotate an already initialized role. Preserve the database and media while repairing the actual cause.

Sources: Production runtime configuration; Local infrastructure configuration; Migration failure and deployment behavior; Schema and media readiness checks; Preserved existing local configuration; PostgreSQL official Docker image.

Use measured limits when investigating slow responses

Check error rate, database connection pressure, query plans, worker backlog and media access before assuming every slow page is a browser problem. The 11 September 2026 reproduction at 100,000 records reached 11.603 seconds p95 and three HTTP errors. Query improvements reduced the ten-minute result to 778 ms p95 with no errors, but this still misses the 750 ms target; a phrase-heavy variant reached 2.196 seconds. The ten-minute 10,000-record run reached 119 ms p95 with no errors. These synthetic, 20-reader measurements on one shared host do not establish a universal record limit, production hosting guarantee or response-time agreement. Test a larger customer's representative site and search mix on the intended host before making capacity commitments.

When escalating, include the source or image revision, environment name, affected route or resource identifier, sanitized error and time, and the smallest reproducible action. Operators can then connect the report to logs and verification evidence without requesting credentials. Developers should reproduce suspected integrity failures against an isolated test database. Preserve authored content and valid backups throughout diagnosis; restoring, reseeding or deleting history is not an ordinary troubleshooting shortcut.

Sources: Normal and stress workload evidence; Operational diagnosis and recovery policy; Current verification inventory.

References

  1. Structured CMS errors

    Repository path: apps/cms/src/cms/errors.ts

  2. Request errors and authenticated API boundary

    Repository path: apps/cms/src/cms/http.ts

  3. Local save state and conflict recovery

    Repository path: apps/cms/src/components/admin/resource-editor.tsx

  4. Draft and publication validation

    Repository path: apps/cms/src/cms/validation.ts

  5. Publication, preview and schedule rules

    Repository path: apps/cms/src/cms/services/content.ts

  6. Current role capabilities

    Repository path: apps/cms/src/cms/policy/index.ts

  7. Immutable media and access eligibility

    Repository path: apps/cms/src/cms/services/media.ts

  8. Published and preview content eligibility

    Repository path: apps/cms/src/cms/services/public.ts

  9. Worker process and health

    Repository path: apps/cms/src/worker/index.ts

  10. Retry and blocked-state handling

    Repository path: apps/cms/src/worker/handlers.ts

  11. Queue setup and retry configuration

    Repository path: apps/cms/src/cms/jobs/queue.ts

  12. Production runtime configuration

    Repository path: compose.yaml

  13. Local infrastructure configuration

    Repository path: compose.dev.yaml

  14. Migration failure and deployment behavior

    Repository path: scripts/ops/deploy.mjs

  15. Schema and media readiness checks

    Repository path: apps/cms/src/app/api/ready/route.ts

  16. Preserved existing local configuration

    Repository path: scripts/init-local.mjs

  17. Normal and stress workload evidence

    Repository path: docs/evidence/performance.md

  18. Operational diagnosis and recovery policy

    Repository path: docs/operations.md

  19. Current verification inventory

    Repository path: docs/build-status.md

  20. PostgreSQL official Docker image

    Initialization variables apply to an empty data directory; existing databases require deliberate credential changes.