Files
ResumeSite/docs/spec/DATA_MODEL.md
T
2026-07-03 21:07:25 +02:00

4.4 KiB
Raw Blame History

DATA_MODEL.md

Content model for the bilingual content collections. All schemas zod-validated at build; a schema violation fails CI. (Conceptual field lists — not code.)


1. Collections overview

content/
├── profile/        singleton per locale (hero, chips, about)
├── projects/       3 entries × 2 locales (jobtrack, inboxintel, homelab)
├── experience/     5 entries × 2 locales (council, side roles, education, 2023-now)
├── skills/         3 group entries × 2 locales
└── meta/           colophon page, 404 copy, contact page copy × 2 locales

Locale-invariant fields live on the EN entry and merge into NO at load (I18N_SPEC §3). Below, fields marked [inv] are invariant; everything else is per-locale prose.

2. profile (singleton)

  • name [inv], roleLine, heroTagline (the one-sentence claim), heroSummary (≤ 2 lines)
  • chips[]: { id [inv], label } — location, permit, availability, languages
  • statusLine (trace-dot tooltip: "open to work" / "åpen for muligheter")
  • aboutParagraphs[] (3), interestsLine
  • photo [inv]: asset ref + per-locale alt, caption
  • links [inv]: email, linkedinRedirect (/Linkedin), gitea, phone
  • cv [inv]: { en: {path, sizeKb, updated}, no: {...} }

3. projects

  • id/slug [inv, per-locale slug via slug map], name [inv], order [inv]
  • status [inv]: active | in-development | archived (drives chip semantics per COLOUR_SYSTEM §3.4)
  • valueProp (one-liner), cardTeaser (2 lines for homepage card)
  • stack[] [inv]: { name, contextLine? per-locale } (chip + tooltip)
  • links[] [inv]: { type: repo|live|docs, url, public: bool } (repo links only if/when repos are public — publish decision is content, not code)
  • tldr: { what, why, stack, role } (4 strings)
  • sections[]: ordered { anchorId per-locale, heading, body (markdown) } — canonical section kinds: problem, architecture, decisions, security, screenshots, next
  • decisions[]: structured { n, choice, alternative, rationale } (rendered as the numbered trade-off blocks)
  • diagram [inv]: SVG asset ref + per-locale title, desc (a11y), nodes[] label overrides per locale
  • media[] [inv refs]: { image, width, height, per-locale alt + caption, order } — dimensions mandatory (CLS 0)
  • template [inv]: case-study | capability (homelab uses the lighter template)
  • summaryOnly? (NO-side flag per I18N_SPEC §4.2)

4. experience

  • id [inv], employer [inv], location [inv], period [inv]: { from, to|null }
  • role, summary, highlights[] (featured only)
  • emphasis [inv]: featured | compact
  • progression? [inv]: for the council entry — [{from: 2015, to: 2017, label-per-locale: "Apprentice"}, {from: 2017, to: 2023, label: "System Developer"}]
  • anchor? — the confirmed concrete bullet (streetlight/highways system) is content, phrased per CANONICAL_CONTENT
  • Entries: warwickshire (featured), royal-vapes, hodcarrier, nuffield (compact, alongside: true [inv] flag renders the "alongside" grouping), education, norway-now (2023, norskkurs + products)

5. skills

  • id [inv], order [inv], title, contextLine, skills[]: { name [inv], tooltip? }
  • Groups: development, devops-infrastructure, practices

6. Page-meta (every routable page)

  • title, description (≤155 chars), ogImage [generated per locale], pageId [inv → slug map join]
  • Case studies additionally emit structured-data fields (SEO_SPEC §3)

7. Asset conventions

  • Screenshots: assets/projects/<id>/<capture>.png source of truth at 2×, seeded demo data only (Phase 3 prerequisite); pipeline emits AVIF/WebP/fallback + srcset.
  • Diagrams: hand-authored SVGs following the design-system diagram style; text within diagrams uses per-locale label injection at build (single SVG source, two rendered outputs) — avoids maintaining twin diagrams.
  • Fonts/CVs/favicons in public/ (unprocessed, stable URLs).

8. Validation rules (CI)

  1. Locale parity (I18N_SPEC §4.1).
  2. Every media[] entry has dimensions + both alts.
  3. Every project has ≥3 decisions[] and a security section (the site's promise to P2 is structural).
  4. status transitions logged in git only — no "archived" entry may appear on the homepage cards (query rule).
  5. Description lengths, title lengths enforced (SEO).
  6. All external links[].url respond 200 in a scheduled link-check workflow (not per-commit).