Skip to main content
Back to Portfolio

Codex — Portfolio Intelligence Dashboard

Portfolio-intelligence dashboard — capability × project heatmap, honest gap report, sister-table packages, and a resume-bullet generator, all driven by one curated dataset and dogfooded against the full personal portfolio.

Laravel 13PHP 8.3MySQL 8Filament 5Next.js 16React 19Tailwind 4TypeScriptPHPUnitVitestPHPStanHMAC-SHA256ApachePM2Let's Encrypt
Codex — Portfolio Intelligence Dashboard preview

Overview

A portfolio build for the buyer whose first question is "have you done X across Y" and whose unstructured-portfolio scan time runs to twenty minutes per candidate. Most freelance portfolios are a chronological list — Codex is the version that admits the shape is a queryable dataset, names every capability against a curated vocabulary, and publishes the gap report alongside the wins.

The headline move:

The capability vocabulary is curated, not free-form — 68 capabilities, hard cap of 80, paper-prototype scroll-test at the cap. Merges are one-way, terminal-canonical, required-reason, undoable via the audit log. No "freelancer tagging themselves as everything" — every claim is a row in project_capabilities, every aliased capability points at a single canonical target, every merge writes a reason. The gap report at /gaps lists capabilities used 0–2 times with a one-sentence note on what work would close each gap — gaps as part of the artefact, not a bug.

Dataset (dogfooded against the live personal portfolio):

  • 47 projects catalogued across demos, redacted client engagements, and personal sites
  • 623 packages across 11 languages on a sister table, joined to capabilities via name-pattern matching
  • 68 capabilities tagged against the curated vocabulary; cap 80
  • 20 industries; per-capability heatmap cells weighted by recency × depth

Surfaces:

  • /heatmap — capability × project matrix with colour-graded cells; mobile collapses to a stacked-row variant so the scan still works at 390px wide. Same dataset drives both renderings, axe-clean a11y.
  • /gaps — honest gap report sorted ascending by usage count, with one-sentence "what work would fill this" hints on every row.
  • /capabilities/[slug] — capability detail surfaces both projects and packages under the same capability, so an Authentication or Pagination page reads as the full body of work.
  • /packages — sister-table surface across 623 rows with language × registry × capability filtering.
  • /resume-bullets — capability-aggregated bullets rendered server-side from the same dataset that drives the heatmap; resume copy and dashboard copy can't drift.
  • Filament v5 admin behind password + first-party TOTP MFA — capability moderation, one-way terminal-canonical merges, MergeCapability and SetPrimaryTag as transactional actions, audit-log unmerge.

Reliability features:

  • HMAC-signed coalesced revalidation. Filament writes fire a request-scoped observer that buffers tags and POSTs once on terminating() to a Next.js /api/revalidate route. Byte-stable canonical body (json_encode([...], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)). HMAC-SHA256 verified with crypto.timingSafeEqual. Two-key list (CODEX_REVALIDATE_SECRETS=current,previous) for no-flap rotation. Bulk-tagging thirty projects is one HTTP round trip, not thirty.
  • RedactedScope as a model-layer boundary — strips client_name + internal_notes on every API response for visibility=redacted rows. Filament admin opts out explicitly via withoutGlobalScope. Signed-URL asset surface for redacted assets uses a separate CODEX_ASSET_SIGNING_KEYS from APP_KEY so asset rotation doesn't invalidate sessions; 14-day 410-Gone window after visibility_changed_at flips.
  • Loopback-fetch wrapper at web/src/lib/codex-api.ts is the only allowed fetch path — injects Host: api.codex.philiprehberger.com on every server-side call, ESLint-pinned. The Apache loopback-traffic carve-out (RewriteCond %{REMOTE_ADDR} !=127.0.0.1) keeps server-side fetches off the http→https redirect rule.
  • Cursor pagination + filter allow-list + RFC 7807 across the read API. PM2 instances: 1 pinned because the /api/revalidate rate-limit counter is in-memory per process.

Stack:

  • Laravel 13, PHP 8.3, MySQL 8, Filament v5, Apache + php-fpm, Let's Encrypt
  • Next.js 16, React 19, Tailwind 4, server-side rendering
  • PHPUnit + Vitest + Playwright; PHPStan level 8 + Pint; CI on push with MySQL service + paratest + path-filter
  • Weekly restore-drill cron + scripts/test-restore.sh end-to-end against a scratch DB

What it proves:

Same person curated the capability vocabulary, designed the schema, wrote the Laravel models + Filament resources + transactional actions, scaffolded the Next.js dashboard + the loopback fetch wrapper, wrote the HMAC-signed revalidate observer + client, deployed three processes to EC2 with atomic releases + Apache + php-fpm + PM2 + Let's Encrypt, and shipped it live. The case for hiring me to build a single coherent product surface where the dataset, the dashboard, the admin, and the resume bullets all stay in sync — not stitched together across a backend dev + frontend dev + DevOps + a content team.

Results

  • 47 projects + 623 packages + 68 capabilities catalogued — dogfooded against the full personal portfolio

  • 50 PHPUnit / 168 assertions + 10 Vitest passing; PHPStan level 8 + Pint clean; weekly restore-drill cron

  • Capability × project heatmap + honest gap report + sister-table packages + resume-bullet generator from one curated dataset

  • HMAC-signed coalesced revalidation — bulk-tag thirty projects = one HTTP round trip; two-key list for no-flap rotation

Gallery

Codex — Portfolio Intelligence Dashboard screenshot 2
Codex — Portfolio Intelligence Dashboard screenshot 3
Codex — Portfolio Intelligence Dashboard screenshot 4

Interested in working together?

Let's discuss how I can help with your project

Get in Touch