Vercel Deployment Runbook
Runbook for the live Vercel-hosted static wiki and its ongoing deploy, validation, and troubleshooting workflow.
Vercel Deployment Runbook
The engineering wiki is live as a static Next.js site (site/) on Vercel at https://madsenjake0.wiki. Every push to main triggers an automatic rebuild of the public docs surface.
Design Rationale
The wiki is deployed as a fully static export (output: "export" in site/next.config.js) rather than a server-rendered Next.js app. This choice eliminates the need for a serverless runtime on Vercel, reduces cold-start latency to zero, and means the deployment is just a directory of HTML files served from a CDN. Since wiki content only changes on pushes to main, there is no benefit to server-side rendering — the content is known at build time.
The alternative of serving wiki content through the FastAPI backend was considered and partially implemented (the server/wiki.py API), but it requires a running server and cannot serve the public audience without infrastructure beyond a static CDN. The two surfaces coexist: Vercel serves the public-facing read-only wiki, while the FastAPI API provides richer capabilities (health checks, commit history, source viewing, staleness detection) for local engineering workflows.
Using vercel.json with explicit installCommand, buildCommand, and outputDirectory instead of Vercel's framework auto-detection was a deliberate workaround for monorepo structure. Vercel's auto-detection looks for next in the root package.json, but Lorewright's root has no package.json — the Next.js app lives in site/. Explicit configuration avoids this mismatch entirely and makes the build contract visible in version control.
Assumptions & Constraints
- Build-time-only wiki reading.
site/lib/wiki.tsreadswiki/*.mdfiles at build time using Node.jsfs— there is no runtime data fetching. If the wiki directory is missing or empty at build time, the site builds with no pages and no error. This is a silent failure mode worth watching for. - Single-branch deployment model. The custom domain (
madsenjake0.wiki) only follows the production deployment, which tracksmain. PR preview deployments get Vercel-generated URLs but not the custom domain. This means you cannot preview wiki changes on the real domain before merging. - GitHub blob links are hardcoded to
main. TheGITHUB_BLOBconstant insite/lib/wiki.tsandsite/app/wiki/[slug]/page.tsxassumes the default branch ismain. If the repository's default branch were ever renamed, all@file:reference links would break silently (they'd 404 on GitHub, not at build time). - No incremental static regeneration. Because the export is fully static, every deploy rebuilds every page. For the current wiki size (~30 pages) this is fast (<30 seconds), but it means build time scales linearly with page count.
- Sanitization is the security boundary. The rendering pipeline uses
rehype-sanitizewith a customized schema that only allows specific CSS classes (wiki-link,broken-link,source-ref,hljs-*for syntax highlighting). Raw HTML in wiki markdown is processed throughrehype-rawbut then sanitized — this permits<a>tags from wiki-link resolution while blocking injection.
Conceptual Model
The deployment architecture draws a clear boundary between build-time content resolution and runtime serving:
Author time: wiki/*.md (frontmatter + markdown + double-bracket links + @file: refs)
↓
Build time: site/lib/wiki.ts resolves links, renders HTML
↓
site/out/ (static HTML, CSS, JS)
↓
Deploy time: Vercel CDN edge cache (global distribution)
↓
Runtime: Browser fetches pre-built HTML (no server logic)
All complexity lives at build time. The wiki.ts module is effectively a compiler: it reads a custom markup language (markdown with wiki-link and file-reference extensions), resolves references against the current page set, and emits HTML. Broken links are rendered with a broken-link CSS class rather than failing the build, which means the build always succeeds but may produce pages with visually flagged broken references.
The relationship between the two wiki surfaces (Vercel static site vs. FastAPI API) is read-only fork — they read the same wiki/*.md source but render independently. The Vercel surface is optimized for public browsing (pre-built HTML, CDN delivery, syntax highlighting). The FastAPI surface is optimized for engineering tooling (structured JSON responses, health checks, backlink graphs, staleness detection). Neither surface writes to wiki files; authoring happens through direct file edits and git commits.
Architecture
wiki/*.md → site/ (Next.js build) → site/out/ → Vercel CDN → madsenjake0.wiki
site/lib/wiki.tsreads allwiki/*.mdat build time, resolves double-bracket wiki links and`@file:`references, renders HTML viaunified(remark + rehype + rehype-highlight).site/next.config.jsusesoutput: "export"+trailingSlash: truefor pure static HTML with no serverless runtime.vercel.jsonat the repo root sets the install command, build command, and output directory explicitly and avoids both framework auto-detection and legacy builders.@file:references link tohttps://github.com/icosahedron10/lorewright/blob/main.
Public Surface vs API-Only Surface
The Vercel deployment is the public, static browsing surface only. It does not expose FastAPI-only wiki capabilities such as:
GET /api/wiki/healthGET /api/wiki/commitsGET /api/wiki/sourcewith historical file and line-range viewing- page
toc, backlink/source metadata, and staleness fields returned byGET /api/wiki/pages/{slug}
Those capabilities remain available from the FastAPI wiki API in server/wiki.py for local engineering workflows and automated checks.
Current Deployment State (as of 2026-04-15)
| Item | Status |
|---|---|
vercel.json configured | ✅ |
site/ Next.js app | ✅ |
trailingSlash: true | ✅ |
framework: "nextjs" removed from vercel.json | ✅ (was causing "No Next.js version detected" error) |
| highlight.js CSS imported | ✅ |
| Vercel project created + GitHub connected | ✅ |
Domain madsenjake0.wiki serving production traffic | ✅ |
Automatic deploys from main | ✅ |
Routine Validation Before Shipping Docs
Run the static-site build locally before pushing documentation changes:
npm --prefix site run build
pytest tests/test_wiki_api.py -q
Triggering a Redeploy
Redeployment is automatic on every push to main. To force a redeploy without a code change:
- Vercel dashboard → project → Deployments → pick latest → Redeploy
Domain or Project Reconfiguration
If the domain or Vercel project needs to move, keep the current production behavior:
- Import
icosahedron10/lorewrightin Vercel. - Leave the root directory at
/;vercel.jsonhandles install/build/output for the monorepo. - Reattach
madsenjake0.wikiin Settings → Domains. - If DNS must be recreated, use the Vercel-provided apex/domain records and wait for TLS reprovisioning.
Adding or Updating Wiki Pages
- Edit or create
wiki/{slug}.mdwith required frontmatter (see Decision: Wiki Maintenance Contract) - Update
<a href="/wiki/index" class="wiki-link">Lorewright Wiki</a>,<a href="/wiki/log" class="wiki-link">Wiki Log</a>, andsource_pathson any touched pages when the wiki contract requires it - Commit and push to
main - Vercel rebuilds automatically — the public page is usually live in under a minute
No server restart or manifest rebuild step is needed; the Next.js build reads wiki/ fresh every time.
Troubleshooting
Build fails with "No Next.js version detected"
vercel.json must NOT contain "framework": "nextjs". Vercel looks for next in the root package.json when this key is present; our root has no package.json. Remove the key.
404 on the deployment root (/) even when Vercel marks the deploy ready
Use explicit top-level installCommand, buildCommand, and outputDirectory in vercel.json. Avoid legacy builds-based configs for this monorepo static export — they can produce a "ready" deployment that does not serve the generated site/out files at the project root.
404 on direct page load (e.g. /wiki/architecture)
Ensure trailingSlash: true is set in site/next.config.js. Without it, Next.js emits flat .html files that Vercel cannot resolve from a bare path.
Preview works but the production domain still 404s
The custom domain only follows the production deployment, not the PR preview deployment. Merge the production fix or switch the Vercel project's Production Branch to the branch containing the fixed vercel.json, then trigger a redeploy.
Wiki content stale after push Check the Vercel deploy log. If the build passed but content looks old, hard-refresh the browser. Vercel CDN caches are invalidated on each deploy.
Broken wiki links (red strikethrough in UI)
Run the FastAPI-only GET /api/wiki/health route locally to get a health report listing broken links, orphan pages, and stale source references. Fix the offending markdown and push.
@file: links point to wrong branch
GITHUB_BLOB is hardcoded to main in both site/lib/wiki.ts:42 and site/app/wiki/[slug]/page.tsx:5. If the default branch changes, update both constants.