Vercel Wrangling & the README Forge

A session chronicle of Vercel Wrangling & the README Forge.

──────────────────────────────────────────────────── -->

Act I · Backlog

The Sentry Inscription

FiremanDecko

Add a backlog item to integrate https://docs.sentry.io/

A single line was added to the ## Future section of product-brief.md — Sentry for error monitoring and performance tracing, with the docs URL preserved for the engineer who picks it up.

No sprint assignment, no urgency. Just the wolf marking the trail.

◈ product-brief.md
ᛞ ᚦ ᛟ

Act II · Debug

The Root Path Mystery

FiremanDecko

There's a 404 error locally

fetch("http://192.168.1.179:9653/", { "method": "GET" });

Playwright navigated to the local dev server. The root / returned a 404 — but oddly, the AppShell was still rendering around it. A prior session had added basePath: '/app' to next.config.ts, and a public/index.html placeholder was supposed to redirect to /app.

The bug: with basePath set, Next.js serves public/ files under the basePath prefix in dev mode. So public/index.html was landing at /app/index.html — not at /. The placeholder was silently useless.

The fix: Next.js middleware runs entirely outside the basePath context. A middleware redirecting //app when NODE_ENV !== 'production' solves it cleanly. In production, the middleware is a no-op — Vercel's CDN serves the marketing site at / directly.

🐺 Root Cause Found

Next.js basePath prefix applies to public/ files in dev mode. public/index.html was served at /app/index.html, not /. Middleware is the correct intercept point — it runs before basePath routing.

// development/frontend/src/middleware.ts
export function middleware(request: NextRequest) {
if (
process.env.NODE_ENV !== "production" &&
request.nextUrl.pathname === "/"
) {
return NextResponse.redirect(new URL("/app", request.url));
}
}
export const config = { matcher: ["/"] };
✦ development/frontend/src/middleware.ts ◈ product-brief.md
ᛞ ᚦ ᛟ

Act III · Revert

The Chain Unforged

FiremanDecko

Revert back to this commit: 8f4b5db698fcb31ba927364b293800446257a4eb

Three commits were cut from the chain: the middleware fix, the placeholder, and the original basePath: '/app' deployment approach. The forge showed all three commits already on origin/main — so the revert required a force push.

The wolf confirmed before striking. The user said: yes go ahead. The commits were undone.

git reset --hard 8f4b5db698fcb31ba927364b293800446257a4eb
git push --force origin main
# + 56cdc65...8f4b5db main -> main (forced update)
ᛞ ᚦ ᛟ

Act IV · Deployment

Static Site Relocated to /static

FiremanDecko

Update the vercel deployment so that the static site is served from /static

With the revert complete, next.config.ts had no basePath — the Next.js app owned /. The new plan: copy static/ into development/frontend/public/static/ before build so Next.js serves it verbatim at /static/*. Clean, no restructuring needed.

The CI step was added to vercel.yml. The APP_URL in the marketing site already pointed to the full Vercel URL — no change needed there.

- name: Copy static site into Next.js public/static/
run: |
mkdir -p development/frontend/public/static
cp -r static/. development/frontend/public/static/
◈ .github/workflows/vercel.yml
ᛞ ᚦ ᛟ

Act V · Bug Fix

The Broken Images

FiremanDecko

Inspect https://fenrir-ledger.vercel.app/static — none of the images are working

Playwright navigated to the production URL. The network log showed /icon.png and /favicon.ico both returning 404. The HTML used relative paths — src="icon.png" — which browsers resolve relative to the document's base URL.

The culprit: the page was served at /static without a trailing slash. Without the slash, browsers treat /static as a file, not a directory, and resolve relative paths from / — so icon.png became /icon.png rather than /static/icon.png.

Fix: three asset references updated to explicit root-relative paths with the /static/ prefix.

🐺 Bug Fixed

Relative paths (icon.png, favicon.ico) resolve from / when page is served without trailing slash. Fixed: src="icon.png" → src="/static/icon.png" (×2) and href="favicon.ico" → href="/static/favicon.ico"

◈ static/index.html
ᛞ ᚦ ᛟ

Act VI · New Feature

Sessions Take Root on Vercel

FiremanDecko

Add a link to the session logs in the footer. Ensure the session logs are deployed to vercel too at /sessions

Two changes in one strike. The footer of static/index.html already had the .step-log-link CSS class defined — used it to slot in ᛏ Session Chronicles → between the rule and the copyright line.

The Vercel workflow was extended with a second cp — mirroring sessions/ into public/sessions/ before build, so the archive lands at /sessions/* on the same deployment.

mkdir -p development/frontend/public/sessions
cp -r sessions/. development/frontend/public/sessions/
◈ static/index.html ◈ .github/workflows/vercel.yml
ᛞ ᚦ ᛟ

Act VII · Identity

The Forge Badge

FiremanDecko

Add this status badge to the README

Deploy to Vercel

The Vercel deployment badge was placed at the top of README.md, directly below the title — a live signal visible to all who enter the repository. Green when the wolf holds the line. Red when the forge has cooled.

◈ README.md
ᛞ ᚦ ᛟ

Act VIII · Design

Three Links Carved

FiremanDecko

Update the README.md links to the vercel deployment ᛟ Enter the Ledger → | ᚱ Visit the Marketing Site →

Each link on one line. Add a link to the session log with it's rune

The old single-line pipe-separated link was replaced with three distinct heading links — one per line. The marketing site URL was updated from the old GitHub Pages address to /static on Vercel. A third link was added for ᛏ Session Chronicles pointing to /sessions.

◈ README.md
ᛞ ᚦ ᛟ

Act IX · Voice

The Wolf Speaks

FiremanDecko

Add some prose around the links in the voice of the wolf

Three lines of wolf-voice prose were woven between the links — unhurried, knowing, each one naming the purpose of the path it guards.

// Before the Ledger link:
*The wolf does not wait. Step into the forge and name your chains before they name you.*

// Before the Marketing Site link: Read the runes. Know what was built, why it was built, and what hunts next.

// Before the Session Chronicles link: Every session forged in fire, recorded in runes. The wolf remembers what the gods tried to bury.

◈ README.md
ᛞ ᚦ ᛟ

Act X · Layout

The Three-Card Hall

FiremanDecko

Make those links in a single row of 3 cards in the markdown. Three boxes on one row with links and prose and runes

Standard Markdown has no multi-column layout. The solution: an HTML <table> with three <td> cells, each centred and set to width="33%". GitHub's Markdown renderer honours HTML tables in full.

Each card holds the rune large at the top as a heading, a bold link, and the italic wolf prose beneath. The three gates now stand side by side in the README.

◈ README.md
ᛞ ᚦ ᛟ

Act XI · Quick Fix

Gates Opened Wide

FiremanDecko

Make those links open in a new tab

Standard Markdown link syntax — [text](url) — has no mechanism for target="_blank". Since the links were already inside an HTML table, converting them to raw <a> tags with target="_blank" rel="noopener" was the natural move. The gates now open onto new ground without pulling the wolf away from the scroll.

<a href="https://fenrir-ledger.vercel.app" target="_blank" rel="noopener">
Enter the Ledger →
</a>
◈ README.md