01 · EloStore ecosystem
EloStore
FACEIT
Level 1
ELO 320
181 ELO to level 2
A services platform for CS2
A commercial service: rank boosting, AI demo analysis, tournaments, skins, a partner program. Rewritten from a monolith to a new stack without stopping sales: 109,522 lines of TypeScript, 82 PostgreSQL tables and an API that answers in 30-90 ms in production.
The team on the storefront
Every booster gets a card on the home page: an agent render, FACEIT level 10 and ELO.
Renders from elostore.ru: made with our prompt engineering on our own 3D work and our own model










Payments: three gateways
Rubles on elostore.ru, dollars and euros on elostore.pro: a Russian payment gateway, a foreign wallet and crypto. Every payment goes through the same check before it becomes an order, and card data never reaches us at all.
The log follows the payment handling in the site's code, amounts and order numbers are made up
Payment logLava
An order finds its booster
A paid order reaches Telegram within a second: a confirmation to the client, a card to admins, an offer with a button to boosters. The site is self-sufficient: the same lands in the dashboard and by email, and the orders channel is a fallback for boosters. First to tap takes it, and the booster's share is credited automatically.
Message texts from the EloStore bots' code, the order, names and amounts are made up
EloStoreTelegram · to the client
#A7K2FACEIT · 6 → 9 lvlTotal: 3,490 ₽ETA: 2-3 daysWe are matching you with a booster and will message you as soon as one picks up the order.EloStoreTelegram · to admins
#A7K2FACEIT · 6 → 9 lvlTotal: 3,490 ₽Client: ArtemETA: 2-3 daysEloStoreTelegram · to booster Stormrush
AI demo review
A player uploads a match recording and gets a round-by-round review. The parser, 70+ metrics, map zone markup and benchmarks are built from scratch, and the LLM is set up and taught by example as a coach: role, slang vocabulary, rules, good and bad reviews.
The player's numbers are made up, the metrics and review format are real
Drop a .dem or click to choose
FACEITPremierMMWingman
Tournaments
A tournament runs entirely on the site: team sign-up, the bracket, captains banning maps and the match launching on our CS2 server. After the veto only the players, the admin and the caster see the server address, and the broadcast gets replays of the best moments.

0 vs 0
Kraken to ban a map
Ancient
Anubis
Dust II
Inferno
Mirage
Nuke
OverpassDouble Elimination · 8 teams
Upper · QF
Kraken13
Nomads9
Stormline13
Havoc11
Frostbite8
Zenith13
Redline13
Aftershock6
Upper · SF
Kraken13
Stormline10
Zenith11
Redline13
Upper final
Kraken·
Redline·
A team assembles via a link
- kkiracapt
- open slot
- open slot
- open slot
- open slot
The task
EloStore was selling on an old monolith: a single server.js, data without a strict schema, payments nobody dared to touch.
The task: rewrite the whole product without stopping sales for a single day, and lay the ground for growth: SEO, new products, a second storefront for the western market.
Slice by layer
- Interfacethe pixel
- Storefront with a price calculator, client, booster and partner dashboards, a 38-section admin, a broadcast overlay
- Logicmoney and rules
- Pricing as pure tested functions, only the webhook creates orders, duplicate-proof payouts, one core for site, bot and admin
- Dataschema and migrations
- 82 tables in a dedicated schema, hand-written idempotent migrations, booster balance in three pockets under FOR UPDATE
- Serverdeploy and operations
- Standalone build as one archive, systemd and nginx, snapshot and health check on deploy, demo parsing as a separate service
- Securitythe kernel
- A guard in every admin page plus a test over every page.tsx, sign-in gate → password → 2FA, CSP without unsafe-inline
Moving without stopping sales

The old Express monolith was replaced with Next.js 15, React 19, strict TypeScript and Drizzle on top of the same PostgreSQL.
- 01First a study of the old system and the live database schema, then a Drizzle schema over the existing data: text dates converted to timestamptz, legacy ids kept
- 02Phases: schema → design system → dashboards → calculator and checkout → chats and admin → traffic switch in nginx
- 03The payment module was moved as a black box: formulas identical to the old production
- 04Server Actions for mutations, API routes only where an external call is needed: webhooks, Telegram, the game server
Result
Traffic runs on the new version, the old app is retired and archived.
Money: payments and payouts

Payments through three providers, crypto included, and automatic payouts to boosters.
- 01Only the provider's webhook creates an order, the client merely starts an invoice
- 02Atomic claim: UPDATE ... WHERE status <> 'succeeded' RETURNING. The delivery that wins the race creates the order
- 03A signature says who, not how much: the amount is checked and the price is recomputed on the server from a snapshot
- 04A provider without webhooks is covered by polling unpaid invoices every 3 minutes
- 05Payouts are idempotent per order-booster pair, balance deltas always sum to zero, and a test holds that
Result
A repeated or late webhook never creates a second order or rolls a status back.
Four roles on one database

Client, booster, partner and admin each work in their own interface over the same data.
- 01Client: orders, chat with the booster, account credentials encrypted and wiped on close, review and tips
- 02Booster: open requests, taking orders, progress, finances and withdrawals
- 03Partner on a separate subdomain: promo code, clicks, conversion, earnings
- 04Business logic lives in server/<domain>/core.ts and is called by the site, the bot and the admin: after payouts once diverged between dashboard and admin, duplicates are gone
AI demo analysis

A paid product: a player uploads a match recording and gets a round-by-round breakdown of mistakes.
- 01A Python CS2 replay parser computes aim and movement metrics
- 02LLM analysis on top of the metrics, a FastAPI worker in Docker, non-root, token compared in constant time
- 03LLM providers block Russian traffic: outgoing requests go through a SOCKS tunnel to a node abroad
Result
Heavy processing is isolated from the storefront and cannot take it down.
Streamer partner program and anti-fraud

Streamers earn a share of orders made with their promo code, viewer-count inflation is caught automatically.
- 01We count not how much the chat writes but how many live people write: a bot farm can write, but its accounts give it away
- 02Signals: share of viewers showing up in chat as real accounts, viewers to followers, a flat viewer curve, zero-follower and batch-registered chatters
- 03Public sources only: anonymous Twitch IRC and open APIs, a tracker samples every 5 minutes
- 04With too little data the verdict is honest: not enough data, not a guess
one dot is 10 viewers
Viewers over the hour
a normal channel
this channela flat line
Stories from production
Incident 01 · open
A layout does not protect a page
In Next.js, layout and page render in parallel. A check in the layout did not stop the page from querying the database and shipping data in the RSC payload: orders and client emails leaked to an unauthenticated curl.
Incident 02 · open
Admin settings never reached the price
The surcharge function took rates as an argument but was called without it. Prices used hard-coded values whatever the admin set.
Incident 03 · open
The sitemap got cached empty
ISR pages were prerendered at build time without database access, and the sitemap once got cached empty.
Stack
Next.js 15 · React 19 · TypeScript strict · Tailwind v4 · Drizzle ORM · PostgreSQL · Zod · Pino · Vitest · Python · FastAPI · Docker · nginx · systemd