Skip to content

add Keystatic blog CMS#1903

Merged
efstajas merged 10 commits into
mainfrom
blog-cms
May 20, 2026
Merged

add Keystatic blog CMS#1903
efstajas merged 10 commits into
mainfrom
blog-cms

Conversation

@efstajas
Copy link
Copy Markdown
Contributor

@efstajas efstajas commented May 19, 2026

Adds Keystatic at /keystatic so marketing can publish blog posts on their own. Local storage in dev (saves direct to working tree), GitHub storage in prod (each save → branch cms/... → PR against main).

Schema in keystatic.config.ts mirrors the existing zod metadataSchema. Existing posts and images are migrated into the per-slug directory layout Keystatic uses; reader changes are limited to (a) tolerating Date objects for date (YAML auto-parses unquoted YYYY-MM-DD) and (b) no-op for authors since the zod schema already accepts string | string[].

Detailed setup is in docs/BLOG_CMS.md.

GitHub App setup (one-time, for prod)

The CMS UI walks you through this if you just visit https://<deployed>/keystatic while logged in to GitHub as a drips-network/app admin:

  1. Visit /keystatic on the deployed app, click Set up Keystatic with GitHub.
  2. Pick a name (e.g. Drips Blog CMS), accept the suggested permissions, install the app on drips-network/app only.
  3. Keystatic dumps the four env vars to the page — copy them to the deployment:
    KEYSTATIC_GITHUB_CLIENT_ID=<from GitHub App>
    KEYSTATIC_GITHUB_CLIENT_SECRET=<from GitHub App>
    KEYSTATIC_SECRET=<openssl rand -hex 32>
    PUBLIC_KEYSTATIC_GITHUB_APP_SLUG=<the GitHub App slug>
    
  4. Grant marketing users write access to drips-network/app (collaborator role is enough; no other GH perms needed). They sign in to /keystatic with their GitHub account.

If you'd rather create the app manually, the required perms are: Contents R/W, Metadata R, Pull requests R/W. Callback URL is https://<host>/api/keystatic/github/oauth/callback, setup URL is https://<host>/keystatic/setup.

Known follow-ups (in docs)

  • Inline Svelte components in posts (<BlogVideoPlayer /> etc.) aren't editable as CMS blocks. The editor shows them as raw text. Proper block support needs migrating the renderer from mdsvex to markdoc-svelte — separate PR.
  • Default sort in the CMS list view is by slug (Keystatic has no per-field default-sort config). Clicking the Date column header sorts interactively.

Notes for review

  • package.json dev and build:app scripts now have NODE_OPTIONS=--experimental-strip-types. Required because the keystatic-sveltekit Vite plugin loads keystatic.config.ts via raw Node import(), not via Vite's transform.
  • BLOG_CATEGORY_OPTIONS is intentionally duplicated between keystatic.config.ts and src/routes/api/blog/posts/schema.ts — keep them in sync.
  • The dev-vs-prod isDev check in keystatic.config.ts uses window.location.hostname because the CMS UI bundle is built by rolldown (not Vite), and rolldown doesn't inject import.meta.env.DEV. Comment in the file explains.
  • scripts/migrate-blog-images.mjs is a one-off; safe to delete after merge if you don't want it kicking around.

Test plan

  • npm install, npm run dev, open http://127.0.0.1:5173/keystatic — admin loads without GitHub prompt
  • /blog and a few post detail pages still render correctly with the migrated frontmatter + image paths
  • In Keystatic, edit an existing post (e.g. change excerpt) and save — confirm the .md file updates in the working tree
  • Create a new post via Keystatic with cover image + body image + multi-author selection — confirm file shape matches existing posts

efstajas added 3 commits May 19, 2026 18:17
Mounts Keystatic at /keystatic via keystatic-sveltekit. Storage is local
in dev, GitHub (PR per save, branchPrefix cms/) in prod. Schema mirrors
the existing zod metadataSchema; categories list is duplicated because the
config file is loaded raw by Node at Vite startup.

Setup, env vars, and the GitHub App config are in docs/BLOG_CMS.md.
Each post's cover + body images move to static/assets/blog-images/<slug>/,
author avatars move to .../authors/<id>/. Single-string authors become arrays
so the Keystatic schema can use a single fields.array(fields.relationship).
Reader already handles both shapes via z.union, so existing posts keep
rendering unchanged.
CMS routes 404 on alt-chain deployments — same convention the blog uses
for redirecting to drips.network/blog.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates the Keystatic CMS into the SvelteKit app (served at /keystatic) so marketing can manage blog content via a git-based workflow: local file edits in dev and GitHub-backed PR creation in production. It also migrates existing blog posts and static assets into Keystatic’s per-slug directory layout, with minimal reader/schema changes to keep existing rendering working.

Changes:

  • Add Keystatic integration (Vite plugin + SvelteKit handle) and a repo-root keystatic.config.ts.
  • Update blog metadata parsing to tolerate YAML-parsed Date values and normalize authors to arrays.
  • Migrate blog posts and images into Keystatic-friendly directory structure; add CMS setup docs.

Reviewed changes

Copilot reviewed 38 out of 104 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
vite.config.ts Registers the Keystatic Vite plugin and adjusts dev server host behavior for Keystatic UI redirects.
static/assets/blog-images/scroll-argentinia-hackathon/collab-drip-list-hiw.png Adds migrated blog image asset under per-post directory.
static/assets/blog-images/ens-funds-its-critical-open-source-dependencies/ens-2.png Adds migrated blog image asset under per-post directory.
static/assets/blog-images/dependency-funding-with-drips/how-drip-lists-work.png Adds migrated blog image asset under per-post directory.
static/assets/blog-images/authors/jason/avatarUrl.png Adds migrated author avatar asset under per-author directory.
src/routes/api/blog/posts/schema.ts Normalizes date values so YAML Date objects are accepted as strings.
src/hooks.server.ts Adds Keystatic request handling and guards CMS routes on alt-chain deployments.
src/blog-posts/wave-4-changelog.md Migrates frontmatter formatting and image paths to per-slug layout.
src/blog-posts/wave-3-changelog.md Updates cover image path and normalizes author to array.
src/blog-posts/wave-2-changelog.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/the-monthly-wave.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/scroll-argentinia-hackathon.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/rpgf-launch-with-filecoin.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/radworks-gives-1m-to-foss-dependencies-with-drips.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/q4-2025-roundup.md Updates cover image path and normalizes author to array.
src/blog-posts/q4-2024-feature-roundup.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/q2-2025-roundup.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/q1-2026-roundup.md Updates cover image path and normalizes author to array.
src/blog-posts/q1-2025-roundup.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/open-source-collective.md Updates cover image path and normalizes author to array.
src/blog-posts/octant-teams-up-with-drips-to-fund-its-dependencies.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/introducing-collaborative-drip-lists.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/full-rpgf-on-drips.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/exploring-sustainable-funding-for-digital-public-goods-with-unicef.md Updates cover image path and normalizes author to array.
src/blog-posts/ens-funds-its-critical-open-source-dependencies.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/drips-web3privacynow.md Updates cover image path and normalizes author to array.
src/blog-posts/drips-wave-whats-launching-in-january.md Updates cover image path and normalizes author to array.
src/blog-posts/devcon-devconnect-support-their-dependencies-with-drips.md Updates cover image path and normalizes author to array.
src/blog-posts/dependency-funding-with-drips.md Updates cover/body image paths and normalizes author to array.
src/blog-posts/creating-meaningful-issues.md Updates cover image path and normalizes author to array.
src/blog-posts/berlin-blockchain-week-guide.md Updates cover image path and normalizes author to array.
src/blog-posts/authors/ugo-x.json Updates author avatar path to per-author directory layout.
src/blog-posts/authors/kat.json Updates author avatar path to per-author directory layout.
src/blog-posts/authors/jason.json Updates author avatar path to per-author directory layout.
src/blog-posts/authors/ele.json Updates author avatar path to per-author directory layout.
src/blog-posts/authors/becca.json Updates author avatar path to per-author directory layout.
src/blog-posts/amplifying-the-impact-of-funding.md Updates cover image path and normalizes author to array.
scripts/migrate-blog-images.mjs Adds one-off script to migrate images into Keystatic’s expected layout and rewrite refs.
README.md Documents the new /keystatic CMS entrypoint and links to setup guide.
package.json Adds Keystatic/React deps and sets NODE_OPTIONS=--experimental-strip-types for dev/build.
keystatic.config.ts Defines Keystatic collections/schema and dev vs prod storage selection.
docs/BLOG_CMS.md Adds CMS setup/workflow documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/hooks.server.ts
Comment thread keystatic.config.ts Outdated
Comment thread keystatic.config.ts Outdated
Comment thread docs/BLOG_CMS.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 38 out of 104 changed files in this pull request and generated 3 comments.

Comment thread keystatic.config.ts Outdated
Comment thread keystatic.config.ts
Comment thread src/hooks.server.ts
@efstajas efstajas merged commit 25f5b10 into main May 20, 2026
6 of 8 checks passed
@efstajas efstajas deleted the blog-cms branch May 20, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants