Skip to content

Thirteen modules, described by what you do with them

A module list is usually a feature list in disguise. This one is ordered the way it was built — each module finished, with its administration and its failing-case tests, before the next one started — and each entry says what an operator actually does with it on a working day.

What happens at a desk, module by module

A module is only marked done when its models and indexes exist, every endpoint is implemented and validated, its admin screens shipped in the same pass, its tests pass including the failure cases, and the player app runs against it with that part of the mock switched off. Anything short of all five leaves it marked partial.
  1. M0

    Foundation

    Nothing, and that is the point.

    Boot order, configuration, the response envelope, the error classifier, the audit log, the index builds that finish before the port binds. Every module above it inherits these, which is why none of them reinvents them.

  2. M1

    Auth

    Watch a player sign up and sign in, and sign a stolen session out.

    Registration, login, refresh with rotation, forgotten-password recovery, a self-hosted captcha, and one live session per account — a second device signs the first out and the app receives SESSION_REPLACED, so it can explain instead of just failing.

  3. M2

    Profile and security

    Reset a withdrawal password a player has locked themselves out of.

    Two passwords that behave differently: the login password changes whenever the player wants and ends every session when it does; the withdrawal password is set once and only an operator reset clears it. The security score is computed on request from three checks, never stored.

  4. M3

    Wallet and ledger

    Read a balance and be able to say where every unit of it came from.

    One entry point writes money. A pending row goes down before the balance moves, one guarded atomic update moves it, and a debit past zero is rejected rather than clamped. Idempotency is a unique index, not a lookup.

  5. M4

    Payments

    Work the deposit queue and approve withdrawals.

    Deposits arrive as agent transfers and sit pending until a staff member matches the transaction id — nothing auto-credits. Agent numbers come from a pool claimed by a single atomic round-robin, so two players cannot be handed the same number at the same moment.

  6. M5

    Aggregator integration

    Sync the catalog, curate the lobby, and never touch a bet by hand.

    Four games-API endpoints we call and five wallet endpoints we host. A catalog sync overwrites only provider-owned fields, so re-syncing can never undo an operator’s curation, and a game whose category does not map is reported rather than filed somewhere wrong.

  7. M6

    Bonus and turnover

    Set a deposit bonus and know exactly when it is cleared.

    The requirement is the bonus amount times the multiplier, never the deposit times the multiplier. Turnover accrues per game weight. Forfeit deducts what the bonus made, not what the player already had.

  8. M7

    Rewards

    Run daily check-in, streaks, rebate and cashback.

    Five reward kinds behind one unique index on player, kind and period — the single guard that makes a retried claim return the first result instead of paying twice.

  9. M8

    VIP

    Set the tiers and let the salary run.

    A tier needs both thresholds met, deposited and wagered. A stray “or” there turns a retention programme into a withdrawal fee, so the rule is written once and tested at the boundary.

  10. M9

    Referral and agent

    Pay agents on a schedule and read the tree.

    Three levels of commission, recomputed on a schedule rather than on every bet, because the bet callback is the one thing that cannot be slow. The recompute is re-runnable: a schedule you cannot retry eventually pays twice.

  11. M10

    Records and reports

    Answer “what happened yesterday” without opening a database client.

    Betting, transaction, bonus and referral records read from the one ledger. A row in the betting record is a round, not a transaction. Day buckets are cut in the operator’s own IANA timezone and stay correct across a DST change.

  12. M11

    Content

    Change the banner, the promotion and the notice yourself.

    Banners, promotions, announcements, FAQ and the theme registry are rows, not deploys. A ninth theme is one style block and one row.

  13. M12

    Back office

    All of the above, from a desk, by staff who are not engineers.

    Eight groups, a menu rendered from a permission table rather than from markup, and an append-only audit row for everything anyone did. A group with no page the person may open is absent, not greyed out.

Three rules that are easy to state and easy to get backwards

Each of these is written once, in one place, and tested at the boundary where it inverts.
A wagering requirement is the bonus times the multiplier
Multiplying the deposit instead is the commonest way a bonus programme becomes unclearable, and players notice within a day.
never the deposit
A VIP tier needs both thresholds met
A stray or there turns a retention programme into a withdrawal fee.
deposited and wagered
Forfeiting a bonus deducts what the bonus made
The player’s own money stays theirs. The bonus, and anything made while it was live, does not.
not the grant

The rules above, on the screens a player actually touches

The wagering rule is not a footnote in a terms page here — it is printed on the bonus a player is choosing, in the same sentence as the cap. A player who cannot find the requirement will find your support desk instead.
The deposit screen, showing bonus options with their turnover requirement
Deposit. Four rails, the cashier's hours, and every bonus carrying its own turnover multiple and cap.
The withdrawal screen
Withdrawal. Refused outright while turnover is owed, with the figure snapshotted when the request was made.
The VIP ladder
VIP. Both thresholds shown, because a tier needs both met.
A game category in the lobby
A catalog category. Public without a session; launching a game, including a demo, is not.

Money is an integer, and time is a timezone

Two decisions that are cheap on day one and impossible to change on day four hundred.
Every amount is stored at a scale of ×100,000
৳3.56 is 356000. A human-typed decimal is rounded once, at the edge, and never again. The scale is the aggregator’s own wire scale, so the adapter converts nothing and rounds nothing on the way in.
no floats
Reports bucket the day in your timezone
Not a fixed offset that drifts. A day boundary stays correct across a daylight-saving change, and the timezone in force is stated on the screen so nobody has to guess which midnight a report means.
any IANA zone
A report row is a round, not a transaction
One spin can produce several bet and win callbacks that share a round id. The ledger stores the transactions; the report groups them, so the betting record reads the way a player describes their own session.
rounds

What is deliberately not included

Four things narrower than a brochure would make them sound. They are written down here so that you find them now, rather than in week three.

Payments ship as reference adapters for one market. bKash, Nagad, Rocket and Upay are Bangladeshi mobile-money rails, and they run through a manual reconciliation queue because none of those providers offers a merchant API to a gambling account. A deposit stays pending until a staff member matches the transaction id; it never auto-credits. A new market means a new adapter written against that market’s rails — the queue, the channel pool and the audit trail are already there, the rail is not. We do not claim any payment method, because that claim is never true.

SMS codes are logged, not sent. No gateway is contracted, so verification and recovery codes are written to the server log until you contract one. One-time codes are switched off for registration and login on purpose: blocking signup on a message that may never arrive loses accounts.

The sportsbook is a list of brand links. Players are handed off to a sportsbook you have a relationship with. There is no odds feed, no bet slip and no settlement here, and the vertical is deferred rather than half-built.

Withdrawal is gated on remaining turnover, outright. While anything is owed, a withdrawal is refused — not partial, not pro-rata. The turnover figure is snapshotted when the request is made, not when it is approved, and a payout card becomes immutable once it has paid out. This is a design decision, not an omission, and it is the behaviour your support desk will be explaining.

The fastest way to judge this is to watch it run