Search by

tilttek / leaderboards

phil

Leaderboards for gamification: members ranked on counts, totals, best gestures, days or reported values, over days, weeks, months, seasons or sliding windows, kept up to date from the activity journal, tie-breaks, snapshots, weekly leagues with promotion, titles, teams, stores in memory or Valkey, o

Package info

github.com/TiltTek/leaderboards

Homepage

pkg:composer/tilttek/leaderboards

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0-alpha 2026-11-12 14:27 UTC

This package is auto-updated.

Last update: 2026-11-12 23:53:43 UTC


README

Members ranked on what they do, by period, and nobody shown to the others without choosing it.

tilttek/leaderboards ranks members on a measure during a period: the games played this month, the points earned this week, the best score of a single game, the days of activity, a level or the longest streak. Four measures are kept from the members' activity, recorded by tilttek/activity — the gestures counted, their quantities added up, the best quantity of one gesture, the distinct days with a gesture —; two take a value the application reports from a balance it keeps elsewhere — the latest value, or the highest. A board ranks over a day, an ISO week, a month, a quarter, a year, named seasons, ever or a sliding window of its last days, each in the timezone it declares. Scores are kept up to date as activity is recorded, not counted again at each display; a cancellation takes its contribution back, and a changed board is replayed from the journal. Equal scores are ordered by up to two tie-breaks — the fewest attempts, the shortest time —, then go to the first who reached them, or share a rank. A board is ranked among friends or inside a group by a circle of members the application gives, and may rank members for each object — each game, each book. A snapshot freezes the first members at the end of a period, once, to show the final standing and reward them. A weekly board may have a league: its members are split into divisions of about thirty, in tiers, formed in their order of arrival or by their volume of the week before; each sees only their division, and at the end of the week the first go up a tier and the last go down. A board may give a title from a threshold, and rank teams with a share of luck the application enables. Nobody is ranked publicly without choosing it: a member who has not chosen to appear sees their own rank, and the others see a line without a name; a member may appear under their name or a pseudonym. Erasing a member removes their scores, their lines in the snapshots and their choice.

It is for an application that wants its members to compare what they do — a community site, a game site, a reading or writing platform —, and that must not expose a member who did not ask to be. tilttek/leaderboards-bundle integrates it with Symfony and keeps the boards in Doctrine DBAL, the scores in Valkey when it is enabled; an application without Symfony takes the library alone, with the stores in memory, the scores in Valkey through the client it has, or stores of its own.

It is a plain PHP library whose dependencies are tilttek/activity, the journal the boards read, phil/resource, the opaque reference of a member, and psr/clock. Members are references the application gives, member:44: the library never reads a name, an e-mail or an account, and the name a public line shows is the application's to give.

The design is small: a Board holds its Measure, its Schedule of Periods, its verbs and conditions, its Ranking of TieBreaks and Ties, and its options; LeaderboardProjection reads the journal and writes Contributions and Scores to a ScoreStore; Leaderboards reads a Standing as one viewer sees it — Rows by each member's Appearance —, takes the values the application reports, takes Snapshots, and exports and erases a member; Leagues places members in the divisions of a board's League and settles its weeks.

Status

Part State
Board, Boards, Measure, Ties: boards on six measures, from a configuration Implemented and tested
TieBreak, Aggregate, Direction, Ranking: up to two tie-breaks, then the first to reach a score or a shared rank Implemented and tested
Period, PeriodKind, Schedule: days, ISO weeks, months, quarters, years, seasons, ever and sliding windows, in a timezone Implemented and tested
LeaderboardProjection: scores kept up to date from the journal, cancellations, rebuilds and sliding windows Implemented and tested
Leaderboards: standings, ranks, circles, rankings by object, reported values, appearances, snapshots, export and erasure Implemented and tested
Title, Team, TeamRow, Chance: titles from a threshold; teams ranked, with the luck a board enables Implemented and tested
ValkeyScoreStore, ValkeyConnection, RawCommandConnection: the scores in the sorted sets of Valkey Implemented and tested
Appearance, Visibility, Row, Standing: hidden by default, by name or by pseudonym Implemented and tested
Snapshot, Placing, LeaderboardObserver: the final standing of a period, told once Implemented and tested
League, Leagues, Division, Settlement, Formation: weekly divisions in tiers, formed by arrival or by volume, promotion and relegation Implemented and tested
Four stores and their in-memory implementations, with the contracts any store passes Implemented and tested
Exceptions under one LeaderboardsException interface Implemented and tested

Documentation

Document What it covers
Installation Requirements and installing.
Boards and periods Measures, verbs, conditions, periods, timezones, seasons, sliding windows, ties and tie-breaks, rankings by object and the configuration of boards.
Scores and the projection How the journal is read, cancellations, rebuilds, and the values the application reports.
Standings A board as one viewer sees it, ties, the viewer's own line and circles.
Appearing on a board Hidden by default, by name or by pseudonym, and what each viewer sees.
Snapshots Freezing a period, rewarding the first, and showing the final standing.
Leagues Weekly divisions in tiers, entering a division, divisions formed by volume, promotion and relegation at the end of the week.
Teams and titles Titles held from a threshold, teams ranked, and the luck a board adds to their scores.
Erasure What a member's export holds and what erasing them removes.
Writing a store The four store contracts an application's storage implements, and the scores in Valkey.
Extension points What an application gives the library: stores, observers, the clock.
Exceptions LeaderboardsException and its exceptions, with their messages.
Testing The library's tests and mutation bar, and how to test code that reads the boards.
Reference Every type of the library, with its role.

Quick start

use Tilttek\Leaderboards\{Appearance, Boards, LeaderboardProjection, Leaderboards};
use Tilttek\Leaderboards\Store\{InMemoryAppearanceStore, InMemoryScoreStore, InMemorySnapshotStore};

$boards = Boards::fromArray([
    'games-month' => ['measure' => 'count', 'verbs' => ['game.played'], 'period' => 'month'],
    'level' => ['measure' => 'latest'],
], 'America/Toronto');
$scores = new InMemoryScoreStore();
$projection = new LeaderboardProjection($boards, $scores); // handed to the journal's projections
$leaderboards = new Leaderboards($boards, $scores, new InMemorySnapshotStore(), new InMemoryAppearanceStore(), $clock);

$leaderboards->appear($member, Appearance::pseudonym('Le Nain Gris'));
$standing = $leaderboards->standing('games-month', viewer: $member);

Requirements

PHP 8.5 or later.

Contributing

Contributions are welcome on the PHIL monorepo: read the contribution guide and the code of conduct. Report a vulnerability privately, as the security policy explains, never in a public issue.

License

MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Tilttek project. See LICENSE.