refactor(marketing): drop the docs and blog, now published drives elsewhere - #2427
refactor(marketing): drop the docs and blog, now published drives elsewhere#24272witstudios wants to merge 8 commits into
Conversation
…ewhere Removes what the app no longer serves: 34 docs page.tsx files (~3,000 lines of markdown embedded in TSX), the 7-post blog and its 888-line data.ts, and 30 MB of hero PNGs under public/blog. The content now lives in two PageSpace drives published at docs.pagespace.ai and blog.pagespace.ai (migrated by scripts/migrate-docs-blog-to-drives.ts). Links out to those hosts go through the new lib/sites.ts helpers rather than bare paths — they are cross-origin now, and a bare /docs/... would resolve against pagespace.ai and take the edge 301 instead of going straight to the destination. Cascading removals, each because its only consumer was deleted: - DocsContent/DocsSidebar, and with them react-markdown + remark-gfm - schema.tsx's Article schema (the published blog emits its own) - pageMetadata.blog / .docs - ui/scroll-area.tsx + @radix-ui/react-scroll-area, hooks/use-mobile.ts (surfaced by knip:check, not guesswork) search-data.ts keeps its hand-maintained docs entries, repointed at the new host, but stops indexing blog post bodies — that index was built from data.ts at build time and there is no longer a build-time source for it. The palette still links to the blog itself. sitemap.ts no longer lists either section. Both published drives emit their own sitemap.xml with canonical URLs on their own host; listing them under pagespace.ai would advertise URLs that only 301. DO NOT MERGE before the Caddyfile change in PageSpace-Deploy is deployed. Until then the edge still routes /docs and /blog here, and merging this takes both sections down. Verified: typecheck, lint, knip:check, and a marketing build all pass with neither route present. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwC25dWRtdaV6h3mjqqsog
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cee2c158de
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export const DOCS_URL = process.env.NEXT_PUBLIC_DOCS_URL ?? 'https://docs.pagespace.ai'; | ||
| export const BLOG_URL = process.env.NEXT_PUBLIC_BLOG_URL ?? 'https://blog.pagespace.ai'; |
There was a problem hiding this comment.
Expose the new site URLs to Docker builds
When a self-hosted or staging Docker build passes NEXT_PUBLIC_DOCS_URL or NEXT_PUBLIC_BLOG_URL, Docker discards them because the marketing Dockerfile's builder declares and exports only the existing public variables at lines 46–58. Since Next.js bakes these values into the client bundle during next build, setting them on the runtime container cannot help, and every Docker image continues linking to the production docs and blog hosts; add both variables to the builder's ARG and ENV lists (and pass them from the relevant Compose/workflow configuration).
AGENTS.md reference: AGENTS.md:L230-L234
Useful? React with 👍 / 👎.
| export const metadata = createMetadata({ | ||
| title: "Security", | ||
| description: "PageSpace security overview: opaque session tokens, direct-permission RBAC, account lockout, OAuth PKCE, encrypted secrets, rate limiting, continuously verified audit logs, SSRF and path-traversal hardening.", | ||
| path: "/docs/security", |
There was a problem hiding this comment.
Redirect the remaining security CTAs before deleting routes
In a standalone or local marketing deployment without the production edge wildcard redirect, deleting this route leaves the security page's CTAs in SecurityPageSections.tsx lines 41, 47, and 396 pointing at /docs/security and /docs/security/zero-trust, so those prominent links now return the marketing app's 404 instead of honoring the newly configurable docs host. The repo-wide /docs search also shows these are the remaining source links; convert them to docsUrl(...) before removing the local routes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — this was a real miss, fixed in 3b0bc4a.
All three links are now docsUrl(...): SecurityPageSections.tsx:41 and :396 ("Security Documentation" / "Security Docs") and :47 ("Zero-Trust Architecture"). Your framing of the impact is right: in production they would have taken the edge 301, but in a standalone or local marketing build with no edge they were a plain 404 — and two of them are the primary CTAs on that page.
The root cause is worth naming: my original sweep read a truncated grep, so these three never entered the changeset. Fixing only the links would leave the same failure mode open for the next route that moves.
So I also added scripts/__tests__/marketing-no-local-docs-blog-links.test.ts, which walks apps/marketing/src and fails on any bare href="/docs...", href="/blog...", or markdown ](/docs...), reporting file:line. CI already runs that suite (cd scripts && bunx vitest run, ci.yml:135). It carries two tests proving it is not vacuous — that it detects a bare link, and that it does not flag the absolute URLs the helpers emit — and I mutation-checked it by restoring one of these hrefs, which turns it red pointing at the exact line.
Re-swept afterwards: zero bare /docs or /blog links remain anywhere in apps/marketing/src. Verified with typecheck, lint, knip:check, and a full marketing build.
…e next miss
Codex caught three `/docs` links I missed on the security page —
`SecurityPageSections.tsx:41,47,396`, two of them prominent CTAs ("Security
Documentation", "Zero-Trust Architecture"). With the docs routes deleted
these resolve against pagespace.ai: in production they take the edge 301,
but in a standalone or local marketing build they are a plain 404. Now they
go through `docsUrl()` like every other outbound docs link.
The miss happened because the original sweep read a truncated grep. So
rather than just fix the three links, this adds
`scripts/__tests__/marketing-no-local-docs-blog-links.test.ts`, which walks
`apps/marketing/src` and fails on any bare `href="/docs..."`, `href="/blog..."`,
or markdown `](/docs...)`, reporting file:line. CI already runs this suite
(`cd scripts && bunx vitest run`, ci.yml:135).
The guard carries two tests proving it is not vacuous — that it detects a
bare link, and that it does not flag the absolute URLs the helpers emit.
Mutation-checked: restoring one `/docs/security/zero-trust` href turns it
red with the exact file and line.
Verified: typecheck, lint, knip:check, marketing build, scripts suite.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwC25dWRtdaV6h3mjqqsog
|
| PR | Adds | Last updated | Effect once this merges |
|---|---|---|---|
| #1295 — Blog: Tabs That Work Like Your Browser | data.ts entry browser-style-tabs (+60) and a PNG |
2026-05-13 | Becomes unmergeable — modify/delete conflict on a deleted file. The post is lost unless migrated. |
| #1296 — Blog: Invite Collaborators Anywhere | a PNG only, no data.ts entry |
2026-05-08 | Already inert — it adds an unreferenced image, and after this PR the directory is gone too. |
What I verified
origin/master'sdata.tsholds exactly 7 slugs, and all 7 are live in the blog drive. The migration captured the complete current blog — nothing published is at risk.- Blog: Tabs That Work Like Your Browser (Because They Should) #1295's
browser-style-tabsis the only piece of real content in either PR that this deletion would strand. - Blog: Invite Collaborators Anywhere #1296 contains no post body at all, so there is nothing to migrate from it.
The decision
browser-style-tabs either gets migrated into the blog drive or it gets dropped. That is a content call, not a technical one — the mechanics are cheap either way (create the page from the PR's markdown, publish at /browser-style-tabs, close #1295).
No action taken on either PR. Raising it so the ordering is deliberate rather than discovered as a merge conflict.
…rketing-docs-blog
Link targets verified end-to-endThe guard test proves no bare So I extracted every
All 11 resolve. Tested against Also re-ran the guard after merging master (95 files) to confirm none of those commits reintroduced a bare link. Clean. |
CI-equivalent gates run locally, including the DB-backed onesThis PR's base is a feature branch, so no workflow triggers and it shows no checks — which is absent, not passing. I said so earlier and then closed the gap rather than leaving it: stood up a local Postgres 17 on 5433 with its own isolated database, and ran everything CI runs.
The one failing test is master's, not this PR's
So it is a pre-existing local-environment discrepancy on master, not a regression here. Separately, the earlier CI failure on the parent branch was a different thing — a genuine flake under concurrent load, confirmed by the same tests failing on the unrelated Still trueGitHub will retarget this PR to |
Stacked on #2426. Edge counterpart: PageSpace-Deploy#26.
Do not merge before PageSpace-Deploy#26 is deployed. Until the edge stops routing
/docsand/bloghere, merging this takes both sections down.What goes
page.tsxfiles (~3,000 lines of markdown embedded in TSX)data.tspublic/blogThe content now lives in two PageSpace drives published at
docs.pagespace.ai/blog.pagespace.ai, migrated byscripts/migrate-docs-blog-to-drives.tsfrom #2426.Links
Outbound links go through a new
lib/sites.ts(docsUrl()/blogUrl()) rather than bare paths. They're cross-origin now — a bare/docs/...would resolve againstpagespace.aiand take the edge 301 instead of going straight to the destination. Hosts are overridable viaNEXT_PUBLIC_DOCS_URL/NEXT_PUBLIC_BLOG_URL, defaulting to production.Cascading removals
Each because its only consumer was deleted — the last two surfaced by
knip:check, not by guesswork:DocsContent/DocsSidebar, and with themreact-markdown+remark-gfmschema.tsx's Article schema (the published blog emits its own structured data)pageMetadata.blog/.docsui/scroll-area.tsx+@radix-ui/react-scroll-area,hooks/use-mobile.tsTwo judgement calls
search-data.tskeeps its hand-maintained docs entries, repointed at the new host, but stops indexing blog post bodies. That index was built fromdata.tsat build time and there is no longer a build-time source for it. The palette still links out to the blog itself. (SearchDialogusesrouter.push, which hard-navigates on an absolute URL.)sitemap.tsno longer lists either section. Both published drives emit their ownsitemap.xmlwith canonical URLs on their own host; re-listing them underpagespace.aiwould advertise URLs that only 301.Verification
bun run typecheck,bun run lint,bun run knip:check, and a fullmarketing buildall pass with neither route present.🤖 Generated with Claude Code
https://claude.ai/code/session_01DwC25dWRtdaV6h3mjqqsog
Review round 1 (3b0bc4a)
Codex caught three
/docslinks this PR left dangling —SecurityPageSections.tsx:41,47,396, two of them the security page's primary CTAs. With the docs routes deleted they resolve against pagespace.ai: in production they take the edge 301, but in a standalone or local marketing build they are a plain 404. All three go throughdocsUrl()now.The miss happened because the original sweep read a truncated grep, so fixing only the links would leave the same failure mode open for the next route that moves. Added
scripts/__tests__/marketing-no-local-docs-blog-links.test.ts, which walksapps/marketing/srcand fails on any barehref="/docs...",href="/blog...", or markdown](/docs...), reporting file:line. CI already runs that suite (cd scripts && bunx vitest run, ci.yml:135). It includes two tests proving it is not vacuous, and is mutation-checked.Re-swept: zero bare
/docsor/bloglinks remain inapps/marketing/src.Two open blog PRs write to the paths this PR deletes — see the detailed comment. Short version: #1295 adds a post (
browser-style-tabs) that is lost unless migrated to the blog drive; #1296 adds only an orphan image and is already inert. All 7 slugs currently on master are live in the drive, so nothing published is at risk.