This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.
The Next.js 16 application serving the complete rectorspace.com ecosystem — the single source of truth for every platform section. Live in production on Vercel. Migrated from a Rails 8 monolith to Next.js 16 (App Router, SSG/ISR, no database) in June 2026.
Tech Stack: Next.js 16.2.6 (App Router) · React 19.2 · TypeScript · Tailwind CSS v4 (CSS-first @theme) · Vitest · self-hosted JetBrains Mono. No database — all content is file-based (markdown + YAML), committed to git.
- RSC by default; client islands need
"use client". - Dynamic route
paramsis an awaited Promise (const { slug } = await params). - Metadata merges layout → page (auto-derives
og:titlefromtitle). - Tailwind v4 is CSS-first (
@themeinsrc/app/globals.css), notailwind.config.js. process.cwd()at build/runtime is the repo root (file loaders readcontent/,data/,public/from there).
Single domain rectorspace.com with route-based sections:
| Section | Route | Purpose | Status |
|---|---|---|---|
| Homepage | / |
Identity hub & landing | ✅ Live |
| Work | /work, /work/:slug |
Story-driven project showcase | ✅ Live |
| Journal | /journal, /journal/:slug |
File-based markdown blog | ✅ Live |
| Apply | /apply/* |
Targeted CVs (noindex) | ✅ Live |
| Labs | /labs |
Experiments & learning | 📋 Planned |
| Cheatsheet | /cheatsheet |
Dev reference | 📋 Planned |
| Dakwa / Quran | /dakwa, /quran |
Da'wah & Quranic content | 📋 Planned |
New sections follow the same file-based content + PORO-style loader pattern (mirror src/lib/content/posts.ts over content/<section>/*.md); deploy = publish.
src/
app/ # App Router routes
layout.tsx # root metadata (metadataBase=SITE_URL) + fonts + VersionFooter
page.tsx # Homepage (RSC + ISR, revalidate 3600)
globals.css # Tailwind v4 @theme tokens + all component CSS
og-image.png/route.ts # OG image Route Handler (Satori) → /og-image.png
sitemap.ts · robots.ts # indexable routes (excludes /apply)
work/ · journal/ · apply/
lib/
site.ts # SITE_URL = https://rectorspace.com (single source)
seo.ts # pageMetadata() — shared title/canonical/og/twitter
og/render.tsx # Satori OG composition
content/ # file loaders: posts, works, achievements, resume, arbital, superteam
github/ # repos, contributions, tech-stack (needs GITHUB_TOKEN)
version.ts · format.ts · repo-time.ts
components/{home,islands,VersionFooter,Markdown}/
content/{work,journal}/*.md # YAML front matter + markdown body
data/{achievements,resume}.yml
public/{fonts,images,*.svg} # self-hosted WOFF2 fonts, profile/OG assets
scripts/{gen-version,generate-resume-pdf}.mjs
next.config.ts # experimental.inlineCss (cuts render-blocking CSS)
docs/DESIGN_SYSTEM.md
- Content:
content/{work,journal}/*.md— YAML front matter + markdown, loaded bysrc/lib/content/{works,posts}.ts(loadWorks()/loadPosts()→{ all, published, recent(), find() }). Drafts excluded from listings + 404 on show. To publish: add a file, commit, deploy. - Achievements:
data/achievements.yml→loadAchievements()(winCount,totalEarnings, etc.). Drives homepage, OG image,/applystats. - Resume / CVs:
data/resume.yml→src/lib/content/resume.ts+/apply/*pages.npm run resume:pdfrenders the PDF.
src/lib/seo.ts—pageMetadata({ title?, description, path, ogType? })is the single source for every indexable route's<title>(suffix• RECTOR • Building for Eternity),canonical,og:url,og:image,twittercard. Pass relative paths —metadataBaseabsolutizes them. Do NOT hand-roll metadata or re-hardcode the suffix.- OG image: served at
/og-image.pngby a Route Handler (force-static) renderingsrc/lib/og/render.tsx(Satori). Path is fixed for parity — already-shared social cards reference it; do not rename. sitemap.ts/robots.tsenumerate indexable routes (excluding noindex/apply/*).robots.tsintentionally has noDisallow: /apply(noindex meta + sitemap-exclusion is the right mechanism; disallowing would hide the noindex from crawlers).
Spec: docs/DESIGN_SYSTEM.md. Tokens in src/app/globals.css (@theme).
- Palette: Soft Cream
#FFF7E1(bg), Deep Brown#3B2C22(text), Sky#41CFFF, Warm Yellow#F9C846, Clay#E58C2E, Leaf Green#A8E063, Muted Red#C75A44. Light/warm theme only (/applyarbital pages have their own dark themes inapply.css). - WCAG AA text tokens (surface-scoped — important): readable text on cream/light surfaces uses darkened tokens —
--color-link #0D7390(5.07:1),--color-green-deep #3C6A12,--color-clay-deep #8A4A12, muted text atbrown/70+. The bright sky/green/clay tokens are for decorative fills (backgrounds, borders, contribution cells, rings), the dark/applythemes, and the OG image. When adding readable text, use the-deep/linktokens to keep accessibility at 100; never darken the shared bright tokens (breaks fills + dark themes). - Type: JetBrains Mono, self-hosted WOFF2 (
display:swap, monospace fallback). Deliberately NOTnext/font/google(de-Googling). OG renderer reads the.ttffiles (Satori can't parse WOFF2) — keep both.
src/lib/github/{repos,contributions,tech-stack}.ts fetch live repo/contribution data for the homepage (ISR, hourly revalidate). Requires GITHUB_TOKEN env var (read-only public_repo); without it degrades gracefully to empty ("No projects found"). Production Vercel project must have a valid GITHUB_TOKEN.
npm install
npm run dev # dev server (Turbopack)
npm run build # production build (set GITHUB_TOKEN for repo data)
npm run start # serve the production build
npm run test # vitest (run once)
npm run test:watch
npx tsc --noEmit # typecheck
npm run lint # eslint
npm run resume:pdf # render the resume PDF- Hosted on Vercel (project under
rectors-projectsteam). Production deploys frommain; PRs get preview deployments. - ISR: homepage +
/workindexrevalidate = 3600(hourly). Work/journal slug pages are SSG viagenerateStaticParams. - Env:
GITHUB_TOKEN(required for repo cards).VERCEL_ENVgates the version footer (production-only). next.config.tsenablesexperimental.inlineCss(inlines route CSS to cut render-blocking; re-verify after any Next upgrade).
- Branches:
main(deploys to Vercel production) ← PRs from typed feature branches (feat/,fix/,docs/,chore/,refactor/). - Commit format:
<type>: <description>. One focused change per commit.
"Building for Eternity" — integrating dunya (technical excellence) with akhirah (the planned da'wah sections). Values: Ihsan (100%-working standard, edge cases + a11y + perf), Amanah (code as trust, documented thoroughly), avoid Israf (lean, minimal dependencies).