Repository navigation
Releases
Releases · solutionforest/laravel-recommender
v0.11.2
[0.11.2] — 2026-11-14
Screenshots and docs for the latest changes. No package changes.
Docs
- New screenshots of the dashboard (healthy, failing checks with the new index and slow-source warnings, explain, dark mode) and of
recommender:doctor,recommender:bootstrap(now with the speed probe) and the newrecommender:doctor --probe - README, dashboard guide and operations describe the speed checks, the index check and
--probe
v0.11.1
[0.11.1] — 2026-11-14
Catch slow queries before they run, not only while they run.
Added
- Index check in
doctorand the dashboard: each interaction table needs an index on its timestamp column and one starting with its user column; a missing one is a warning with the$table->index(...)to add (Laravel 10.35+) - Speed probe:
recommender:doctor {feed} --probe(also run byrecommender:bootstrap) runs each part once on real data — job reads, a personal and a guest list with every source / booster, the catalog tail, therecommendablescope / filter and the cards — times each, flags anything overslow_ms/slow_query_msand names the slowest SQL. Read-only; works before the first scores exist
v0.11.0
[0.11.0] — 2026-11-14
Find slow queries in your own code.
Added
- Speed checks in
doctorand the dashboard. The package now times every call into app code while serving (sources, boosters, therecommendablescope orfilter, cards, groups, catalog tail) and every SQL query whileupdate-scores/build-neighboursrun, and records how long each job run took. Anything slower thanslow_ms(200 ms),slow_query_ms(1000 ms),slow_scores_seconds(300) orslow_neighbours_seconds(1800) shows up as a warning with the part's name (e.g.recommendable scope (Post)or the SQL) and what usually fixes it, and is logged at most once an hour. Only slow events are stored (cache, 7 days, max 20 per feed); the timers add no measurable cost (stress numbers unchanged). See operations → slow queries
v0.10.10
[0.10.10] — 2026-11-14
Support dates and CI actions. No package changes.
Docs
- Laravel 12 support ends with the first release after 31 March 2027, together with Laravel 10 and 11 (Laravel's own security fixes for 12 end on 24 February 2027). From then on the package supports Laravel 13 and newer
Changed
- CI:
actions/checkout@v7,softprops/action-gh-release@v3(Dependabot)
v0.10.9
[0.10.9] — 2026-11-14
Support dates. No package changes.
Docs
- README supported-versions table: new Laravel security fixes until and Supported here until columns. Laravel 11 support ends with the first release after 31 March 2027, like Laravel 10 (both no longer get Laravel security fixes)
v0.10.8
[0.10.8] — 2026-11-14
Security checks in CI. No behaviour changes.
Added
- Security workflow (every PR,
main, weekly):composer auditof the runtime dependencies for Laravel 10–13 (Laravel 10 and 11 report-only: both are end of life and have advisories that will not be fixed, e.g. CVE-2026-48019), and Psalm taint analysis ofsrc/that fails on anyTainted*finding. See SECURITY.md - Dependabot updates for the CI actions; on the repository: Dependabot alerts and security updates, secret scanning with push protection
Changed
- Feed names are validated in one place (
FeedDefinition::validName()), which the taint analysis recognises. Its first run flagged the dashboard's?feed=reaching a query: not exploitable (the value must name a configured feed, names are limited to[A-Za-z0-9_-.], and it is a bound parameter), now provably so - CI:
actions/checkout@v5(v4 ran on a deprecated Node version) - README supported-versions table: Laravel 11 no longer gets security fixes from Laravel (since March 2026); Laravel 12 needs 12.60+ for Laravel's own fixes
v0.10.7
[0.10.7] — 2026-11-14
PHPStan level 10 (max). No feature changes.
Changed
- Static analysis at PHPStan level 10 for
src/and the examples (was 8): every value read from config, the cache or a database row is checked or converted to its type before use, through the newSupport\Valuehelper (int,float,string,id,map; same results as a PHP cast for the values these sources hold). No ignores, no baseline - A feed's
filter,cards,groupsorinteractionsclass that does not implement its contract now fails with a clearInvalidArgumentExceptionnaming the feed and key (before: aTypeError) - Cache entries that are not what the package wrote (e.g. edited by hand) are ignored instead of failing: non-id entries in cached lists are dropped, and a list entry whose
idsis not an array is treated as missing FeedDefinition::list()returns only non-empty strings (list<string>)
Stress numbers are unchanged within run-to-run noise (update-scores ~91k events/s; similar() cold 3 queries / warm 0).
v0.10.6
[0.10.6] — 2026-11-14
Supported versions in one table; no package code changes.
Docs
- README: Supported versions table (Laravel 10–13 × PHP 8.3–8.5), showing what CI tests and the Laravel 10 end date
- Release steps:
mainis protected (all CI checks must pass before merge, no direct pushes); releases go through a pull request, then the merge commit is tagged
Changed
- CI: the full suite also runs on PHP 8.5 with Laravel 11 and 12
v0.10.5
[0.10.5] — 2026-11-14
Correct scores outside UTC, and safer impressions. If your app timezone is not UTC, run recommender:rebuild-scores after upgrading (see UPGRADE).
Fixed
- Scores in apps whose timezone is not UTC (Laravel 11–13).
update-scoresread its stored watermark back in UTC (Carbon 3) while interaction tables hold app-local times. East of UTC (e.g.Asia/Hong_Kong) each run re-read the last hours and counted events again; west of UTC (e.g.America/New_York) new events could be skipped. The watermark is now read in the app timezone (also in the dashboard andrebuild-scores). Laravel 10 (Carbon 2) was not affected. Present since 0.0.1 - Redis cache store: the cached neighbour version came back as a string, so it was never reused and every
similar()call ran an extra query. Found by the new Redis CI job
Security
- Guest pages no longer count impressions by default (only with
'impressions' => true). Guests have no seen-set, so every reload counted again and anonymous traffic could push an item's quality down, whichrebuild-scorescannot undo. Opt back in with'impressions_guests' => true, behind a rate limit cards_vary_byvariants are capped per card (card_variants_max, default 20, oldest dropped), so unvalidated attribute values cannot grow one cache entry without limit
Changed
- CI: PHP 8.5 with Laravel 13; Laravel 10 on PHP 8.5 is an install + class-loading check, because Laravel 10's test tools (Testbench 8 / Pest 2) do not install on PHP 8.5; and a job that runs the whole suite on a real Redis cache store (
RECOMMENDER_TEST_CACHE=redis) - README: Laravel 10 support ends with the first release after 31 March 2027
v0.10.4
[0.10.4] — 2026-11-14
Docs checked against the code. No package code changes.
Docs
- Tuning: removed content from an app-specific feed (pet / shop classes that do not exist in the package, "lessons from a real inspiration feed", video posters). Recipes now use package classes plus clearly marked classes you write; new "Common pitfalls" table; recipes in A–D order
- Maths: neighbour cut-offs (
neighbours_min_co_count,neighbours_max,history_per_user), whatrank(i)means, booster term in the blend, the exact exploration interleave rule, relaxed diversity caps,Math::fromAgeisexp(−age / halfLife)(≈ 0.37 afterhalfLife, not a true half-life) - Reference:
origincan also be'tail'; queuedwarm()carries the attributes you pass (not the user model); impression writes described correctly (two bulk updates, more for new rows); ~270 pages/s matches the measured run - Operations: generic FAQ and SQL example (no app-specific wording); current version in the release example
- Performance: cold
similar()is 3 queries in the summary table too; page title - Tutorial / how it works / CONTRIBUTING / AGENTS / agent skill:
originvalues,FeedPagefields, storage classes, Laravel ^10–^13,locks: fallbackwording, app-specific lines removed - Config comments:
cache_storenull means Redis when reachable, elseCACHE_STORE; links point todocs/tuning.mdanddocs/operations.md
Changed
examples/blog:SponsoredShopSource/SponsoredShopBoosterrenamed toSponsoredAuthorSource/SponsoredAuthorBooster; they read onlysponsored_author_ids(thesponsored_shop_idsfallback is gone)