Skip to content

javaabu/stats v2.0 (next-gen) - #4

Open
n4ff4h wants to merge 11 commits into
Javaabu:mainfrom
n4ff4h:next-gen
Open

n4ff4h wants to merge 11 commits into
Javaabu:mainfrom
n4ff4h:next-gen

Conversation

@n4ff4h

@n4ff4h n4ff4h commented Nov 10, 2026

Copy link
Copy Markdown

javaabu/stats v2

The next-gen major of stats, built on the fork n4ff4h/stats (next-gen); tracking epic n4ff4h#13. Stat definitions from v1 keep working; the front end, dependencies, routes and database support are new.

What's in it

  • Foundations. PHP 8.4+, Laravel 12/13, javaabu/forms v2. No more javaabu/helpers, javaabu/settings or maatwebsite/excel (CI fails if helpers or settings ^1 come back). Branch alias dev-next-gen: 2.x-dev.
  • Any database. Date grouping for MySQL, MariaDB, PostgreSQL and SQLite; CI runs the suite on all four.
  • Immutable dates. Works in apps that call Date::use(CarbonImmutable::class), as Laravel's starter kits do: dates are CarbonInterface, made with the Date factory. CI runs the whole suite with CarbonImmutable too (Stats fail when the app uses CarbonImmutable (Laravel 13 starter kit default) n4ff4h/stats#14).
  • Charts. TimeSeriesChart, CategoryChart, PieChart, Sparkline and StatTile describe a chart in PHP:
    • React draws them with Onu's charts (<StatsChart>, @javaabu/stats through javaabu/manifest). Their npm packages are declared for manifest's pages scope, so manifest:check doesn't ask Blade apps for React packages;
    • Blade draws them as accessible SVG with the same tokens (<x-stats::chart> and friends), mirrored in RTL.
    • Several stats or periods on one plot, and comparisons with the previous period.
  • Cached dashboards. Versioned cache keys, TTLs for current and past periods, Stats::forget()/flush(), the InvalidatesStats model trait, Stats::warm() with stats:warm and the WarmStatsCache job.
  • Pages. Route::stats() gives time series and categorical pages in Blade or Inertia React:
    • stencil forms, javaabu/filters filters via StatsFilter::from(), and CSV export;
    • for any guard, with overridable controllers.
  • API. Route::statsApi() keeps the v1 JSON API.
  • Authorization. view_stats through javaabu/permissions and an overridable StatsPolicy.
  • Dhivehi and RTL, with docs for people and agents, llms.txt, a Laravel Boost guideline and the javaabu-stats skill.

Upgrade notes

See docs/upgrading.md. The main breaks:

  • The material-admin views and the <x-stats::time-series> / <x-stats::categorical> components are removed. Use the pages, charts, or a page per model (extend the controller's filters()).
  • Week keys are now the start date of the week, and month keys are YYYY-MM. Hourly keys now match the SQL.
  • A plain date_to covers the whole day.
  • Date methods type-hint CarbonInterface instead of Carbon; overrides of setDateFrom(), setDateTo(), getMaxDate() and getMinDate() must widen their parameters.
  • Exports are CSV without Laravel Excel.
  • The route helpers are deprecated in favour of Route::stats() / Route::statsApi().

Before releasing

  • Codecov for the Javaabu repo.
  • Register with docs.javaabu.com (Register with Javaabu Docs (docs.javaabu.com) n4ff4h/stats#12).
  • A Dhivehi speaker should review docs/advanced-usage/dhivehi-and-rtl.md#translations-to-review.
  • Once the next-gen packages are released, drop the VCS repositories from composer.json, and move @javaabu/forms to npm.

🤖 Generated with Claude Code

n4ff4h and others added 11 commits November 5, 2026 20:08
…ts, cache, stencil forms

- PHP ^8.4, Laravel 12/13, Testbench 10/11. Drops javaabu/helpers, javaabu/settings
  and maatwebsite/excel; javaabu/forms ^2. Branch alias dev-next-gen: 2.x-dev.
- Date grouping for MySQL, MariaDB, PostgreSQL and SQLite. Weeks are keyed by the
  date they start on; months by YYYY-MM; hourly keys now match the SQL.
- CSV exports without a dependency; a plain date_to covers the whole day.
- Route::stats() / Route::statsApi(), configurable controllers, a StatsPolicy and
  view_stats through javaabu/permissions, any guard.
- Chart builders (TimeSeriesChart, CategoryChart, PieChart, Sparkline, StatTile)
  serialised for Onu and drawn as SVG in Blade; several stats or periods on a plot.
- StatsCache with versioned keys and TTLs, Stats::warm(), stats:warm and the
  WarmStatsCache job, the InvalidatesStats model trait.
- Stats forms defined with stencil; javaabu/filters filters via StatsFilter::from().
- Pint, CI matrix (PHP 8.4/8.5 x Laravel 12/13 x lowest/stable), MySQL, MariaDB and
  PostgreSQL jobs, a job without optional packages, the JS job, Codecov, badges.

Refs #1, #2, #3, #4, #5, #6, #7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y; fix the CI pnpm store

Refs #2, #3, #4, #5, #6

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ests

- @javaabu/stats (resources/js, through javaabu/manifest): StatsChart draws any
  chart from PHP with Onu's TimeSeriesChart, CategoryChart, PieChart, Sparkline
  or StatTile; StatsTile; the stats::TimeSeries/Index and stats::Categorical/Index
  pages with StencilForm and the CSV download. Typed props, Vitest tests on
  fixtures generated from PHP.
- Blade: <x-stats::chart>, time-series-chart, category-chart, pie-chart, sparkline,
  stat-tile and stat-tiles as accessible SVG figures with Onu's tokens, a summary,
  a View as table toggle, and mirroring in RTL locales.
- Chart step labels in the app's locale; Inertia pages get errors and a CSRF token.

Refs #2, #3, #4, #11

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… logical CSS

Refs #10

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… guide, Dhivehi review list, README and changelog

Refs #8, #9, #10

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and chart recomputation

- Exports read form filter values from the request body.
- Pages pass the current route's parameters to their export and category URLs,
  so a prefix like users/{user}/stats works.
- Filter values 0, '0' and false are applied; only missing values are skipped.
- Downloads check the policy's export ability (the stat's canView() by default).
- Category search paging links keep filter[metric].
- stats:time-series refuses unknown types.
- Charts compute again when an option changes after reading them; a tile's link,
  icon and texts aren't part of its cache key. React tiles show the period.

Refs #2, #5, #7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The date range contracts, HasDateRange, ExactDateRange, PresetDateRanges,
TimeSeriesModes, TimeSeriesSteps and the stats requests type-hinted the
mutable Carbon\Carbon but built dates with now(), so every stat threw a
TypeError in apps on Laravel's starter kits. They now type-hint
CarbonInterface (DateTimeInterface for setters) and make dates with the
Date factory, so they are whichever class the app uses. No code relied on
mutating a date in place.

STATS_IMMUTABLE_DATES=1 runs the suite with CarbonImmutable, and a new CI
job does so; ImmutableDatesTest always does. Upgrade guide, docs, Boost
skill, llms.txt and AGENTS.md cover the new hints.

Closes #14

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chart styles are the only registered asset and import nothing, so
@javaabu/forms, @javaabu/onu, recharts, react, react-dom and
@inertiajs/react are only needed by the Inertia pages and @javaabu/stats
imports. Declaring them with npm(..., for: 'pages') (Javaabu/manifest#17)
stops `manifest:check` asking Blade apps to install React packages.
Tested with manifest:check in a Blade app and an Inertia app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Composer read composer.json from every branch and tag of each VCS
repository through the GitHub API: about 350 calls per CI job, around
3,800 per run. A second run within the hour exhausted the workflow
token's limit, and Composer failed with "Could not authenticate against
github.com" (Javaabu/exports#2, Javaabu/translatable#4). "no-api": true
makes Composer clone these repositories instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every job downloaded each package's zipball from api.github.com, around
140 calls a job, which counts against the workflow token's hourly limit.
Each job now restores Composer's files cache, keyed by job, matrix entry
and composer.json/composer.lock, and falls back to the job's last cache
when those change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant