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.

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,
MergeCapabilityandSetPrimaryTagas 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/revalidateroute. Byte-stable canonical body (json_encode([...], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)). HMAC-SHA256 verified withcrypto.timingSafeEqual. Two-key list (CODEX_REVALIDATE_SECRETS=current,previous) for no-flap rotation. Bulk-tagging thirty projects is one HTTP round trip, not thirty. RedactedScopeas a model-layer boundary — stripsclient_name+internal_noteson every API response forvisibility=redactedrows. Filament admin opts out explicitly viawithoutGlobalScope. Signed-URL asset surface for redacted assets uses a separateCODEX_ASSET_SIGNING_KEYSfromAPP_KEYso asset rotation doesn't invalidate sessions; 14-day 410-Gone window aftervisibility_changed_atflips.- Loopback-fetch wrapper at
web/src/lib/codex-api.tsis the only allowed fetch path — injectsHost: api.codex.philiprehberger.comon 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: 1pinned because the/api/revalidaterate-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.shend-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


