Portrait of Patrice GADEGBEPatrice GADEGBE

Tontini

Tontini is a tontine bookkeeping application, in which an organiser forms their circle, sets the contribution and the order of the turns, then follows the payout calendar and the history of operations.

Role
Sole author of the API and of the application
Period
From June 2024 to December 2025, for the most part in July 2025
Status
Prototype. Unpublished prototype, with no integrated payment
Technologies
Django 4.2, Django REST Framework, PostgreSQL 15, Flutter, flutter_bloc
Repositories
Two
Architecture of TontiniA Flutter application calls a Django API served by nginx and Daphne, which stores its data in PostgreSQL.ApplicationFlutter, flutter_blocshared packagesAPIDjango 4.2, REST Frameworknginx, DaphnePostgreSQL 15groups, seatspayouts, ledgerHTTPS, tokenORM
Figure 1. Architecture of Tontini. No payment provider appears in it: the application keeps the accounts, it does not move money.

Context

A tontine is a rotating savings circle: each member pays the same contribution at a fixed interval, and the sum collected goes to one of them, each in turn. Tontini keeps its books, with the amount of the contribution, its periodicity, the order of the beneficiaries and the history of what has been paid.

A first version, written in June 2024, was only a mock-up fed with simulated data. The API was developed in July 2025, in four working days, and the application was connected to it at the same time.

Problem

The organiser knows the members of their circle before any of them has installed the application, and must be able to prepare the whole tontine without waiting for them. The order of the turns also changes often before the first payout, when a member is added or asks to go earlier, and the calendar must follow without anyone having to correct it date by date.

Answer

A seat rather than an account

A member is first a seat in the circle, which carries a name, a position and an invitation code, and which is attached to an account only later. The organiser thus creates all the seats from the outset, then passes each person their code, as a text, a QR code or a link. Joining takes two calls: the first shows the group that matches the code, the second attaches the account to the seat.

A calendar rebuilt on every change

The payout calendar is kept in the database, with one row per beneficiary, and it is deleted then recreated after each change to the group or to its members. The date of each payout is deduced from the member’s position and from the periodicity, and its amount from the product of the contribution by the number of members. As soon as a first payout is confirmed, the calendar is no longer regenerated.

members = Member.objects.filter(group=group).order_by('position')
amount = group.contribution * members.count()

try:
    paid_distribution = Distribution.objects.get(is_paid=True, round=current_round, group=group)
except Distribution.DoesNotExist:
    distributions = Distribution.objects.filter(round=current_round, group=group)
    distributions.delete()
    for member in members:
        distribution_date = current_round.start_date + get_interval_duration(group.interval, member.position)
        Distribution.objects.create(
            amount=amount,
            date=distribution_date,
            currency_code=group.currency_code,
            is_paid=False,
            position=member.position,
            round=current_round,
            group=group,
            member=member
        )
Listing 1. Rebuilding the calendar of a round from the order of the members.

A ledger written on confirmation

When the organiser confirms a payout, the server writes the ledger in a single stroke: one distribution operation for the beneficiary and one contribution operation for each member. The application therefore does not track contributions one by one.

Limits and outlook

Tontini keeps the accounts of a tontine and moves no money: no means of payment is integrated, and the confirmation of a payout remains a declaration by the organiser. The model moreover provides for a single round only, so that nothing describes what happens after the last payout.

Several points need to be reworked before any real use. The checking of rights still rests largely on the application, and must be carried by the server. Amounts are stored as floating-point numbers and the ledger entries are not grouped in a transaction. The frequency of the periodicity is entered without being taken into the computation of the dates, and the notifications, whose sending is in place, are not triggered by any operation. Lastly, the tests are limited to the original template.

Back to the other projects