Partner platform model
Luckotto is one self-contained app: business pages, partner APIs, an embeddable player UI, and background scanner jobs.
Entity model
Lifecycle
- A website user creates a partner site and receives the initial API key.
- The user copies an /embed URL with partner payout address, playerUname, and playerIdentifier.
- The embed queries /api/luckotto routes in the same monolith. Browser code never touches Postgres directly.
- The API routes return one min-round-scoped deposit address from partner payout address and player context. Trusted server-side clients use /api/luckotto/tickets/authenticated with the partner API key.
- The player sends Bitcoin to the player/partner/minimum-round deposit address.
- The root worker loop or scanner commands record payments, credit Luckotto tickets, and settle rounds.
- Public round and Luckotto ticket pages remain visible on the website.
- A ticket record is public: anyone with its round number and ticket UUID can view its tiles, draw weight, and status.
Product rules
Single deploymentThe website, /api/luckotto routes, /embed player UI, and worker loop are built from one root package.
Database accessServer-side pages, route handlers, and jobs use shared root utilities to talk directly to Postgres.
API surfaceThe monolith exposes a small JSON REST surface under /api/luckotto.
Embed isolationThe embed communicates only with public /api/luckotto routes and can be embedded by partners.
No iframe secretsEvery API endpoint used by the iframe is public and must work without a partner API key.
Player contextPartners pass playerUname and playerIdentifier to create deposit addresses and look up player Luckotto tickets.
REST APIPartner-facing API operations are plain JSON REST endpoints.
Iframe contract
Player help<iframe title="Partner Lotto" src="https://luckotto.example/embed?partner=tb1pyqn8k6d9lyjen5akpz7v42y37vc42cp6tzepvvvr8h63ulecu27suulrjw&playerUname=DisplayName&playerIdentifier=UNGUESSABLE-PER-PLAYER-SECRET" style="width:100%;max-width:560px;height:760px;border:0;" loading="lazy" ></iframe>
The iframe URL carries public player context only. It must never include an API key or server-side partner settings.
The embedded navigation exposes play, rounds, verification, how-to-play, and FAQ pages with the same public context preserved in the URL.