Skip to content

Share Graft CMS across Astro and Next, remove Sanity, pin Bun 1.4 - #53

Merged
cursor[bot] merged 7 commits into
masterfrom
cursor/graft-shared-cms-fefd
Sep 3, 2026
Merged

cursor[bot] merged 7 commits into
masterfrom
cursor/graft-shared-cms-fefd

Conversation

@AndersonDesign1

@AndersonDesign1 AndersonDesign1 commented Sep 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

Graft is now the CMS for both site versions. Sanity is gone.

  • Shared CMS: schema + MDX live in packages/content (@andy-portfolio/content). graft compile writes the static SQLite index both apps read.
  • Astro (apps/web, port 3000): still the live Vercel site. Blog bodies stay on Astro content collections + @astrojs/mdx.
  • Next (apps/web-next, port 3001): restored as a workspace so bun dev / bun lint / bun build include it. Not deployed. Blog uses @usegraft/sdk-next MdxBody; projects and case studies come from the same Graft collections.
  • Removed: apps/studio, packages/sanity-config, Sanity export script, revalidate webhooks, Sanity env on Turbo/CI.
  • Bun 1.4.0 is pinned (packageManager, CI setup-bun). First 1.4 install wrote configVersion: 1 in bun.lock (still hoisted).

Two versions + Graft

Version Path Port Deploy
Astro 7 apps/web 3000 Vercel (Root Directory apps/web)
Next.js 16.3 apps/web-next 3001 Local archive only

Author posts, projects, and case studies once under packages/content/content/.

Vercel stays Astro-only: apps/web/vercel.json buildCommand is bun run build (the Astro app script, which compiles Graft then runs astro build). There is no apps/web-next/vercel.json.

Index path (dev + prerender)

The compiled SQLite file lives at packages/content/.graft/index.db. Resolving it via import.meta.url broke in two bundlers:

  • Astro prerender rewrote it to dist/server/.prerender/.graft/index.db
  • Next Turbopack resolved @andy-portfolio/content to a virtual [project]/packages/content path that is not on disk

getIndexPath() now confirms the candidate exists (or falls back to cwd / GRAFT_CONTENT_ROOT) at open time.

CI Next build (no secrets)

Lint’s new web-next build step has no Spotify/Resend secrets. Next was throwing while collecting /api/spotify/now-playing because env.ts parsed those keys at import. The archive now matches Astro: lazy getSpotifyEnv / getResendEnv, Resend constructed inside handlers, Spotify idle {isPlaying:false} when env is missing. Verified locally with those variables unset.

Greptile P1: stale static sitemap

Deleted apps/web-next/public/sitemap.xml so src/app/sitemap.ts owns /sitemap.xml (Graft posts + /case-studies/*, no obsolete /case-study/*). Deleted the same file from apps/web/public/ so Vercel does not ship it beside @astrojs/sitemap (sitemap-index.xml / sitemap-0.xml). Confirmed Next :3001/sitemap.xml includes i-built-smol and both case studies.

Bun 1.3.14 vs 1.4.0

Same machine (Linux), warm node_modules + bun cache, 3 runs, median. GNU time for wall + max RSS; bun --version also timed with perf_counter (GNU time rounds sub-10ms to 0.00). Nested scripts used the version under test via PATH.

1.3.14 can still bun install --frozen-lockfile against this 1.4 configVersion: 1 lockfile (no rewrite).

Command 1.3.14 median 1.4.0 median Notes
bun --version startup 1.00 ms (5.7 MB) 0.85 ms (4.0 MB) 20 warm runs after dropping the first
bun install --frozen-lockfile 0.02 s (25.2 MB) 0.02 s (18.6 MB) Warm graph; RSS is the real 1.4 win here
content compile 0.43 s 0.44 s Graft CLI; wash
bun run lint 1.28 s 1.27 s Turbo --force; wash
Astro web build 5.89 s (934 MB) 5.96 s (1178 MB) Work is Node 22 (Astro/Vite)
Next web-next build 3.96 s 4.02 s Incremental .next after the first 1.4 run

Do not read this as live-site TTFB. Vercel’s Astro compile still runs on Node 22. Bun 1.4 only changes local/CI bun install and bun run of those scripts.

Verification

Lint, format, Astro typecheck, Next tsc, Astro production build, and Next production build all passed locally after the index-path fix.

agent-browser walk of Astro :3000 and Next :3001: /, /projects (SEO filter), both blog posts, both case studies, Astro mobile viewport. Same Graft titles, no cdn.sanity.io.

Astro home Selected Works
Next home Selected Works
Astro projects SEO filter
Astro Smol blog post
Next Smol blog post
Astro projects on mobile

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Summary by cubic

Replaces Sanity with a shared Graft CMS for both the live Astro site and the local Next.js archive, so both apps read the same compiled content index from @andy-portfolio/content, and pins Bun to 1.4.0.

Changes

  • Moves schema and MDX into @andy-portfolio/content; graft compile writes the SQLite index both apps read.
  • Astro keeps its content collections for blog bodies; the Next app uses @usegraft/sdk-next for MDX and reads the same index for projects and case studies.
  • Resolves the index path at open time via @andy-portfolio/content/package.json, with a cwd fallback for Turbopack's virtual paths, so Astro's prerendered build finds it.
  • Allows 127.0.0.1 as a dev origin in the Next app so agent-browser can reach the dev server.
  • Reads Next Spotify and Resend env lazily so next build works in CI without secrets.
  • Removes apps/studio, packages/sanity-config, the Sanity export script, and the revalidate webhook routes.
  • Adds apps/web-next back to the Turbo workspace and updates its dev/build scripts to compile Graft first.
  • Removes both static public/sitemap.xml files so the generated sitemaps own /sitemap.xml.
  • Pins Bun to 1.4.0 in packageManager and the CI setup.

Migration

  • Run bun install to update the lockfile.
  • Remove Sanity environment variables and webhook secrets from any deployments or local env files.

Written for commit 6bede75. Summary will update on new commits.

Review in cubic

Lift schema and MDX into packages/content, restore the Next archive as a
local workspace on the same static index, and remove Studio plus
sanity-config. Vercel still builds only the Astro app.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
@vercel

vercel Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
andy-portfolio Ready Ready Preview Sep 3, 2026 11:54am UTC

@coderabbitai

coderabbitai Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: c4eb6de8-3be0-4d2e-8d56-d4fd1276a6fd


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…chunks.

Astro prerender rewrites import.meta.url to dist/server/.prerender, so a
relative path to graft.config.ts looked for .graft/index.db in the output
tree. Look up @andy-portfolio/content/package.json instead (with cwd fallbacks).

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
root: false walks up to the repo config, whose force-ignore then lints zero files.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
createRequire can succeed with a path that is not on disk. Confirm the
content root exists, then fall back to cwd, and resolve at open time.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
next dev binds localhost and blocks HMR/static chunks from 127.0.0.1, which
is what agent-browser uses unless the origin is allowlisted.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
GitHub Actions has no secrets, and next build was evaluating env.ts while
collecting /api/spotify/now-playing. Match Astro: lazy getters, construct
Resend inside handlers, and return {isPlaying:false} when Spotify env is missing.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@AndersonDesign1

Copy link
Copy Markdown
Owner Author

@greptile-apps

@greptile-apps

greptile-apps Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This change moves portfolio content to the shared Graft package and updates the Astro site and local Next archive to consume it. Production validation confirmed that the migrated blog and case-study pages build and serve their expected Graft content. However, the legacy static sitemap still overrides the generated sitemap, causing search engines to receive stale and invalid route entries.

Confidence Score: 4/5

Not merge-safe until the static sitemap no longer overrides the Graft-generated sitemap.

There is one verified non-security P1 finding. Under the scoring rules, a single non-security P1 results in a score of 4.

Files Needing Attention: apps/web-next/public/sitemap.xml should be removed, renamed, or generated from the shared Graft content so that apps/web-next/src/app/sitemap.ts serves /sitemap.xml.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a proof for the posted P1 finding and prepared a production build with compiled Graft content.
  • T-Rex validated the proof by inspecting the runtime public-route contract output.
  • T-Rex examined the runtime sitemap HTTP response to confirm route discovery.
  • T-Rex authored a route-contract test script and captured its source for reproducibility.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. apps/web-next/public/sitemap.xml, line 36-58 (link)

    P1 Static sitemap shadows Graft sitemap

    public/sitemap.xml is served for /sitemap.xml instead of the Graft-backed metadata route in src/app/sitemap.ts. Crawlers therefore receive stale XML that omits the migrated i-built-smol post and advertises obsolete singular /case-study/* URLs rather than the active /case-studies/* pages. Remove or rename this static file so the generated sitemap owns the route, or generate the static XML from the same Graft content.

    Artifacts

    Production build with compiled Graft content

    • trex-artifacts/graft-next-01-before.log — Ran `bun run --filter=@andy-portfolio/web-next build` from `/home/user/repo`; Graft compiled 15 documents and Next prerendered the migrated blog and case-study static paths successfully.

    Runtime public-route contract output

    • trex-artifacts/graft-next-02-after.log — Started the compiled Next archive and requested the blog index, both migrated blog pages, and both case-study pages; all returned 200 with expected Graft content before the sitemap assertion failed.

    Runtime sitemap HTTP response

    • trex-artifacts/graft-next-sitemap-response.log — Captured the real HTTP response from `http://127.0.0.1:3001/sitemap.xml\`; it is the stale static XML with old `www` and singular `/case-study/` entries and no `i-built-smol` entry.

    Route-contract test script source

    • trex-artifacts/graft-next-route-contract.sh — Exact Bash source authored for the production-server checks of migrated public pages and expected Graft sitemap entries.

    Captured route-contract test script source

    • trex-artifacts/graft-next-route-contract-source.log — Command-captured contents of the exact test script used in the runtime validation.

    View artifacts

    T-Rex Ran code and verified through T-Rex

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/web-next/public/sitemap.xml
    Line: 36-58
    
    Comment:
    **Static sitemap shadows Graft sitemap**
    
    `public/sitemap.xml` is served for `/sitemap.xml` instead of the Graft-backed metadata route in `src/app/sitemap.ts`. Crawlers therefore receive stale XML that omits the migrated `i-built-smol` post and advertises obsolete singular `/case-study/*` URLs rather than the active `/case-studies/*` pages. Remove or rename this static file so the generated sitemap owns the route, or generate the static XML from the same Graft content.
    
    ---
    
    For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Prompt To Fix All With AI
### Issue 1
apps/web-next/public/sitemap.xml:36-58
**Static sitemap shadows Graft sitemap**

`public/sitemap.xml` is served for `/sitemap.xml` instead of the Graft-backed metadata route in `src/app/sitemap.ts`. Crawlers therefore receive stale XML that omits the migrated `i-built-smol` post and advertises obsolete singular `/case-study/*` URLs rather than the active `/case-studies/*` pages. Remove or rename this static file so the generated sitemap owns the route, or generate the static XML from the same Graft content.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Parse Next Spotify and Resend env on req..." | Re-trigger Greptile

public/sitemap.xml was served instead of Next’s sitemap.ts, advertising
obsolete /case-study/* URLs and omitting i-built-smol. The same file in
apps/web would ship on Vercel beside @astrojs/sitemap.

Co-authored-by: Anderson Joseph <hello@andersonjoseph.com>
@cursor
cursor Bot merged commit 355a5c1 into master Sep 3, 2026
8 checks passed
@cursor
cursor Bot deleted the cursor/graft-shared-cms-fefd branch September 3, 2026 12:03

This branch was successfully deployed

1 active deployment
Preview — 6bede753 Deployed Sep 3, 2026 by vercel[bot]
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