Faction management toolkit for Torn.com — real-time member tracking, war coordination, training guides, market analysis, and 25+ tools. Built with FastAPI + Next.js 15.
  • Python 49.6%
  • TypeScript 49.5%
  • JavaScript 0.4%
  • Shell 0.2%
  • CSS 0.1%
Find a file
Paweł Orzech 36b0536727 fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts
Announcements: expiry was compared as text against datetime('now'), so the
admin UI's toISOString() values ("…T…Z") stayed on the banner until UTC
midnight and offset values used wall-clock text. Compare through SQLite
datetime() instead (repairs existing rows too) and reject expiry strings
that SQLite cannot parse (400 in admin, JSON error in MCP).

Stats: get_snapshots returned the OLDEST `limit` snapshots; it now returns
the most recent ones, still oldest first.

MCP tool descriptions now match behaviour: player_stats, send_chat_message
(no live broadcast), add_target (overwrites), add_stakeout (notes only /
owner check), remove_target, create_notification (in-app only),
spy_estimate (fallback shape), chain_analytics (top 20), war_status (last 10).

CLAUDE.md: fix CURRENT_VERSION location (version.ts), drop stale counts,
replace the Playwright walkthrough reference with Claude in Chrome, and state
the post-deploy check plainly with its reason. AGENTS.md follows the heading.

Release 1.82.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SDfBz9WqvFrk4A21g4Hsz4
2026-09-25 00:41:03 +02:00
.github Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00
.jules fix(security): escape chat-search snippets + restrict extension-auth postMessage origin 2026-06-24 15:46:21 +02:00
api fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts 2026-09-25 00:41:03 +02:00
docs Fix personal workspace features and data scope (#137) 2026-09-24 11:27:34 +02:00
extension refactor: collapse repeated loader/helper bodies (#133) 2026-09-19 23:16:10 +02:00
frontend fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts 2026-09-25 00:41:03 +02:00
ops Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00
scripts Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00
static chore(cleanup): untrack Plans drafts, superpowers history, favicon, dead frontend 2026-09-13 22:52:39 +02:00
tests fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts 2026-09-25 00:41:03 +02:00
.dockerignore feat(perf): Sprint 1 — observability + quick wins 2026-04-27 10:27:02 +02:00
.env.example Improve TM Hub functionality and user experience 2026-08-02 00:27:46 +02:00
.gitignore docs: AGENTS.md becomes a pointer to CLAUDE.md; ignore egg-info 2026-09-13 22:53:24 +02:00
.gitleaks.toml ci(security): add gitleaks secret scanning (CI + pre-commit) 2026-06-24 15:39:10 +02:00
.mcp.json feat: MCP server embedded in FastAPI — 30 tools for faction management 2026-04-11 14:53:33 +02:00
.pre-commit-config.yaml ci(security): add gitleaks secret scanning (CI + pre-commit) 2026-06-24 15:39:10 +02:00
AGENTS.md fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts 2026-09-25 00:41:03 +02:00
CLAUDE.md fix: announcement expiry, latest stat snapshots, accurate MCP tool contracts 2026-09-25 00:41:03 +02:00
docker-compose.yml feat: multi-stage Docker build, FastAPI serves Next.js export 2026-03-28 15:54:25 +01:00
Dockerfile Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00
lighthouserc.json Fix personal workspace features and data scope (#137) 2026-09-24 11:27:34 +02:00
nginx.conf fix: restore legacy login and grant The Masters complimentary access (#136) 2026-09-24 10:08:39 +02:00
plan.md fix: harden multitenant SaaS boundaries 2026-07-26 10:38:35 +02:00
pyproject.toml ci(test): ratchet coverage contracts and mutation 2026-07-13 00:24:12 +02:00
README.md Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00
start.sh fix(enemies): stop the Enemy page crashing when you load a faction 2026-07-23 17:30:35 +02:00
uv.lock Launch isolated personal and faction workspaces with Xanax billing (#135) 2026-09-24 09:49:39 +02:00

TM Hub login screen

TM Hub

An operational toolkit for Torn.com factions.
War coordination, member readiness, faction intelligence, economic tools, live chat, and in-game Companion overlays in one self-hosted platform.

Python 3.12 Next.js 16 React 19 Pytest coverage gate

Important

The production instance at hub.tri.ovh is the private, legacy single-tenant deployment for The Masters [TM], faction 11559. The repository also contains the tested multi-tenant control plane, per-tenant data isolation, onboarding, and Xanax billing flows, but the SaaS launch lock and all component flags are off by default. See Multi-tenancy status before changing those boundaries.

What TM Hub is

TM Hub turns Torn, TornStats, and YATA data into decisions faction members and leaders can act on. It is designed around four rules:

  • Explain the decision. Say what a number means and what the player should do next.
  • Teach the mechanic. Pair each tool with the guidance a player needs to use it, rather than showing raw API data.
  • Show provenance. Distinguish live, cached, imported, and estimated data.
  • Fail clearly. Show explicit loading, empty, stale, and error states when an upstream service is down.

Product surfaces

Faction operations

Surface What it provides
Dashboard and team Live faction state, readiness, status, energy/cooldowns, travel, hospital, chain, OC, loot, and chat summaries
Ranked wars Current opponent, score and progress, enemy threat estimates, target claims, off-limits coordination, reports, and history
Chain tracker Chain discovery, member contribution, bonus hits, assists, timeline, analytics, and war reports
Chain reports Torn's official report for each completed chain: every bonus hit and who took it, per-member respect and attack mix, and the members who hit nothing
Organized crime OC assignments, participant roles, readiness, checkpoint pass rates, crime-experience ranking, and chat digest
Armoury competitions Deposit-based competitions by item/category, polling, leaderboards, and admin controls
Scheduling and notifications Faction schedule, announcements, inbox, web push/PDA delivery, and configurable notification groups
Faction chat Channels, threads, search, reactions, pins, mentions, presence, bots, assist calls, and live WebSocket updates
Faction HQ Lifetime faction stats, purchased upgrades, hall-of-fame placings, the position and ability matrix, and the bank ledger

Intelligence and player tools

Surface What it provides
Spy Central Player/faction lookup, TornStats and YATA intelligence, local spy history, stat estimates, and admin curation
Targets, stakeout, and activity Tagged target lists, player status watch, activity heatmaps, flight tracking, hit calling, and mug-opportunity scoring
Stats and training Stat snapshots, growth leaderboards, gym formulas, happy jumps, energy planning, and SE/Xanax comparisons
Market and travel Torn item catalog, live prices and market listings, margins and taxes, foreign stock, travel timing, and profitability
Stocks, bounties, and revives Portfolio/ROI views, bounty prioritization, revive history, success rates, and leaderboards
Company tools Faction company directory plus director-only employee, application, stock, train, trend, and runway analysis
Awards and guides Honor/medal progress, circulation context, FAQ, game guides, and curated userscripts

TM Hub Companion

extension/ is a separately built userscript that brings authenticated TM Hub data into Torn pages. It supports overlays for faction intelligence, flights, activity, hit calling, chat, and related shortcuts; rollout-heavy features are controlled through the authenticated feature-flag contract. Its token is independently issued and revocable, and the production bundle is built into /companion.user.js as part of the Docker image.

Screenshots

Dashboard Team
TM Hub dashboard in dark mode Faction team overview
Training Market
Training guide and calculators Market scanner and profit calculations
NPC loot Light theme
NPC loot levels and reservations TM Hub dashboard in light mode

Player names in the screenshots are anonymized.

Architecture

flowchart LR
    B["Browser / installed PWA"] --> N["nginx :8000"]
    C["TM Hub Companion on torn.com"] --> N
    N -->|"static HTML, JS, CSS"| S["Next.js static export"]
    N -->|"HTTP, SSE, WebSocket"| A["FastAPI via Gunicorn<br/>2 Uvicorn workers"]
    A --> T["Torn API v1/v2<br/>TornStats · YATA"]
    A --> D["SQLite WAL<br/>repository layer"]
    A --> R["Redis<br/>pub/sub · leader lease · shared limits"]
    L["One APScheduler leader"] --> A
    D --> BK["Optional encrypted B2 backups"]

Runtime model

  • Frontend: Next.js 16 App Router, React 19, TypeScript, Tailwind CSS v4, and Chart.js. output: "export" produces static assets; there is no Next.js server in production.
  • API: Python 3.12 and FastAPI with 32 feature routers and approximately 240 HTTP/WebSocket route handlers.
  • Persistence: SQLite in WAL mode through thread-local pooled repository connections. The 59 numbered migrations run automatically at startup.
  • Background work: APScheduler 4 jobs run only in the elected worker. Production uses a Redis lease; a single-host deployment without Redis falls back to a POSIX file lock. Losing a Redis lease stops that scheduler before another worker takes over.
  • Realtime and shared state: Redis provides cross-worker chat pub/sub, presence, scheduler leadership, shared rate limits, and distributed cache support. Single-worker development can run without Redis.
  • Edge: nginx serves precompressed static assets, proxies API/WebSocket traffic, and includes the canonical host in its cache key. The final image pins and validates a SQLite runtime containing the WAL-reset corruption fix.
  • Observability: optional Sentry-compatible backend and browser reporting with secret/PII scrubbing, request analytics, Companion RUM, health checks, and production-image load tests.

Authentication and authorization

  1. A member submits a Torn API key to POST /api/keys.
  2. The backend validates the key and faction membership, then stores it encrypted with Fernet.
  3. The backend issues a signed session JWT, sets a Secure, HttpOnly, SameSite=Strict cookie in production, and keeps bearer-token compatibility for the current web client and Companion.
  4. Protected requests bind the JWT subject to X-Player-Id; revoked JWTs and deactivated faction members are rejected immediately.
  5. Admin and platform sessions use separate token types and cookies. Tenant roles are owner → admin → member; the legacy faction retains its explicit break-glass superadmin allowlist.

When multi-tenancy is enabled, the validated request host selects a control-plane tenant and an isolated tenant database. Tenant/faction JWT claims, repositories, caches, rate limits, schedulers, WebSockets, SSE streams, backups, and realtime channels are all checked against that context. Unknown or mismatched hosts fail closed.

Repository layout

api/
├── main.py                  FastAPI app, lifespan, middleware, legacy core routes
├── config.py                Environment and feature-flag configuration
├── auth.py / tenancy.py     JWT, revocation, roles, host and tenant boundaries
├── torn_client.py           Async Torn/TornStats/YATA client and caches
├── db/
│   ├── migrations/          59 startup-applied SQL migrations
│   └── repos/               SQLite repository layer
├── routers/                 32 domain routers
└── scheduler/               Leader election and background jobs

frontend/
├── src/app/                 Static-exported application routes
├── src/components/          Domain and shared React components
├── src/hooks/               Data-fetching and UI hooks
├── src/lib/api-client.ts    Same-origin API client and auth lifecycle
└── e2e/                     Playwright functional/visual tests

extension/                   TM Hub Companion userscript, tests and build
ops/k6/                      Load-test scenarios
scripts/                     Migration, restore, calibration and verification tools
docs/                        ADRs, threat model, runbooks and engineering evidence

Local development

Prerequisites

  • Python 3.12+
  • uv
  • Node.js 22.19+ and npm (the Docker build itself uses Node 20)
  • Docker for the production-like full-stack image
  • Redis for multi-worker/realtime parity; optional when running one API worker

Install

git clone https://github.com/pawelorzech/tm-war-room.git
cd tm-war-room

uv sync --extra dev
npm --prefix frontend ci
npm --prefix extension ci

cp .env.example .env

Set at least TORN_API_KEY. In production, ENCRYPTION_KEY and JWT_SECRET are mandatory; development generates ephemeral values when APP_VERSION=dev.

Run individual development servers

# FastAPI on http://localhost:8000
TORN_API_KEY=xxx uv run uvicorn api.main:app --reload --port 8000

# Next.js UI development server on http://localhost:3000
npm --prefix frontend run dev

# Rebuild the Companion on changes
npm --prefix extension run build:watch

The browser client uses same-origin /api/* requests. Use a local reverse proxy when developing the UI against the separate API process, or run the production-like image below for an integrated stack.

Run a production-like image

docker build -t tm-hub .
docker run --rm \
  --name tm-hub-local \
  --env-file .env \
  -e WEB_CONCURRENCY=1 \
  -p 8000:8000 \
  -v tm-hub-data:/app/data \
  tm-hub

Open http://localhost:8000. Use REDIS_URL and more than one worker only when Redis is reachable.

Configuration

The minimal starter file is .env.example; runtime defaults and feature gates live in api/config.py. Important groups are:

Group Variables Notes
Torn TORN_API_KEY, TORNSTATS_API_KEY, FACTION_ID, CACHE_TTL FACTION_ID defaults to The Masters (11559)
Secrets ENCRYPTION_KEY, JWT_SECRET, SUPERADMIN_IDS, MCP_SECRET Primary encryption/signing keys fail fast outside APP_VERSION=dev
Runtime APP_VERSION, REDIS_URL, WEB_CONCURRENCY, FORWARDED_ALLOW_IPS Production defaults to two workers; shared state requires Redis
Push and storage VAPID_*, B2_*, BACKUP_ENCRYPTION_KEY, BACKUP_RETENTION_DAYS Backups use a separate encryption key and should use restricted private-bucket credentials
Observability SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATE, NEXT_PUBLIC_SENTRY_DSN, ENABLE_RUM All are optional; RUM is feature-flagged
Companion features ENABLE_FF_SCORE, ENABLE_FLIGHTS, ENABLE_ACTIVITY, ENABLE_HIT_CALLING Runtime flags exposed through the authenticated Companion contract
SaaS launch SAAS_ENABLED, MULTITENANCY_ENABLED, BILLING_ENABLED, ONBOARDING_ENABLED, NEXT_PUBLIC_SAAS_ENABLED Umbrella and component flags default to 0; provisioning also defaults to dry-run

Do not enable the SaaS flags from this table alone. Follow the migration runbook, threat model, and current launch checklist.

Verification

Backend

# Full suite; v1.76.0 collects 1,944 tests
uv run pytest tests/ -v

# CI-equivalent parallel run with coverage ratchet
uv run pytest -n auto --dist loadfile \
  --cov=api --cov-report=term --cov-report=xml --cov-fail-under=68.8

Frontend

npm --prefix frontend run typecheck
npm --prefix frontend run lint
npm --prefix frontend run test:coverage
npm --prefix frontend run build
npm --prefix frontend run size:routes
npm --prefix frontend run test:e2e

Companion

npm --prefix extension run typecheck
npm --prefix extension run test:coverage
npm --prefix extension run test:mutation
npm --prefix extension run size

Run scripts/local_ci.sh on the operator's computer for all release gates, including the production Docker image, pinned SQLite runtime, WAL concurrency, nginx, k6, Companion API contracts, Gitleaks and the mobile Lighthouse budget. Pushes and pull requests do not launch GitHub runners. The GitHub workflows remain available only as manually dispatched fallbacks.

Deployment

master is the production branch:

flowchart LR
    M["Review and merge to master"] --> L["Local release script on operator computer"]
    L --> CI["Tests, coverage, static export,<br/>E2E, mutation, size and security gates"]
    CI --> IMG["Production image + SQLite/nginx/k6 validation"]
    IMG --> C["Local Coolify API trigger, build and rollout"]
    C --> P["hub.tri.ovh"]

scripts/local_deploy.sh --deploy requires a clean local master matching origin/master, runs every local gate, then triggers Coolify with locally held credentials. A production rollout is not complete until the authenticated browser walkthrough and evidence checklist in CLAUDE.md has passed.

Legacy redirects remain:

URL Destination
rw.tri.ovh https://hub.tri.ovh/team
train.tri.ovh https://hub.tri.ovh/training

Engineering documentation

License

Private software built for The Masters [TM]. It is not licensed for public redistribution.