- Python 49.6%
- TypeScript 49.5%
- JavaScript 0.4%
- Shell 0.2%
- CSS 0.1%
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
|
||
|---|---|---|
| .github | ||
| .jules | ||
| api | ||
| docs | ||
| extension | ||
| frontend | ||
| ops | ||
| scripts | ||
| static | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .mcp.json | ||
| .pre-commit-config.yaml | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| lighthouserc.json | ||
| nginx.conf | ||
| plan.md | ||
| pyproject.toml | ||
| README.md | ||
| start.sh | ||
| uv.lock | ||
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.
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 |
![]() |
![]() |
| Training | Market |
![]() |
![]() |
| NPC loot | Light theme |
![]() |
![]() |
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
- A member submits a Torn API key to
POST /api/keys. - The backend validates the key and faction membership, then stores it encrypted with Fernet.
- The backend issues a signed session JWT, sets a
Secure,HttpOnly,SameSite=Strictcookie in production, and keeps bearer-token compatibility for the current web client and Companion. - Protected requests bind the JWT subject to
X-Player-Id; revoked JWTs and deactivated faction members are rejected immediately. - 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
- Multi-tenant isolation ADR
- Multi-tenancy status and launch gates
- Multi-tenancy threat model
- Migration runbook
- Incident response runbook
- Encrypted database restore runbook
- Performance audit and baselines
- Torn API v2 migration notes
- Companion documentation
License
Private software built for The Masters [TM]. It is not licensed for public redistribution.





