Skip to content

Add markdown blog CMS#59

Merged
andrewzolotukhin merged 3 commits into
mainfrom
feat/markdown-blog-cms
Jun 28, 2026
Merged

Add markdown blog CMS#59
andrewzolotukhin merged 3 commits into
mainfrom
feat/markdown-blog-cms

Conversation

@andrewzolotukhin

@andrewzolotukhin andrewzolotukhin commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Original request

The request was to add a modern Markdown-based open-source CMS for a website blog, extend the PR Workflow skill so feature PRs can write Markdown blog posts for SEO, add a Blog link to the home page, update the skill itself, then backfill the blog by creating posts for shipped GitHub PRs with screenshots where possible.

Summary

Adds a Git-backed Markdown/MDX blog for xpenser using Keystatic, exposes public /blog and /blog/[slug] routes, updates the PR workflow skill, and backfills the blog with release posts for every merged PR through #58. The blog now contains 54 posts total: the CMS workflow post for PR #59 plus 53 historical PR posts. Open PR #46 is intentionally excluded until it ships.

What changed

  • Added Keystatic configuration for apps/web/content/blog/*.mdx with title, slug, description, publish/update dates, target keyword, secondary keywords, draft state, source PR metadata, optional hero screenshot metadata, and MDX content.
  • Added guarded Keystatic admin/API routes at /keystatic and /api/keystatic; local editing is enabled outside production, while production editing requires Keystatic GitHub credentials.
  • Added public blog index/post routes with MDX rendering, canonical metadata, JSON-LD, sitemap entries, Open Graph/Twitter image support, and screenshot rendering for posts with hero images.
  • Added 53 backfilled MDX posts for merged PRs feat(timezone): add timezone support with IANA validation and formatting #1-32, Fix issue template questions link #37-45, and Add transaction tags and tag reports #47-58, each with source PR links, shipment dates, keyword metadata, and internal links.
  • Added three reusable committed blog screenshots under apps/web/public/blog for dashboard, transactions, and preferences/MCP/email-report surfaces; non-visual posts fall back to /og-image.png.
  • Added Blog links to the home page internal SEO card grid, public header, and footer.
  • Updated Docker runtime copying so blog content is available in standalone deployments.
  • Updated .agents/skills/pr-workflow/SKILL.md so public feature PRs add/update a blog post or document a skip reason, and so PR-backed posts include source metadata and real screenshot guidance.
  • Added unit/component/e2e coverage for blog loading, rendering, metadata, sitemap, navigation, source links, image rendering, and public route access.

Reasoning

Keystatic fits this repo because it keeps content as reviewed files in Git, works with the existing Next.js App Router app, and gives maintainers a CMS UI without adding a database. The production admin path is guarded so missing CMS credentials do not expose local filesystem editing or break normal builds.

The backfill keeps the blog as a truthful release archive instead of publishing unmerged work. Posts use real merge/shipment dates and real product screenshots where they honestly match the feature area. Internal/config-only posts intentionally use the default OG image rather than invented screenshots.

Blog posts

  • Existing CMS workflow post: /blog/markdown-blog-workflow
  • Backfilled archive size: 53 additional merged-PR posts
  • Screenshot-backed examples:
    • /blog/dashboard-vendor-view-controls
    • /blog/transaction-scan-progress-fix
    • /blog/configurable-email-finance-reports
  • Default-image fallback example: /blog/disable-gtm-in-pr-environments

Validation

  • npm run lint
  • npm run typecheck
  • npm test - 83 files, 447 tests
  • npm run build -w @xpenser/web - generated 60 static pages
  • MDX consistency audit: 54 posts, no PR Add cash-flow forecast report #46 post, no duplicate source PR numbers, no missing screenshot assets
  • Focused local e2e: PLAYWRIGHT_BASE_URL=http://127.0.0.1:3012 npm run test:e2e -- --project=chromium --no-deps tests/e2e/public-auth.spec.ts -g "serves the public blog index and a published post"
  • GitHub check: Lint and test
  • GitHub check: Deploy PR environment
  • GitHub check: Playwright e2e
  • Preview QA: PLAYWRIGHT_BASE_URL=https://xpenser-pr-059.cleverbrush.com npm run test:e2e -- --project=chromium --no-deps tests/e2e/public-auth.spec.ts -g "serves the public blog index and a published post"
  • SigNoz verification unavailable: traces/logs for xpenser-web-pr-59 and xpenser-web-pr-059 returned no service values or rows after preview QA; http.server.duration.count returned no PR Add markdown blog CMS #59 metric data in the validation window.

Screenshots / Preview

Preview URL: https://xpenser-pr-059.cleverbrush.com

Committed blog screenshots:

  • /blog/dashboard-month.png
  • /blog/transactions.png
  • /blog/preferences-mcp-email.png

Preview QA validated /blog, /blog/markdown-blog-workflow, /blog/dashboard-vendor-view-controls, /blog/disable-gtm-in-pr-environments, screenshot rendering, fallback OG image metadata, and source PR links.

Checklist

  • I kept the change focused.
  • I updated docs or tests where needed.
  • I checked for secrets, local env files, and generated build output.
  • API changes keep contracts, endpoint metadata, and handlers aligned. No public API contract changes were made.

@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-59 June 27, 2026 23:26 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-59 June 27, 2026 23:38 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-59 June 28, 2026 00:31 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin force-pushed the feat/markdown-blog-cms branch from 9b65702 to 716f99a Compare June 28, 2026 00:39
@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-59 June 28, 2026 00:41 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin merged commit 61d27b7 into main Jun 28, 2026
4 checks passed
@andrewzolotukhin andrewzolotukhin deleted the feat/markdown-blog-cms branch June 28, 2026 00:58
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.

1 participant