Stu Mason
Stu Mason

Activity

Pull Request Opened

PR #107 opened: 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, wraps render() in Cache::remember() with 6h TTL
  • app/Reports/Panels/ — typed panel classes:
    • StatGrid — headline number tiles
    • LineChart — time-series, pivots long → wide for recharts, multi-series
    • Leaderboard — SQL-backed sortable table with column formatters
    • Narrative — prose with **bold** / `code` inline, safely rendered (no innerHTML)
  • app/Reports/Registry.php — central list of all reports
  • ReportControllerindex + show, named routes
  • php 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

  1. Anthropic Ate OpenAI's Lunch (/reports/anthropic-vs-openai) — 5-month mindshare data, monthly line chart, top cross-platform stories
  2. 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 build passes
  • vendor/bin/pint --dirty passes
  • Local /reports index 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-openai and /reports/claude-code-wars render on prod
  • Verify cache works — second hit should be sub-100ms
+1079
additions
-4
deletions
23
files changed