trends.stumason.dev
TypeScript
Pull Request Merged
PR #107 merged: feat(reports): point-in-time data snapshot system
Summary
Adds a /reports/{slug} system for publishing point-in-time analytical snapshots of the data. Two reports ship today; future reports are 1 PHP class + zero frontend changes.
Architecture
app/Reports/Report.php— abstract base, wrapsrender()inCache::remember()with 6h TTLapp/Reports/Panels/— typed panel classes:StatGrid— headline number tilesLineChart— time-series, pivots long → wide for recharts, multi-seriesLeaderboard— SQL-backed sortable table with column formattersNarrative— prose with**bold**/`code`inline, safely rendered (noinnerHTML)
app/Reports/Registry.php— central list of all reportsReportController—index+show, named routesphp artisan reports:refresh [slug?]— bust cache + re-materialize- Defensive try/catch in data panels — a broken query degrades to a single empty panel, not a 500
Reports shipped
- Anthropic Ate OpenAI's Lunch (
/reports/anthropic-vs-openai) — 5-month mindshare data, monthly line chart, top cross-platform stories - The AI Coding Tool Wars (
/reports/claude-code-wars) — 12-week mentions, Claude Code dominance
Adding a report
class MyReport extends Report
{
public function slug(): string { return 'my-slug'; }
public function title(): string { return 'Title'; }
public function panels(): array {
return [
new StatGrid(...),
new LineChart(title: ..., sql: '...', xKey: 'month', yKey: 'count', seriesKey: 'category'),
new Narrative(...),
];
}
}
Add to Registry::all(), done.
Test plan
-
npm run buildpasses -
vendor/bin/pint --dirtypasses - Local
/reportsindex renders with both report cards (screenshot in commit) - Local
/reports/{slug}requires prod DB (verified routes registered, controller resolves) - Post-merge: verify
/reports/anthropic-vs-openaiand/reports/claude-code-warsrender on prod - Verify cache works — second hit should be sub-100ms
+1079
additions
-4
deletions
23
files changed