shipanysaas
Documentation
Back
  • Getting started
    • Install and run
    • Project structure
    • Configuration
    • Commands
  • Coding agents
    • Agent skills
  • Authentication
    • Email sign-in
    • OAuth providers
    • Two-step sign-in and passkeys
  • Database
    • Migrations
    • Row-level security
    • Database tests
    • Reading and writing data
  • Features
    • Teams and invitations
    • Email
    • File uploads
    • Blog, docs and changelog
  • Billing
    • Stripe and Lemon Squeezy
    • Pricing plans
    • Webhooks
  • Live demo
  • Blog, docs and changelog

    The blog, these docs and the changelog are Markdoc files in apps/web/content. How they are organised, their fields, and the showcase list.

    /blog, /docs and /changelog render content through a CMS client chosen by CMS_CLIENT:

    • keystatic (the value in apps/web/.env): Markdoc files in the repository.
    • wordpress: posts from a WordPress site at WORDPRESS_API_URL.

    The content folder

    With Keystatic, content lives in apps/web/content/ (set by NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH=./content):

    FolderPage
    posts//blog/<file name>
    documentation//docs/<folder>/<file name>
    changelog//changelog/<file name>
    showcase/products.json/showcase (read directly, not through the CMS)

    Every published post, doc page and changelog entry is added to the sitemap, with publishedAt as its last-modified date.

    Fields

    Each .mdoc file starts with front matter. The schema is in packages/cms/keystatic/src/keystatic.config.ts:

    FieldUsed for
    titlePage title
    descriptionSubtitle, card text and meta description
    publishedAtDate (YYYY-MM-DD). Blog and changelog are sorted by it, newest first
    statusOnly published entries are shown. Also draft, review, pending
    orderPosition in the docs sidebar
    labelShorter name for the docs sidebar
    imageCover image for posts, from public/site/images
    categories, tagsLists of strings
    collapsible, collapsedDocs only: make a sidebar section fold

    How the docs sidebar is built

    A folder with a file of the same name is a section: documentation/billing/billing.mdoc is the Billing page, and the other files in documentation/billing/ appear under it. Sections and pages are sorted by order. The /docs landing page shows one card per section.

    Writing

    The body is Markdoc, which reads like Markdown: headings, lists, links, code blocks, tables and images work. No custom Markdoc tags are registered; add your own in packages/cms/keystatic/src/custom-components.tsx.

    The Keystatic editing UI is not mounted, so you edit the files directly (or let your agent do it). pnpm turbo gen keystatic adds the admin routes and the @keystatic/next dependency if you want an editor. Storage defaults to local files; NEXT_PUBLIC_KEYSTATIC_STORAGE_KIND can be github or cloud with the related KEYSTATIC_* variables.

    The showcase list

    content/showcase/products.json is an array of products checked against apps/web/app/[locale]/(marketing)/showcase/_lib/showcase.schema.ts: slug, name, tagline, url, makerName, optional makerUrl, category, platforms, launchedAt, featured and an optional logo. The form on /showcase emails submissions to CONTACT_EMAIL. You review them and add the ones you accept to the file. An empty array shows a "no products yet" message.