Appearance
Content Management
Marketing content has two sources. General site copy is versioned with the application; posts, authors, categories, and blog media are managed in Sanity.
Content Ownership
| Content | Source | Change process |
|---|---|---|
| Shared labels, metadata copy, page copy, and repeated calls to action | apps/marketing/src/utils/strings.ts | Code review and application deployment |
| Main navigation and footer link groups | apps/marketing/src/data/site-navigation.ts | Code review and application deployment |
| Structured page-specific data | apps/marketing/src/data/ or the owning feature directory | Code review and application deployment |
| Route composition and tightly coupled content | apps/marketing/src/app/ and src/components/ | Code review and application deployment |
| Blog posts, authors, categories, and images | Sanity documents | Draft, review, and publish in Sanity Studio |
| CMS field definitions and validation | apps/marketing/src/sanity/schemaTypes/ | Code review, Studio deployment, then content updates |
| Page metadata and JSON-LD assembly | src/utils/metadata/ and src/utils/schema/ | Code review and application deployment |
Use the narrowest source that still keeps repeated content consistent. A label used by several components belongs in strings.ts; a navigation destination belongs in site-navigation.ts; a one-off section can keep its copy with the component. Do not introduce a second content registry for the same text.
Code-Driven Content
src/utils/strings.ts contains shared copy for navigation, the footer, page metadata, blog UI, homepage sections, early access, newsletter, contact, demo, and FAQ. Components select the relevant branch rather than embedding another copy of a repeated label.
src/data/site-navigation.ts combines those labels with destinations and descendant-matching behavior:
ts
const siteLinks = {
product: { label: strings.navigation.links.product, href: '/demo' },
blog: {
label: strings.navigation.links.blog,
href: '/blog',
matchDescendants: true,
},
faq: { label: strings.navigation.links.faq, href: '/faq' },
contact: { label: strings.navigation.links.contact, href: '/contact' },
}The exported primary and footer groups feed desktop navigation, mobile navigation, and the footer. Change a destination there so all shell variants remain aligned.
Focused data modules hold larger structured collections. For example, src/data/earlyAccess.ts supplies event-type and preview data to the early-access components. Keep rendering and event behavior in components; keep reusable data and copy out of JSX when several components consume it.
Sanity Content
Sanity is limited to the blog domain. src/sanity/schemaTypes/ defines post, author, category, and Portable Text block schemas. src/sanity/structure.ts configures the Studio navigation, and sanity.config.ts registers the schemas, structure, project, dataset, and /studio base path.
The marketing application does not mount Studio in the App Router. Run the standalone Studio from apps/marketing/:
bash
pnpm exec sanity dev --port 3334Use the dataset configured for the current environment. Sanity supplies draft and publish workflow, version history, and media management. The site reads published content through the Sanity CDN; it does not expose draft mode or live preview.
Schema Changes
A schema field is not available to the site until every consuming layer understands it:
- Update the schema in
src/sanity/schemaTypes/. - Update the corresponding type under
src/types/blog/. - Add the field to the relevant GROQ projection under
src/utils/blog/. - Update metadata, sitemap, or presentation code that consumes it.
- Deploy the Studio schema before editors depend on the new field.
For route fetching, filtering, Portable Text, images, metadata, and sitemap behavior, see Blog System.
Metadata Content
Page components use getPageMetadata() instead of constructing unrelated metadata objects inline. Static page titles, descriptions, and keywords come from the metadata branch in strings.ts. Blog-post metadata is derived from the fetched post, including a plain-text excerpt from Portable Text.
Structured data is assembled separately through the schema helpers. Keep visible marketing copy, metadata, and JSON-LD consistent when a page's purpose or claims change. See SEO and Schema.
Updating Content
Code-Driven Pages
- Change the existing copy or data source rather than adding a duplicate constant.
- Check every component that consumes that source, especially desktop and mobile shell variants.
- Preview responsive layouts and verify that longer copy still reflows.
- Run the marketing tests, type check, and build for changes that affect rendering or metadata.
Blog Documents
- Edit and review the document in the standalone Sanity Studio.
- Confirm required relationships, slug, image alt text, and publication date.
- Publish the document to make it available through the CDN-backed client.
- Check the relevant listing and detail routes, including metadata and sitemap output.
The current client does not configure an ISR interval, cache tags, or on-demand revalidation. Plan content freshness and draft-preview behavior together before adding any of those mechanisms.