Skip to content

Latest commit

 

History

129 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Три отметки

Три отметки

The all-in-one companion for «Мир танков»: a site, a game modpack and its manager.
Player stats · Marks of excellence · Tank analytics · Clans · Replays · Streamer tools · In-game HUD · Developer API

Site API Game client Status

Bun Next.js React NestJS TimescaleDB Tauri Python

What's inside · Architecture · Getting started · Commands · CI and releases · Docs


Три отметки is one place for everything a «Мир танков» (Lesta, RU realm) player looks up between battles, plus a modpack that shows the rest right in the game. It is an independent fan project, not affiliated with Lesta Games.

Important

Game data comes from the Lesta API under its terms, and they are hard rules here:

  • every page carries the attribution;
  • game accounts link only through Lesta ID, never with a password;
  • no ads;
  • data retention and deletion are honoured.

The mod is fair play: it shows only the player's own data and what the client already shows, never enemy positions, reloads or aim.

What's inside

🌐 Site — triotmetki.ru

  • Players: profiles with WN8, EFF and our Броня-Индекс, recent periods, sessions, activity calendar, compare, signatures.
  • Tanks: catalogue with server stats and tier lists, tank pages, 3D armor, tech tree, builds, supertest.
  • Marks of excellence: thresholds and their history, real mark curves from mod data, projections.
  • Clans, replays, maps and tactics: heatmaps, a tactic board, guides, platoons, tournaments.
  • Streamers: overlays, challenges, Twitch and VK Video Live commands, a Twitch panel.
  • Blog, shop archive, events, bonus codes and mini-games.
  • Bots: Telegram, Discord and VK, plus web push and email digests.
  • Три отметки Plus: metered free tier, trial, promo codes and referrals.
  • ru/en, dark and light themes, PWA, full SEO. No mocks: pages without data show honest empty states.

🎮 Modpack — .mtmod for client 1.45

  • 41 components, each with its own switch, as split packages or one union package.
  • Battle HUD drawn with the client's own icons:
    • panels that replace the stock ones: team HP and score, damage log, sixth sense;
    • hit log, marks with a projection, consumables, reload, equipment, clock;
    • arty meter and platoon points.
  • Hangar: marks and ratings, hangar info, session stats and goals, personal bests, a tidier hangar.
  • Replays: a replay manager and upload to the site.
  • Streamer mode and chat filter.
  • Panels move with Alt + mouse and stay on screen at any resolution and interface scale.

🧰 Manager — Tauri 2 desktop app

  • Finds the game by itself; installs a ready-made set in one click.
  • Components, sets, profiles, snapshots and rollback.
  • Conflict check against third-party mods.
  • Moves the modpack after a client patch; updates from our VPS.

🔌 Developer API

  • Public /v1 with keys and webhooks.
  • A typed TypeScript client: @otmetki/sdk.

Architecture

flowchart LR
  subgraph game["Player's PC"]
    client["«Мир танков» 1.45"]
    mod["Modpack<br/>Python 2.7 + Gameface UI"]
    manager["Manager<br/>Tauri 2"]
    client --- mod
    manager -- installs --> mod
  end

  subgraph vps["VPS · docker compose"]
    caddy["Caddy<br/>TLS · /downloads"]
    web["Next.js 16<br/>triotmetki.ru"]
    api["NestJS API<br/>api.triotmetki.ru"]
    worker["Worker<br/>BullMQ collector"]
    db[("PostgreSQL 17<br/>+ TimescaleDB")]
    redis[("Redis")]
  end

  lesta["Lesta API"]

  caddy --> web & api
  web --> api
  api --> db & redis
  worker --> db & redis
  worker -- rate-limited --> lesta
  mod -- signed battle results --> api
  manager -- releases --> caddy
Loading
  • One server image, two entrypoints: src/main.ts serves the site API, the developer API, auth and mod ingest; src/worker.ts runs the collector that pulls the Lesta API into TimescaleDB.
  • Everything is stored on the VPS: replays and armor models on a volume, public downloads served by Caddy at /downloads/. There is no S3 and no CDN.

Stack

Layer Tech
Web Next.js 16, React 19 + React Compiler, next-intl, TanStack Query/Table/Virtual, visx, Base UI, cmdk, motion, Embla, SCSS modules, FSD
API NestJS 11 on Bun, better-auth (Lesta ID, Telegram, VK Mini App), Zod contracts, OpenAPI
Worker BullMQ jobs, a shared Redis rate limiter, cockatiel circuit breaker
Data PostgreSQL 17 + TimescaleDB, Prisma 7, Redis
Game mod Python 2.7 .mtmod packages (logic tested on Python 3), React Gameface UI
Manager Tauri 2: Rust core + React UI
Tooling Bun workspaces + catalog, ESLint, Prettier, Stylelint, Vitest, Playwright, knip, jscpd, madge, Husky, commitlint

Repository

apps/
  web/client/        Next.js site (Feature-Sliced Design)
  web/server/        NestJS API + collector worker, Prisma schema, Lesta client, replay parser
  game/modpack/      game-client modpack: core, companion, features, catalogue
  game/manager/      modpack manager: tauri/ (Rust) + web/ (React)
packages/            only code shared between apps
  ratings/           WN8, EFF, Броня-Индекс, MoE math
  schemas/           Zod contracts shared by client and server
  gamedata/          loadout calculator and the game-data model
  design-tokens/     SCSS tokens for the site, the manager and the in-game window
  icons/             SVG icon set as React components
  sdk/               @otmetki/sdk, the public API client
  logger/            pino wrapper
e2e/                 Playwright smoke tests
infra/caddy/         Caddyfile for docker-compose.yml
docs/                architecture, guides, ops, product, research, specs

Getting started

You need Bun ≥ 1.3, Docker and Python 3 (for the modpack's tests). The manager also needs Rust.

bun install
cp .env.example .env     # set INTERNAL_API_TOKEN (32+ chars: openssl rand -base64 32)
bun run dev:infra        # TimescaleDB :5434, Redis :6380, Mailpit :1025 (inbox :8025)
bun run db:push          # extensions + prisma db push + the Timescale layer
bun run gamedata:import  # optional: vehicles, modules, equipment and maps from the public client-data repos
bun run dev              # server :4000 + client :3000

bun run dev:all also starts the worker, and bun run dev:manager starts the manager.

Note

No Lesta key? Everything still runs. There is no mock and no generated data anywhere.

  • With LESTA_APPLICATION_ID empty, the server boots, the worker starts in degraded mode and every page shows its empty state.
  • LESTA_NOTICE=true adds the site-wide «data not connected yet» banner. It is a runtime switch: restart the client, no rebuild needed.
  • bun run gamedata:import still fills the tank catalogue, maps and missions.
Dev server troubleshooting

bun run dev and dev:all restart a crashed server or client by themselves (concurrently --restart-tries). Ctrl+C still stops everything.

  • next dev slowly eats memory or stops answering. Stop it, delete apps/web/client/.next/dev and start again. The dev-only settings in apps/web/client/config/dev-server.ts keep memory flat:

    • Turbopack's disk cache stays on;
    • memory eviction is 'full';
    • the React Compiler runs through its Rust port;
    • webpack loaders run in worker threads;
    • reactDebugChannel is off. With it on, Next 16.3 holds every HTML request that never opens an HMR socket.

    dev:client also caps the V8 heap at 6 GB, so Next restarts itself before the machine runs out of memory.

  • The API disappears. dev:server and dev:worker run under nodemon (apps/web/server/nodemon.json), which watches only the server's own sources, because Bun's --watch crashes on Windows. After a real crash, save any file or type rs + Enter.

  • Need a second next dev? Start it with NEXT_DIST_DIR=.next/probe and another -p.

  • Disk: the Turbopack cache can reach tens of GB. Deleting .next/dev while the dev server is stopped is always safe.

Commands

Command What
bun run dev · dev:all · dev:client · dev:server · dev:worker · dev:manager Dev servers
bun run dev:infra · dev:infra:down Local TimescaleDB, Redis and Mailpit
bun run db:push · db:reset · db:studio Schema sync (no migrations before production), full reset, Prisma Studio
bun run gamedata:import Import the game client's data
bun run verify typecheck + lint + import cycles + UTF-8 + format + styles: what CI runs
bun run fix Auto-fix lint, formatting, styles and the Prisma schema
bun run test · test:changed Vitest across the monorepo · only the tests your uncommitted changes reach
bun run test:modpack The modpack's Python suites
bun run test:e2e · e2e:screens Playwright smoke · the screenshot suite
bun run lint:unused · lint:dupes knip (unused files, exports, dependencies) · jscpd (copy-paste)
docker compose up -d --build Production-like stack: Caddy, client, server, worker, db, redis

Use bun run test, never bun test.

CI and releases

Workflow When What
deploy manual verify, tests, modpack suites and the e2e smoke, then client and server images to ghcr and a rollout on the VPS. Code that already passed skips the checks.
release manual Builds the modpack and the manager for versions not yet on the VPS and publishes them there
modpack PRs touching apps/game/modpack, or manual pytest, ruff, vermin; a manual release build of the packages and the component catalogue
manager PRs touching the manager, or manual UI checks, cargo fmt / clippy / test on Windows; a manual NSIS installer build

To release, bump version in apps/game/modpack/package.json (its otmetki.games lists the supported clients) and in apps/game/manager/package.json, commit, and run release. The first production deploy follows docs/ops/deploy.md.

Docs

Start here
docs/README.md Index of every doc
docs/product/features.md Product scope and what is done
docs/specs/2026-09-24-otmetki-design.md Architecture
docs/guides/ Code style: client, server, shared
docs/architecture/fsd.md Feature-Sliced Design in the client
docs/research/data/lesta-api.md Lesta API reference and terms
apps/game/modpack/README.md The modpack and its components
CLAUDE.md Guidance for AI agents working in the repo

Contributing

  • Commits: conventional commits, enforced by commitlint.
  • Pre-commit hook: lint-staged, a typecheck of the touched workspaces, and the modpack suites when Python changes.
  • Code: every user-facing string goes through next-intl in ru and en. Shared contracts live in @otmetki/schemas. Ready-made packages are preferred over custom code.

© Три отметки. «Мир танков» and all related game content are the property of Lesta Games.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages