tradeit.gg

ENGINEERING · CROSS-CUTTING SUBSYSTEM · 10-05-2026

Redis Architecture

Cross-cutting cache, coordination bus, and queue backbone — every namespace, TTL, pub/sub channel, Bull queue, lock pattern, and the cross-repo handoffs that bind the platform together.

Read on Wiki: /engineering/backend/redis-patterns · Markdown source
Last deepened: 2026-05-10 · Tier A (foundation)
70+
Key namespaces (backend)
8
Repos read/write Redis
14
Helper modules
5
Pub/Sub channels
2
Bull queue instances

Contents


1. At-a-glance

MetricValue
Redis libraries in use2 — redis v4 (node-redis) in 7 repos · ioredis in 2 repos
Connection targetprocess.env.TRADEIT_REDIS_URI · port 6379 · plaintext (no TLS)
Repos that read or write Redis8 — backend, admin-backend, socket-server, tradebot-server, inventory-parser, stats-manager, stock-manager, oauth2-server, buff-scrapper
Helper modules in tradeit-backend14 under server/redis/
Distinct key namespaces (backend)70+ across helpers, services, controllers, queues
Bull queue instances2 — tradeitQueue (main URI) + tradeitScreenshotQueue (separate URI)
Pub/sub channels5 main — tradestate, bot <botId>, itemReserved, image, canceledtrades
Distributed locks4 patterns — lockTrade:, indexLaneLock:, updateItemsStocks, syncItemPricesRunning
Hard rule violations (KEYS)0 — no redis.keys() calls in any tradeit repo
ElastiCache IaC tracked in tradeit-infraNONE — provisioning lives outside git

2. Purpose & boundaries

Redis serves four distinct responsibilities that share one ElastiCache instance:

  1. L2 cache — write-through caches with TTLs from 5s (rate limits) to 365d (AI-generated SEO), backed by MySQL/OpenSearch source-of-truth.
  2. Coordination bus — pub/sub channels carry trade-state events, bot commands, and item-reservation notifications between tradeit-backend, tradeit-socket-server, and the bot fleet.
  3. Bull queue backbonetradeitQueue (main work) and tradeitScreenshotQueue (image processing) persist job state in the bull:* keyspace.
  4. Distributed coordination — atomic locks (SET NX), inventory mirrors (sinv:*/cinv:*), rate-limit counters.

Owns

  • Key naming conventions and TTLs
  • Pub/sub channel definitions and payload shapes
  • Bull queue topology (queue names, processor entry points)
  • Distributed-lock TTLs and renewal semantics

Does NOT own

  • Underlying ElastiCache cluster (provisioned outside tradeit-infra)
  • Bot daemon's text-protocol semantics on bot <botId> (defined in tradebot-server)
  • Express session storage internals (delegated to connect-redis middleware)
  • Eviction policy (configured at the cluster, not in code)

3. Process / runtime model

3.1 tradeit-backend — singleton client + on-demand attach

3.2 Other repos

No Redis usage: tradeit-login-server, tradeit-inventory-server, tradeit-tradebot-creator, tradeit-cms (Strapi).

3.3 Connection footprint at steady state

ProcessConnections per instance
tradeit-backend (per PM2 worker)1 main + 1 session-store + 1 per Bull queue active in that worker
tradeit-socket-server1 subscriber connection
tradeit-tradebot-server (per bot worker)1 client + 1 subscriber to bot <botId>
tradeit-stats-manager1 ioredis client
Other services1 connection each

With ~400 bot workers + 4-8 backend PM2 workers + socket-server replicas, expect 500–700 client connections at peak.

4. Architecture

graph LR
  subgraph "tradeit-backend"
    BE_API["controllers / services
(70+ key namespaces)"] BE_CFG["configurationService.js
L1 60s + L2 180s"] BE_RES["reserveAssetRedis.js
list-based reservation"] BE_TRADE["tradeRedis.js
locks + pub/sub"] BE_BULL_MAIN["mainQueue.js
tradeitQueue (Bull)"] BE_BULL_SS["screenshotQueue.js
tradeitScreenshotQueue (Bull)"] end subgraph "Redis (ElastiCache)" R_KV[("KV namespaces
cinv:* sinv:* configuration:*
insight_* invsize* bot_acc_info ...")] R_LIST[("Lists
reserved-assets_*
reserved-assets_ttl_*")] R_PUBSUB[("Pub/Sub
tradestate · bot <id>
itemReserved · image · canceledtrades")] R_BULL[("Bull keyspace
bull:tradeitQueue:*
bull:tradebotQueue:*")] end subgraph "tradeit-socket-server" SOCK_SUB["sub.subscribe()
tradestate · canceledtrades
itemReserved"] SOCK_IO["io.to(steamId).emit(...)"] end subgraph "tradeit-tradebot-server (~400 bots)" BOT_KV["invsize* · pollData
botRefreshToken · inspectResult"] BOT_SUB["sub.subscribe('bot <id>')"] BOT_PUB["publish 'tradestate'
publish 'finishedtrades'
publish 'canceledtrades'"] end subgraph "tradeit-admin-backend" ADMIN_CFG["configurationService.ts
writes configuration:*
(no DEL on edit — gap)"] end subgraph "tradeit-inventory-parser" PARSE_LOCK["indexLaneLock:*
10-min alias-swap"] end BE_API --> R_KV BE_CFG --> R_KV BE_RES --> R_LIST BE_RES --> R_PUBSUB BE_TRADE --> R_KV BE_TRADE --> R_PUBSUB BE_BULL_MAIN --> R_BULL BE_BULL_SS --> R_BULL ADMIN_CFG -.->|"NO INVALIDATION"| R_KV PARSE_LOCK --> R_KV BOT_KV --> R_KV BOT_PUB --> R_PUBSUB BOT_SUB --> R_PUBSUB R_PUBSUB --> SOCK_SUB SOCK_SUB --> SOCK_IO classDef gap fill:#2a1218,stroke:#f43f5e,stroke-width:2px,color:#fecdd3 class ADMIN_CFG gap

The dashed NO INVALIDATION edge is the single most damaging cache-coherency gap on the platform. tradeit-admin-backend writes configuration:<key> on admin edits but never publishes a DEL or pub/sub event, so tradeit-backend instances continue serving stale values for up to 180s (per-key TTL) or 360s worst-case for category-bundle reads. See Platform Configuration §6.

5. Inputs & outputs

5.1 Connection ingress

ConnectorLibraryConnection optionsFile
tradeit-backend mainredis v4socket: { host: TRADEIT_REDIS_URI, port: 6379 }server/redis.js:36-46
tradeit-backend sessionredis v4 (legacyMode)Same host, separate connectionserver/index.js:73-90
Bull tradeitQueuebull v4.16.5redis://${TRADEIT_REDIS_URI}:6379server/queue/mainQueue.js:34
Bull tradeitScreenshotQueuebull v4.16.5redis://${TI_SCREENSHOT_SKIN_REDIS_URI}:6379server/queue/screenshotQueue.js:24
tradeit-socket-serverredis v4One subscriber connectionsrc/socket.ts:55-66
tradeit-stats-managerioredisREDIS_HOST:REDIS_PORTsrc/redis/redis.service.ts

5.2 Egress (consumers)

5.3 No HTTP control plane

There is no admin HTTP endpoint for invalidating Redis keys directly. Cache busting happens through service-level redis.del(key) calls embedded in write paths, Bull job removeReserve triggering lRem on the reservation lists, and the daily 01:00 UTC cron sweeping insight_keys:<gameId>.

6. Keyspace catalog

Grouped by namespace. TTLs are in seconds unless noted. Source paths rooted at tradeit-backend/ unless qualified.

6.1 Inventory & catalog

KeyTTLOpsPurposeSource
sinvpersistentGETAggregate site inventory snapshotserver/redis/inventoryRedis.js
sinv:${botIndex}:compressedpersistentGETPer-bot inventory, zstd-compressedserver/redis/inventoryRedis.js
cinv:${steamId}:${gameId}:compressedpersistentGET, DELUser inventory per game, compressedserver/redis/inventoryRedis.js
cinv:${steamId}:lastRequestDEL on demandDELInvalidate user inventory cacheserver/redis/inventoryRedis.js
cinv:${steamId}:playedGamesDEL on demandDELInvalidate played-games cacheserver/redis/inventoryRedis.js
hardInventoryRefresh:${steamId}600SETEX, GETThrottle expensive Steam refreshesserver/redis/inventoryRedis.js
globalItemInfopersistentGETItem metadata catalogserver/redis/inventoryRedis.js
skins_count:${appId}600SETEX, GETGame skins inventory countserver/redis/categoryRedis.js:5-13
caskets730:${botId}persistentGETCS:GO container metadata per botserver/repository/containerItemsRepo.js
containers:${botIndex}n/aMGETBulk-read of container IDs across botsserver/service/botsService.js:166+

6.2 Bot fleet state cross-repo: backend reads, tradebot-server writes

KeyTTLOpsPurposeWritten by
bot_acc_info:${botId}persistentSET, GETBot login credentials + metadataserver/redis/botAccountRedis.js:4-12
invsize440:${botId}persistentSET, GETTF2 backpack metadatatradeit-tradebot-server/src/index.ts:340
invsize730:${botId}persistentSET, GETCS:GO inventory sizetradeit-tradebot-server/src/index.ts:2893
invsizeProtected730:${botId}persistentSET, GETCS:GO trade-locked itemstradeit-tradebot-server/src/index.ts:2894
invsizeAll730:${botId}persistentSET, MGETAggregate CS:GO inventorytradebot-server; read by botsService.js:166+
stayingalive:${botIndex}n/aMGETBot heartbeat, bulk-readbotsService.js:166+
pollData:${botId}persistentSET, GETBot poll state, written every 3 mintradeit-tradebot-server/src/index.ts:348
botRefreshToken:${botId}persistentSET, GET, DELOAuth2 refresh tokentradeit-tradebot-server/src/index.ts:505
inspectResult:${assetId}20SETEX, GETFloat-inspection resulttradeit-tradebot-server/src/index.ts:308

6.3 Trades & reservations

KeyTTLOpsPurposeSource
userLastTradeTime:${steamId}persistentSET, GETLast trade timestamp per userserver/redis/tradeRedis.js
userOpenTrades:${botId}900SET, GETRecent trade timestamps per botserver/redis/tradeRedis.js
userTradeLock:${steamId}persistentHGETALL, HSETHash of locked assetIdsserver/redis/tradeRedis.js
lockTrade:${assetId}900SET NX, DELAtomic trade lock (NX guard)server/redis/tradeRedis.js
tradeDisabledpersistentSET, GETGlobal trade kill switchserver/redis/tradeRedis.js
reserved-assets_${appId}none (list)LPUSH, LRANGE, LTRIM, LREMPer-game reserved asset listserver/redis/reserveAssetRedis.js:5,16,30,35
reserved-assets_ttl_${appId}none (list)LPUSH, LRANGEParallel list of {assetId, expired} JSON blobsserver/redis/reserveAssetRedis.js:6-8
⚠️ Reserved-asset expiry is encoded inside the JSON payload (expired: Date.now() + 20*60*1000), not via Redis TTL. Lazy expiry is enforced when a reader scans the list. This pattern is the root cause of the must_not.terms query bottleneck addressed by the Reserved-Assets OS-field redesign (spec 2026-05-10-reserved-assets-os-field-design.md).

6.4 Configuration cache owned by Configuration deep-dive

KeyTTLOpsNotes
configuration:${key}180GET, SETEX, DELPer-key config string. Also written by tradeit-admin-backend/services/configurationService.ts:62,71 with no DEL on admin edit
configurationCategory:${cat}:0180GET, SETEXFull-category fetch, plain
configurationCategory:${cat}:1180GET, SETEXHash-keyed (compact frontend payload)

See Platform Configuration for the L1+L2 read path, the no-pub/sub-invalidation gap, and the 11 config categories.

6.5 Marketplace, billing, identity

KeyTTLOpsPurposeSource
marketplace_config_cache:${key}variableGET, SETEX, DELMarketplace settings cacheserver/service/marketplaceConfigService.js:29-107
stripe_customer_id:${steamId}persistentSET, GETSteam ID → Stripe customer IDserver/redis/stripeRedis.js:1-20
stripeCountryIds21600 (6h)GET, SETEXStripe-supported country listserver/controllers/user.js:672-682
steamLevel:${steamId}300GET, SETEXSteam user level cacheserver/service/userService.js:238-245
steam_trade_verification:${steamId}persistentSET, GET, DELTrade-offer verification artefactserver/redis/steamTradeVerificationRedis.js
steam_trade_verification_token:${steamId}persistentSET, GET, DELVerification tokenserver/redis/steamTradeVerificationRedis.js
steamGuardLastCheckTime:${steamId}600SETEX, GETSteam Guard check throttleserver/redis/checkSteamGuardRedis.js
steamGuardStatus:${steamId}persistentGETBoolean status (1/0)server/redis/checkSteamGuardRedis.js
steamGuardEscrowDays:${steamId}persistentGETEscrow days countserver/redis/checkSteamGuardRedis.js
login:${steamId}_${ihash}session-implicitSET, DELOAuth2 login state (nonce + challenge)tradeit-oauth2-server/src/guards/login.guard.ts:52-59
sess:*30dfull setExpress session via connect-redisserver/index.js:73-90

6.6 Coupons, rate limits, server status

KeyTTLOpsPurposeSource
coupon:${steamId}10GET, SETEXCoupon-claim rate limit (rejects within 3000ms)server/service/couponService.js:348-353
searchInventory:${clientIp}5GET, SETEXSearch rate-limit per IPserver/controllers/inventory.js:604-611
server_status300SETEX, GETLive health JSONserver/redis/serverStatusRedis.js
server_status_stats:${key}259200 (3d)SETEX, GETHistorical stats snapshotserver/redis/serverStatusRedis.js
siteStatsCache300GET, SETEXAggregated server statsserver/service/serverStatusService.js:85-102
usercountpersistentGETActive user count writer unknown — see §14server/service/serverStatusService.js
syncItemPricesRunning3600GET, SETEX, DELSingleton lock for price sync cronserver/controllers/cron.js:822-834
revert_trades_sync_${gameId}_lastIdpersistentGET, SETCron resume-cursorserver/controllers/cron.js:1529-1587
inventory_sync_${gameId}_lastScanIdpersistentGET, SETCron resume-cursorserver/controllers/cron.js:1754-1786

6.7 SEO & insights

KeyTTLOpsPurpose
seo_page_content:/${locale}${uri}600SET, GETSEO page metadata cache
seo_gift_content:${appId}:${giftId}persistentSET, GETGift page SEO metadata
writestuff_published_urispersistent (set)SADD, SMEMBERS, SISMEMBER, DELSet of published URIs
insight_chart:${gameId}:${slug}86400SETEX, GETChart data
insight_cat:${gameId}86400SETEX, GETCategory overview
insight_cat_slug:${gameId}:${key}86400SETEX, GETCategory-specific data
insight_col:${gameId}86400SETEX, GETCollection insights
insight_items_in_container:${gameId}:${containerId}86400SETEX, GETContainer item listings
insight_container:${gameId}:${containerId}86400SETEX, GETContainer metadata
insight_item_stock:${gameId}:${itemId}:${context}600SETEX, GETItem availability
insight_ai_content:${locale}:${slug}31536000 (configurable, default 365d)SETEX, GETAI-generated SEO summary; configurable via wikiAiContentTtlInDay
aiGenerating:insight_ai_content:${locale}:${slug}600SETEXGeneration lock
insight_keys:${gameId}86400SADD, SMEMBERSSet of all insight keys per game
insightInvalidateKeysvariableSADD, SMEMBERS, DELPending-invalidation set, swept by daily cron at 01:00 UTC

6.8 Admin operations

KeyTTLOpsPurpose
admin_balance_cachepersistentSET, GETSum of admin balances
admin_delete_reserved_items:${appId}:${assetId}persistentSET, GET, DELTrack admin removal of reserved items

6.9 Locks (cross-cutting pattern)

Lock keyHolderTTLPattern
lockTrade:${assetId}tradeit-backend trade flow900sSET NX EX 900 then DEL on completion
indexLaneLock:${gameId}:${laneKey}tradeit-inventory-parser~60s, renewed at 50%SET NX EX + Lua-EVAL CAS DEL on release
updateItemsStockstradeit-stock-manager300s@LockWithRedis decorator
syncItemPricesRunningtradeit-backend cron3600sSETEX → DEL on success/failure
aiGenerating:insight_ai_content:*insightRedis AI generator600sSETEX → DEL

6.10 Bull keyspace

Bull stores its job state under the bull:<queueName>:* prefix automatically. Keys observed: id, wait, active, completed, failed, delayed, paused, priority, jobs:<id>, events, meta. No application code touches these directly; manage exclusively via the Bull API.

7. MySQL coupling

Redis keys most tightly coupled to MySQL:

Redis keyMySQL sourceRead pathInvalidation
configuration:*steamarbitrage.configurationsL1 → L2 → MySQLPer-key DEL on backend; no DEL on admin edits
configurationCategory:*:*steamarbitrage.configurationsL2 → MySQLTTL only (180s)
caskets730:*steamarbitrage.bot_casketsRedis → MySQL fallbackManual DEL on bot inventory change
stripe_customer_id:*steamarbitrage.users.stripe_customer_idRedis → MySQL fallbackPersistent — re-set on user create
revert_trades_sync_*_lastIdcron resume cursorRedis onlyRead-modify-write each cycle

Redis is always cache or coordination, never the source of truth, except for ephemeral state (locks, rate limits, pub/sub-driven flows).

8. OpenSearch coupling

Redis indirectly affects OpenSearch through the reservation flow:

No direct Redis ↔ OpenSearch sync. OpenSearch indexes are rebuilt from MySQL and Redis is consulted as an overlay during query construction.

9. Bull queues / cron / pub-sub continuations

9.1 Bull queues

QueueRepoRedis URITasksRemoval
tradeitQueuetradeit-backend${TRADEIT_REDIS_URI}:6379tradeBonus, logSold, tradedAssetIds, logWithdraw, removeReserve, instantSellCompletedunset
tradeitScreenshotQueuetradeit-backend${TI_SCREENSHOT_SKIN_REDIS_URI}:6379downloadunset
tradebotQueue:${i} (per-bot)tradeit-tradebot-server${TRADEIT_REDIS_URI}:6379deleteContainerItem, checkRevertTrade, inspectunset

Init guard (mainQueue + screenshotQueue): if (process.env.TI_ENV !== 'production' && Number(process.env.ENABLE_QUEUE) !== 1) return — production always enabled; non-prod is opt-in via ENABLE_QUEUE=1.

⚠️ No retention configured. Neither queue sets removeOnComplete, removeOnFail, attempts, or backoff. Failed jobs accumulate and require manual cleanup. Bull keyspace memory growth is monitored only via the ElastiCache memory alarm.

9.2 Cron handoffs that mutate Redis

CronScheduleRedis effectFile
Insight invalidation sweep0 1 * * * (01:00 UTC)DEL all insight_* keys not refreshed by current cronserver/redis/insightRedis.js
Price syncfrequentAcquires syncItemPricesRunning lock; releases on completionserver/controllers/cron.js:822-834
Revert-trades syncper-gameReads/writes revert_trades_sync_${gameId}_lastIdserver/controllers/cron.js:1529-1587
Inventory syncper-gameReads/writes inventory_sync_${gameId}_lastScanIdserver/controllers/cron.js:1754-1786
Stats-manager config refreshevery 5 minOverwrites configuration:* (no TTL set)tradeit-stats-manager/src/admin-config/admin-config.service.ts

9.3 Pub/sub channels (the coordination spine)

ChannelPublisherPayloadSubscribers
tradestateserver/redis/tradeRedis.js:51 + tradebot-serverJSON {steamId, token, state, msg, extra?}tradeit-socket-server src/socket.ts:61 → Socket.IO tradestate event scoped to steamId room
bot ${botId}server/redis/tradeRedis.js:117, 121; checkSteamGuardRedis.js:21Text protocol — withdraw <botId> <steamId>_<tradeHash> tradeData:<json> / sale ... / checkSteamGuard ...bot daemon worker subscribed to its own bot-id channel
itemReservedserver/redis/reserveAssetRedis.js:12; server/queue/mainQueue.js:142empty stringtradeit-socket-server src/socket.ts:65 → Socket.IO reserve-items (throttled ~1/sec)
imageserver/controllers/internal.js:154JSON image metadatainternal listener (image-processing worker)
canceledtradestradebot-server src/index.ts:1622steamIdtradeit-socket-server src/socket.ts:57
finishedtradestradebot-server src/index.ts:1204trade keyunconfirmed live consumer
steamDowntradebot-server src/index.ts:3239timestampunconfirmed live consumer

10. Configuration flags & guards

FlagWherePurpose
TRADEIT_REDIS_URIenv (all repos)Primary Redis host
TI_SCREENSHOT_SKIN_REDIS_URIenv (tradeit-backend)Separate Redis for screenshot Bull queue
TI_ENVenv (all repos)production enables queue init unconditionally
ENABLE_QUEUEenv (tradeit-backend)Non-prod opt-in (1 = enable) for Bull queues
tradeDisabledconfigurations.tradeDisabled (Redis-cached)Global trade kill switch on every trade attempt
wikiAiContentTtlInDayconfigurations rowConfigurable TTL for insight_ai_content:* (default 365d)
numBotsconfigurations.numBotsBot fleet size — drives MGET length for invsizeAll730:*, stayingalive:*, containers:*
(no flag)There is no graceful-degradation flag to run tradeit-backend without Redis. attachRedis fails the request with HTTP 500.

11. Failure modes & runbook

FailureDetectionBlast radiusRecovery
ElastiCache primary failoverdd-trace redis.call errors spike; attachRedis returns HTTP 500All HTTP requests fail until reconnectAuto-reconnect via redis v4 default; PM2 process does not auto-restart
Stale config after admin editFrontend continues showing old value up to 180s (per-key) or 360s worst-caseTrade-flag toggles, anomaly limits, pricing flagsManual: edit again, or redis.del('configuration:<key>')
Bull queue backlogbull:tradeitQueue:wait length growinglogSold, logWithdraw delayed → MySQL audit lagAdd workers; inspect failed jobs (no auto-removal)
lockTrade:* orphanLock stuck after worker crashAsset unreversible from cinv/sinv for up to 900sWait for TTL, or DEL lock manually
reserved-assets_* list overflowLLEN grows unbounded if removeReserve jobs failInventory parser pre-swap hydration slows; data-node CPU climbsOS-field redesign replaces this; transitional fix is manual LREM/LTRIM
KEYS command leakHard rule violationSite-wide latencyGUARANTEED ABSENT — verified via rg, see §13
Connection stormMany PM2 + Bull instances reconnecting after a transient failureRedis client connection limit hitStagger PM2 restarts; consider connection pooling for Bull
connect-redis session driftSession-store connection desyncsUsers get logged out / sessions orphanedRestart backend; sessions are 30d

12. Observability

⚠️ Observability gap: no automated monitoring of pub/sub channel publish rate, Bull failed-job count, or per-namespace TTL/eviction. Phase-2 follow-up: wire into Datadog dashboards.

13. Code map (file:line)

13.1 Connection lifecycle

ConcernPath
Singleton client + middlewaretradeit-backend/server/redis.js:1-64
Session-store connection bootstraptradeit-backend/server/index.js:73-90
Subscriber connection (socket-server)tradeit-socket-server/src/socket.ts:55-66

13.2 Helpers (tradeit-backend/server/redis/)

HelperOwns namespace
botAccountRedis.js:4-12bot_acc_info:*
categoryRedis.js:5-13skins_count:*
checkSteamGuardRedis.js:1-50 (publish at L21)steamGuard*; channel bot <botId>
inventoryRedis.js:1-50cinv:*, sinv:*, globalItemInfo, hardInventoryRefresh:*
reserveAssetRedis.js:5-39 (publish L12)reserved-assets_*, reserved-assets_ttl_*; channel itemReserved
tradeRedis.js:1-191 (publish L51, L117, L121)lockTrade:*, userOpenTrades:*, userTradeLock:*, tradeDisabled; channels tradestate, bot <botId>
seoPageContentRedis.js:1-40seo_page_content:*, writestuff_published_uris
seoGiftContentRedis.js:1-15seo_gift_content:*
serverStatusRedis.js:1-45server_status, server_status_stats:*
steamTradeVerificationRedis.js:1-30steam_trade_verification*
stripeRedis.js:1-20stripe_customer_id:*
insightRedis.js:1-200insight_*
admin/adminBalanceRedis.jsadmin_balance_cache
admin/adminDeleteReservedItemRedis.jsadmin_delete_reserved_items:*

13.3 Service / controller / queue / repo touch-points

FileRole
server/service/configurationService.js:19-62L1+L2 cache for configuration:*
server/service/marketplaceConfigService.js:29-107Marketplace settings cache
server/service/userService.js:238-245steamLevel:* cache
server/service/serverStatusService.js:85-102siteStatsCache, usercount
server/service/botsService.js:166+MGET fan-out across bot fleet
server/service/oauth2/oath2WebHookService.js:28-34OAuth2 client cache
server/service/couponService.js:348-353Coupon rate-limit
server/controllers/cron.js:822-834, 1529-1587, 1754-1786Cron locks + resume cursors
server/controllers/user.js:672-682stripeCountryIds cache
server/controllers/internal.js:154image channel publisher
server/controllers/inventory.js:604-611Search rate-limit
server/controllers/steam.js:23Login key DEL
server/queue/mainQueue.js:1-194tradeitQueue definition
server/queue/screenshotQueue.js:1-101tradeitScreenshotQueue definition
server/repository/containerItemsRepo.jscaskets730:* reads

13.4 Cross-repo

RepoPathSurface
tradeit-socket-serversrc/socket.ts:57, 61, 65Subscribers for canceledtrades, tradestate, itemReserved
tradeit-tradebot-serversrc/index.ts:218, 257-258, 308, 340, 367, 505, 585, 838+, 1204, 1622, 2559, 2893-2898, 3239, 3849All bot-state KV + pub/sub publishers
tradeit-admin-backendsrc/services/configurationService.ts:50-71configuration:* writes (no DEL on admin edit)
tradeit-stats-managersrc/admin-config/admin-config.service.ts:20-25configuration:* overwrites every 5 min, no TTL
tradeit-stock-managersrc/app.service.ts:17, src/common/redis/redis.decorator.ts:8updateItemsStocks lock
tradeit-buff-scrappersrc/common/redis.service.tsGeneric lock wrapper
tradeit-oauth2-serversrc/guards/login.guard.ts:52-59login:* writes; sess:* via connect-redis
tradeit-inventory-parsersrc/modules/inventoryIndex/inventory.controller.ts:200-230indexLaneLock:* Lua-EVAL CAS DEL

14. Open questions & known gaps


Related deep-dives: Platform Configuration · OpenSearch Patterns · Trade Lifecycle