Search by

tilttek / points

phil

A double-entry ledger of points for gamification: balances that are sums of movements, named currencies, earning rules on members' activity with caps per period, first-in first-out expiry, cancellations as reverse movements, spending and transfers that never go negative, rebuilds, and the erasure of

0.1.0-alpha 2026-11-11 09:53 UTC

This package is auto-updated.

Last update: 2026-11-11 14:51:41 UTC


README

Points your members earn, spend and give, kept in a ledger where every point comes from somewhere and goes somewhere.

tilttek/points keeps the members' points in a double-entry ledger: each movement debits one account and credits another — a member's account, the account a rule issues from, the account of a reward, the account of expired points —, so a balance is always the sum of the movements, never a field that someone writes. Earning rules turn the members' activity, recorded by tilttek/activity, into points — ten points per game, fifty at most a week —, in one or several currencies the application names; a cancelled activity reverses what it earned. Points can expire, first in first out; a spending or a transfer never makes a balance negative, while a cancellation that does is written as it is. When a rule changes, the points derived from the activity are recomputed from the journal over the period the application chooses, and the movements decided by people — spendings, transfers, grants — stay as they are. Erasing a member deletes their movements and keeps the other members' points. It is not money: points are never converted into a currency, and nothing here handles a payment.

It is for an application that rewards what its members do — a community site, a store's loyalty programme, a game site — and wants balances it can explain line by line. tilttek/points-bundle integrates it with Symfony and keeps the ledger in Doctrine DBAL; an application without Symfony takes the library alone and writes its own Ledger, or uses the one in memory.

It is a plain PHP library whose dependencies are tilttek/activity, the journal the rules read, phil/resource, the opaque reference of a member, and psr/clock, the clock that stamps each movement. Members are references the application gives, member:44: the library never reads a name, an e-mail or an account.

The design is small: an Account and a Movement between two of them, kept as LedgerEntry lines by a Ledger; Points reads balances and histories and writes what the application decides; PointsProjection reads the journal of activity through EarningRules; Lots follows what is left of each credit for the expiry.

Status

Part State
Account, Currency, Currencies, MovementKey, Movement, LedgerEntry: the ledger's values, checked Implemented and tested
Ledger and InMemoryLedger: written once by key, covered payments, balances, net between two accounts, statements, rebuilds, erasure Implemented and tested
Points: balances, histories, grants, revocations, spendings, refunds, transfers, expiry, erasure Implemented and tested
EarningRule, Cap, Period, Rules: points per gesture, caps per member and period in a timezone, context conditions Implemented and tested
PointsProjection: the activity turned into points, cancellations reversed, rebuilds Implemented and tested
Lots and Lot: expiry first in first out, debts paid by the next credits Implemented and tested
Exceptions under one PointsException interface Implemented and tested

Documentation

Document What it covers
Installation Requirements and installing.
The ledger Accounts, movements, keys, balances and histories.
Earning points Earning rules, caps, conditions, the projection, cancellations and rebuilds.
Spending and giving Grants, revocations, spendings, refunds, transfers and the balance that never goes negative.
Expiry Lifetimes, first in first out, debts, and the task that expires every member.
Erasure What erasing a member removes and what it keeps.
Writing a ledger The Ledger contract an application's storage implements.
Extension points What an application gives the library: the ledger and the clock.
Exceptions PointsException and its exceptions, with their messages.
Testing The library's tests and mutation bar, and how to test code that moves points.
Reference Every type of the library, with its role.

Quick start

composer require tilttek/points
use Phil\Resource\ResourceReference;
use Symfony\Component\Clock\NativeClock;
use Tilttek\Points\Currencies;
use Tilttek\Points\Currency;
use Tilttek\Points\Ledger\InMemoryLedger;
use Tilttek\Points\Points;

$points = new Points(new InMemoryLedger(), new NativeClock(), new Currencies(new Currency('points')));
$member = ResourceReference::of('member', '44');

$points->grant($member, 50, 'welcome:44');
$points->spend($member, 30, 'order:2026-0193:redeem', 'order:2026-0193');
$points->balance($member); // 20

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.