package.json and yarn.lock, and builds and deploys separately — there is no shared runtime, no shared node_modules, and no cross-app imports. You work inside whichever app directory you need and treat the other as a sibling project.
The Two Apps
Both apps use the Pages Router (
pages/), not the App Router. Each has its own _app.tsx and _document.tsx for custom wrappers, its own styles/ directory for CSS modules, and its own public/ directory for static assets such as favicons and OG images.
Directory Tree
The repository root holds the two app directories alongside a smallscripts/ folder and repo-level config files. Here is a condensed view of the key paths:
URL Routing and the /n Redirect
Neither app uses server-side rewrites. Both are configured with output: 'export' in next.config.js, which generates a fully static site that Vercel serves directly from the filesystem.
The root path (/) on each domain uses an HTML <meta http-equiv="refresh"> tag to immediately redirect the browser to /n, which is where the actual content lives. This approach works without any server logic:
- Visiting
war.re→ browser reads the meta-refresh → navigates towar.re/n - Visiting
ryan.war.re→ browser reads the meta-refresh → navigates toryan.war.re/n
<noscript> fallback link is included for browsers with JavaScript disabled so they still get a clickable link to /n.
Pages Directory Structure
Each app mirrors the samepages/ layout:
The
subdomains/ryan/ app also has a components/ directory at the app root, holding the resume-specific React components (Activity, ActivityList, Experience, ExperienceItem) that the /n page composes together.
Independent Builds
Run all commands from inside the relevant app directory — not from the repository root. Each app is self-contained:main/ app currently has no Jest unit tests (--passWithNoTests is set so the test script exits cleanly). The subdomains/ryan/ app has full Jest coverage for its components.