Theme
Architecture
Jua Markets is a Bun + Turborepo monorepo: three web apps and a Telegram Mini App over shared packages, one Postgres database on Supabase, and contracts on two chains. This page is the map; the rest of this manual says what to do.
The model in one paragraph
Jua is non-custodial. Customers trade from their own wallets: on the website, orders are signed in the wallet and settle through Polymarket's CTF Exchange V2 over Gnosis's Conditional Tokens on BNB Smart Chain; in the Telegram Mini App, each trade is the customer's own USDT transfer to JuaTonExchange on TON. Jua's servers run the order book, match orders, send each match to the chain from an operator key, propose and record results from a resolver, and pay referrers' commissions out of a fee vault per chain (JuaVault on BNB Smart Chain, JuaTonVault on TON). There are no deposits, withdrawals or customer balances for real money; play money and Demo are virtual balances in the database.
Apps
| App | Port (dev) | Stack | What it is |
|---|---|---|---|
apps/web | 3000 | TanStack Start (Vite + Nitro), React 19 | The customer site, juamarkets.com. Relays /api/* to the API; serves the Mini App's static build at /tg/ |
apps/api | 3001 | Hono on Node (run from source with tsx) | The trading API: the only HTTP surface, some 150 paths under /api. Runs housekeeping and the workers |
apps/admin | 3002 | TanStack Start | The staff portal, admin.juamarkets.com. Holds no database credentials; reads everything through /api/admin/* |
apps/telegram | 3003 | Vite + React, static | The Telegram Mini App: Telegram sign-in, TON Connect, trading USDT on TON |
apps/mobile | Expo | The iOS and Android app (ships through EAS, not the server) | |
apps/docs | 3400 | VitePress | This site, docs.juamarkets.com |
In production each of web, admin and api is a Docker container from one infra/docker/Dockerfile, run by docker compose on one VM, behind a TLS edge (nginx on the host today; infra/deploy/Caddyfile for the compose edge profile). Supabase hosts Postgres, Auth, Realtime and Storage (Setting up Supabase).
Packages
| Package | What it holds |
|---|---|
packages/core | Framework-free domain code shared by every app: countries, categories, wallet and exchange order building (@jua/core/exchange), types |
packages/money | Integer money (micro-dollars and micro-shares, whole-cent prices), the fee formula (buyFee), FX for display |
packages/i18n | The eleven message catalogues |
packages/db | The Drizzle schema (source of truth), migrations, the migration runner, the connection |
packages/data | Server-side domain code: the CLOB engine, resolution and settlement, the exchange and TON workers, services, auth. Never reaches a browser |
packages/ui-web | Shared React primitives for web and admin |
packages/contracts | CTF Exchange V2 (vendored, BUSL-1.1) over Conditional Tokens, NoWalletFactory, JuaVault; ABIs; deploy scripts; an in-process EVM harness |
packages/ton-contracts | JuaTonExchange, ShareMinter, ShareWallet, JuaTonVault in Tact; the committed build; @ton/sandbox tests; a development chain |
packages/config | Shared TypeScript bases and the Biome plugin for the money rules |
Two lint rules shape the architecture: apps/admin may never import @jua/data or @jua/db (the portal holds no credentials), and packages/data and packages/db stay framework-free (their dependency graph is the blast radius of the database credentials).
Workers
All run inside the API process, from the one-minute housekeeping pass (or an external scheduler calling the cron route), each under a database lease so any number of API instances share the work safely:
| Worker | Every | Does |
|---|---|---|
| Market housekeeping | 1 min | Expires orders, closes markets whose time is up, finalises undisputed proposals, renews recurring events |
| Settlement (exchange) worker | 1 min, and after each trade | Sends matches to CTF Exchange, confirms them, undoes refused ones, prepares conditions, reports results, pays EVM commissions |
| TON worker | 5 s (and each pass) | Reads JuaTonExchange's transactions into the books, sends matches, closes, refunds, new markets, results and fee claims; pays TON commissions |
| Listing translations | 1 min | Translates queued listings with Claude |
| Demo housekeeping | 1 min | Fills demo orders, settles demo positions, advances simulated payments |
| House market maker | 1 min | Play money only: re-quotes every open market |
| Crypto housekeeping | 1 min | The vault model's watcher, payout queue, hourly reconciliation and custody alerts; runs only with CRYPTO_PROVIDER set |
Details: Housekeeping and The workers.
Chains and contracts
| Chain | Contract | Role |
|---|---|---|
| BNB Smart Chain (56; test 97) | ConditionalTokens (Gnosis) | Holds the USDT behind every pair of shares; splits, merges, pays redemptions after the oracle reports |
| CTFExchange (Polymarket V2, BUSL-1.1) | Settles the operator's matches of signed orders; admin = the owner Safe, operator = the API's key | |
| NoWalletFactory (Jua) | Stands in for Polymarket's wallet factories so proxy/Safe-signed orders can never move anything | |
| JuaVault (the fee vault) | Receives every fee; the operator pays referrers' collections out of it within limits; the Safe sweeps Jua's share | |
| TON (mainnet; testnet) | JuaTonExchange, ShareMinter, ShareWallet | The Mini App's exchange: holds each order's USDT or shares until it fills or ends; one share jetton per outcome per market |
| JuaTonVault (the fee vault) | Receives claimed fees; pays referrers' collections within limits; the owner multisig sweeps |
The contracts has the deploy order and commands; Keys and roles who holds what.
Data
Postgres on Supabase, owned by Drizzle (packages/db/src/schema.ts), migrated by bun run db:migrate from the deploy and never by the containers. Row-level security on every table; clients never write business tables directly. Tables the operator reads most: settlements (matches, per venue), chain_markets and chain_results (conditions and results on CTF), commission_payouts and affiliate_commissions, the ton_* tables (ton_cursor, ton_messages, ton_markets, ton_results, ton_refunds), job_heartbeats and job_leases, provider_events (durable alerts), and the audit log.
Where the design is written down
The repository's docs/ folder holds the designs this manual summarises: non-custodial.md (the model), ctf-exchange.md (orders, fees, results on BNB Smart Chain), ton-exchange.md (the TON exchange), telegram-mini-app.md, deployment.md, database.md, security-review.md, jurisdictions.md, listing-translations.md; packages/contracts/README.md for the contracts. The API's OpenAPI document is at /api/openapi.json on the API (served in production only with API_DOCS=true, through an SSH tunnel to the API's loopback port).