Buffering...
Narrative Interface System is the evolution of my personal landing page codebase into a reusable, section-driven foundation. It keeps the proven landing experience intact today while treating every section (hero, timeline, skills, projects, learning, contact) as a composable building block.
This repo is where I harden the data contracts, layout shell, and Contentful mapping patterns that will power future narrative surfaces. The current deployment still serves the personal site, but each change aims to make the same system ready for additional pages without rewriting the core.
Narrative Interface System is a high-signal personal landing page that treats SEO, narrative, and content modeling as one system.
Built UI-first, CMS-second, with Contentful + Agent-assisted reviews to keep the landing page sharp.
Structure version: v0.1.0
See VERSION and CHANGELOG.md for history.
- Project Goals
- Status & Metrics
- Tech Stack
- Architecture & Folder Structure
- Data & Agent Flow
- Getting Started
- Development Scripts
- Phases (0β9)
- Next Steps β Landing Page To-Dos
- AgentOps Workflow
- Deployment (Netlify)
Core focus: a strong landing page
- Build a single-page personal landing that:
- Reads clearly for recruiters, hiring managers, collaborators.
- Shows SEO sense, content thinking, and frontend craft.
- Treat the page as an Interface & Narrative Toolkit:
- Clear positioning, key projects, and βNow / Learningβ sections that tell a coherent story.
SEO & Content
- Go beyond βSEO is configuredβ into SEO that actually sells you:
- Good headings, clear copy, structured data, and compelling social previews.
- Use Contentful to keep copy and sections flexible:
- One bucket (Bucket 1 β Personal Landing) for this repo.
- Other buckets (Blog/Notes, Projects index, etc.) live in other repos/docs.
Agents
- Use Agent Checkpoints to:
- Review structure, copy, SEO, and UX.
- Capture decisions in
agent/CHECKPOINT_LOG.mdfor traceability.
- Structure version:
v0.1.0 - Changelog:
CHANGELOG.md
Latest Lighthouse (Netlify plugin):
- Performance: 99
- Accessibility: 96
- Best Practices: 100
- SEO: 100
- PWA: 30 (PWA is explicitly not a goal for this project)
Phase status (Bucket 1 β Personal Landing):
- Phases 0β9: β complete
This repo is now βPhase 9 completeβ β a solid, tested, deployed landing page.
Everything under βNext Stepsβ is optional polish to keep sharpening the same page.
- Vite + React (SPA)
- TypeScript
- CSS with design tokens
tokens.cssβ colors, typography, spacing, radii.layout.cssβ layout, sections, header, responsive behavior.
- Contentful (e.g.
masterenvironment)- Content model for Bucket 1 lives in sibling repo:
gharo-content-models. - This app reads a single
pagePersonalLandingentry with:slug: "/",- ordered
sections[]referencing:sectionHero,sectionTimeline,sectionSkills,sectionProjects,sectionLearning,sectionContact.
- Content model for Bucket 1 lives in sibling repo:
- Static TS fallback
personalLandingPageobject matches the Contentful-backed TS types.- Used as a typed fallback when CMS fetch fails or for local development.
Seo.tsxβ manages<title>+<meta name="description">for SPA.PersonSchema.tsxβ JSON-LD Person schema for personal-brand queries.
- AgentOps loop
- Checkpoint prompts + payloads in
agent/checkpoints/. - Helper:
agent/scripts/buildCheckpointPayload.mjs.
- Checkpoint prompts + payloads in
- Used to review:
- Data modeling, mapping, SEO choices, UX, and layout.
- Netlify
- Build:
npm run build - Publish:
dist
- Build:
- Env vars
VITE_CONTENTFUL_SPACE_IDVITE_CONTENTFUL_ENVIRONMENTVITE_CONTENTFUL_DELIVERY_TOKENSECRETS_SCAN_OMIT_KEYS
- Lighthouse CI
@netlify/plugin-lighthousevianetlify.toml.
narrative-interface-system/
βββ VERSION
βββ README.md
βββ CHANGELOG.md
βββ package.json
βββ tsconfig.json
βββ .eslintrc.cjs
βββ .prettierrc
βββ .gitignore
βββ .env.example # template for Contentful env vars (no secrets)
βββ .nvmrc # Node version hint for CI/Netlify
βββ netlify.toml # Netlify build + Lighthouse plugin config
βββ agent/
β βββ CHECKPOINT_LOG.md # log of agent checkpoints + decisions
β βββ checkpoints/ # markdown payloads/prompts per phase
β βββ scripts/
β βββ buildCheckpointPayload.mjs
βββ src/
β βββ main.tsx # Vite entrypoint, mounts <App />
β βββ App.tsx # wraps the Page component
β βββ data/
β β βββ page-personal-landing.ts
β βββ services/
β β βββ contentfulClient.ts
β β βββ fetchPersonalLandingPage.ts
β βββ components/
β β βββ layout/
β β β βββ Page.tsx
β β βββ sections/
β β β βββ SectionRenderer.tsx
β β β βββ HeroSection.tsx
β β β βββ TimelineSection.tsx
β β β βββ SkillsSection.tsx
β β β βββ ProjectsSection.tsx
β β β βββ LearningSection.tsx
β β β βββ ContactSection.tsx
β β βββ Seo.tsx
β β βββ PersonSchema.tsx
β βββ styles/
β β βββ tokens.css
β β βββ layout.css
β βββ __tests__/ # or co-located *.test.ts files
βββ public/
# static assets (favicons, etc.) β optional
-
contentfulClient.ts:- Uses
VITE_CONTENTFUL_*env vars to create a CDA client.
- Uses
-
fetchPersonalLandingPage.ts:-
Fetches
pagePersonalLandingwithslug: "/". -
Uses
includedepth to pull in all linked sections/items. -
Maps into:
PersonalLandingPage- Section types (
HeroSection,TimelineSection,SkillsSection,ProjectsSection,LearningSection,ContactSection).
-
Uses:
- Section mapper registry (
contentTypeIdβ mapper). - Safe array helpers and defensive defaults.
- Unknown section types are logged and skipped instead of crashing.
- Section mapper registry (
-
-
Page.tsx:-
Loads CMS data on mount; falls back to
personalLandingPageon error. -
Renders:
- Skip link, sticky header, nav, and all sections via
SectionRenderer. <Seo />+<PersonSchema />for SEO and structured data.
- Skip link, sticky header, nav, and all sections via
-
-
SectionRenderer.tsx:- Switches on
section.sectionTypeand renders the appropriate section component.
- Switches on
-
Use
agent:buildor checkpoint.mdfiles to:- Bundle code + context for review.
- Ask about SEO, layout, types, mapping, or narrative.
-
Apply suggestions and log them in
agent/CHECKPOINT_LOG.md.
- Node 18+ or 20+
- npm
npm installcp .env.example .env.localThen fill:
VITE_CONTENTFUL_SPACE_ID=your_space_id
VITE_CONTENTFUL_ENVIRONMENT=master
VITE_CONTENTFUL_DELIVERY_TOKEN=your_delivery_tokennpm run devOpen http://localhost:5173.
npm run build
npm run previewOpen http://localhost:4173.
npm run devβ dev server.npm run buildβ production build.npm run previewβ preview built site.npm run lintβ ESLint.npm run formatβ Prettier.npm run test/test:watchβ tests (mappers, components).npm run agent:buildβ build an Agent checkpoint payload.
All complete for Bucket 1 β Personal Landing:
- Phase 0 β Setup β scaffold, tooling, Agent skeleton.
- Phase 1 β Static Data Shape β TS types + static
personalLandingPage. - Phase 2 β Layout β
Page.tsx,SectionRenderer, sections. - Phase 3 β Visual Design & Tokens β tokens + layout CSS.
- Phase 4 β UX & Accessibility β skip link, focus, headings, sticky nav.
- Phase 5 β Contentful Model β Bucket 1 model in
gharo-content-models. - Phase 6 β Seed Content β real data in Contentful.
- Phase 7 β Integration & Mapping β CMS β TS mapping, safe patterns.
- Phase 8 β Go Live + SEO / Lighthouse β Netlify deploy, plugin, SPA SEO basics.
- Phase 9 β Hardening & Beyond β JSON-LD Person, Vitest, CI workflow (lint + test + build).
From here on out, changes are incremental polish on this one landing page.
Phase 9 β Hardening & Beyond is complete for this repo. The landing page is live, tested, mapped to Contentful, and has solid SEO basics. Ongoing tasks now live in TASKS.md.
netlify login
netlify link # choose your Netlify site (e.g. narrative-interface-system)netlify env:set VITE_CONTENTFUL_SPACE_ID your_space_id
netlify env:set VITE_CONTENTFUL_ENVIRONMENT master
netlify env:set VITE_CONTENTFUL_DELIVERY_TOKEN your_delivery_token
# Ignore non-sensitive space ID in secrets scan
netlify env:set SECRETS_SCAN_OMIT_KEYS VITE_CONTENTFUL_SPACE_IDnpm run build
netlify deploy --prod
# Build command: npm run build
# Publish directory: dist