OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      62d7523d49e4
DATE      2025-09-22
SUBJECT   web/nix: support tw realms
FILES     13 CHANGED
HASH      62d7523d49e4
DATE      2025-09-22
SUBJECT   web/nix: support tw realms
FILES     13 CHANGED
 

diff --git a/nix/apps/default.nix b/nix/apps/default.nix
index bc0662a..a8affa5 100644
--- a/nix/apps/default.nix
+++ b/nix/apps/default.nix
@@ -39,6 +39,7 @@
     rankingProcessor = import ./challenge-mode/ranking-processor.nix {inherit wri
ters python3Packages;};
     # analyze periods across all dungeons to find optimal API strategy
     periodAnalyzer = import ./utils/period-analyzer.nix {inherit writers python3P
ackages;};
+    multiPeriodAnalyzer = import ./utils/multi-period-analyzer.nix {inherit api w
riters python3Packages;};
     # convert simulation data to apps
 
     # DEPRECATED SCRIPTS
@@ -113,6 +114,10 @@
           type = "app";
           program = "${periodAnalyzer}/bin/period-analyzer";
         };
+        multiPeriodAnalyzer = {
+          type = "app";
+          program = "${multiPeriodAnalyzer}/bin/multi-period-analyzer";
+        };
         wowstats-db = {
           type = "app";
           program = "${wowsimstats-cli}/bin/wowstats-db";

diff --git a/nix/apps/default.nix b/nix/apps
/default.nix
index bc0662a..a8affa5 100644
--- a/nix/apps/default.nix
+++ b/nix/apps/default.nix
@@ -39,6 +39,7 @@
     rankingProcessor = import ./challenge-m
ode/ranking-processor.nix {inherit writers p
ython3Packages;};
     # analyze periods across all dungeons t
o find optimal API strategy
     periodAnalyzer = import ./utils/period-
analyzer.nix {inherit writers python3Package
s;};
+    multiPeriodAnalyzer = import ./utils/mu
lti-period-analyzer.nix {inherit api writers
 python3Packages;};
     # convert simulation data to apps
 
     # DEPRECATED SCRIPTS
@@ -113,6 +114,10 @@
           type = "app";
           program = "${periodAnalyzer}/bin/
period-analyzer";
         };
+        multiPeriodAnalyzer = {
+          type = "app";
+          program = "${multiPeriodAnalyzer}
/bin/multi-period-analyzer";
+        };
         wowstats-db = {
           type = "app";
           program = "${wowsimstats-cli}/bin
/wowstats-db";
 

diff --git a/nix/apps/utils/multi-period-analyzer.nix b/nix/apps/utils/multi-perio
d-analyzer.nix
new file mode 100644
index 0000000..eb5986a
--- /dev/null
+++ b/nix/apps/utils/multi-period-analyzer.nix
@@ -0,0 +1,365 @@
+{
+  writers,
+  python3Packages,
+  api,
+  ...
+}: let
+  inherit (api) realm;
+
+  multiPeriodAnalyzerScript =
+    writers.writePython3Bin "multi-period-analyzer" {
+      libraries = [python3Packages.aiohttp];
+      doCheck = false;
+    }
+    ''
+      import os
+      import aiohttp
+      import asyncio
+      import json
+      import sys
+      import time
+      from collections import defaultdict
+      import csv
+
+      # All Challenge Mode dungeons (from constants.go)
+      DUNGEONS = [
+          {"id": 2, "name": "Temple of the Jade Serpent", "slug": "temple-of-the-
jade-serpent"},
+          {"id": 56, "name": "Stormstout Brewery", "slug": "stormstout-brewery"},
+          {"id": 57, "name": "Gate of the Setting Sun", "slug": "gate-of-the-sett
ing-sun"},
+          {"id": 58, "name": "Shado-Pan Monastery", "slug": "shado-pan-monastery"
},
+          {"id": 59, "name": "Siege of Niuzao Temple", "slug": "siege-of-niuzao-t
emple"},
+          {"id": 60, "name": "Mogu'shan Palace", "slug": "mogu-shan-palace"},
+          {"id": 76, "name": "Scholomance", "slug": "scholomance"},
+          {"id": 77, "name": "Scarlet Halls", "slug": "scarlet-halls"},
+          {"id": 78, "name": "Scarlet Monastery", "slug": "scarlet-monastery"},
+      ]
+
+      # All realms (from constants.go and nix/api/realm.nix)
+      REALMS = [
+          # US Realms
+          {"id": 4372, "region": "us", "name": "Atiesh", "slug": "atiesh"},
+          {"id": 4373, "region": "us", "name": "Myzrael", "slug": "myzrael"},
+          {"id": 4374, "region": "us", "name": "Old Blanchy", "slug": "old-blanch
y"},
+          {"id": 4376, "region": "us", "name": "Azuresong", "slug": "azuresong"},
+          {"id": 4384, "region": "us", "name": "Mankrik", "slug": "mankrik"},
+          {"id": 4385, "region": "us", "name": "Pagle", "slug": "pagle"},
+          {"id": 4387, "region": "us", "name": "Ashkandi", "slug": "ashkandi"},
+          {"id": 4388, "region": "us", "name": "Westfall", "slug": "westfall"},
+          {"id": 4395, "region": "us", "name": "Whitemane", "slug": "whitemane"},
+          {"id": 4408, "region": "us", "name": "Faerlina", "slug": "faerlina"},
+          {"id": 4647, "region": "us", "name": "Grobbulus", "slug": "grobbulus"},
+          {"id": 4648, "region": "us", "name": "Bloodsail Buccaneers", "slug": "b
loodsail-buccaneers"},
+          {"id": 4667, "region": "us", "name": "Remulos", "slug": "remulos"},
+          {"id": 4669, "region": "us", "name": "Arugal", "slug": "arugal"},
+          {"id": 4670, "region": "us", "name": "Yojamba", "slug": "yojamba"},
+          {"id": 4725, "region": "us", "name": "Skyfury", "slug": "skyfury"},
+          {"id": 4726, "region": "us", "name": "Sulfuras", "slug": "sulfuras"},
+          {"id": 4727, "region": "us", "name": "Windseeker", "slug": "windseeker"
},
+          {"id": 4728, "region": "us", "name": "Benediction", "slug": "benedictio
n"},
+          {"id": 4731, "region": "us", "name": "Earthfury", "slug": "earthfury"},
+          {"id": 4738, "region": "us", "name": "Maladath", "slug": "maladath"},
+          {"id": 4795, "region": "us", "name": "Angerforge", "slug": "angerforge"
},
+          {"id": 4800, "region": "us", "name": "Eranikus", "slug": "eranikus"},
+
+          # EU Realms
+          {"id": 4440, "region": "eu", "name": "Everlook", "slug": "everlook"},
+          {"id": 4441, "region": "eu", "name": "Auberdine", "slug": "auberdine"},
+          {"id": 4442, "region": "eu", "name": "Lakeshire", "slug": "lakeshire"},
+          {"id": 4452, "region": "eu", "name": "Chromie", "slug": "chromie"},
+          {"id": 4453, "region": "eu", "name": "Pyrewood Village", "slug": "pyrew
ood-village"},
+          {"id": 4454, "region": "eu", "name": "Mirage Raceway", "slug": "mirage-
raceway"},
+          {"id": 4455, "region": "eu", "name": "Razorfen", "slug": "razorfen"},
+          {"id": 4456, "region": "eu", "name": "Nethergarde Keep", "slug": "nethe
rgarde-keep"},
+          {"id": 4464, "region": "eu", "name": "Sulfuron", "slug": "sulfuron"},
+          {"id": 4465, "region": "eu", "name": "Golemagg", "slug": "golemagg"},
+          {"id": 4466, "region": "eu", "name": "Patchwerk", "slug": "patchwerk"},
+          {"id": 4467, "region": "eu", "name": "Firemaw", "slug": "firemaw"},
+          {"id": 4474, "region": "eu", "name": "Flamegor", "slug": "flamegor"},
+          {"id": 4476, "region": "eu", "name": "Gehennas", "slug": "gehennas"},
+          {"id": 4477, "region": "eu", "name": "Venoxis", "slug": "venoxis"},
+          {"id": 4678, "region": "eu", "name": "Hydraxian Waterlords", "slug": "h
ydraxian-waterlords"},
+          {"id": 4701, "region": "eu", "name": "Mograine", "slug": "mograine"},
+          {"id": 4703, "region": "eu", "name": "Amnennar", "slug": "amnennar"},
+          {"id": 4742, "region": "eu", "name": "Ashbringer", "slug": "ashbringer"
},
+          {"id": 4745, "region": "eu", "name": "Transcendence", "slug": "transcen
dence"},
+          {"id": 4749, "region": "eu", "name": "Earthshaker", "slug": "earthshake
r"},
+          {"id": 4811, "region": "eu", "name": "Giantstalker", "slug": "giantstal
ker"},
+          {"id": 4813, "region": "eu", "name": "Mandokir", "slug": "mandokir"},
+          {"id": 4815, "region": "eu", "name": "Thekal", "slug": "thekal"},
+          {"id": 4816, "region": "eu", "name": "Jin'do", "slug": "jindo"},
+
+          # KR Realms
+          {"id": 4417, "region": "kr", "name": "Shimmering Flats", "slug": "shimm
ering-flats"},
+          {"id": 4419, "region": "kr", "name": "Lokholar", "slug": "lokholar"},
+          {"id": 4420, "region": "kr", "name": "Iceblood", "slug": "iceblood"},
+          {"id": 4421, "region": "kr", "name": "Ragnaros", "slug": "ragnaros"},
+          {"id": 4840, "region": "kr", "name": "Frostmourne", "slug": "frostmourn
e"},
+      ]
+
+      API_TOKEN = os.getenv("BLIZZARD_API_TOKEN")
+      PERIOD_RANGE = range(1026, 1030)  # Test periods 1026-1028
+      MAX_CONCURRENT = 50  # Reduced concurrency for comprehensive testing
+      BATCH_SIZE = 50
+
+      async def test_realm_dungeon_period(session, semaphore, realm, dungeon, per
iod_id):
+          """Test a specific realm/dungeon/period combination asynchronously"""
+          async with semaphore:
+              region = realm["region"]
+              realm_id = realm["id"]
+              dungeon_id = dungeon["id"]
+              namespace = f"dynamic-classic-{region}"
+
+              url = (
+                  f"https://{region}.api.blizzard.com/data/wow/connected-realm/"
+                  f"{realm_id}/mythic-leaderboard/{dungeon_id}/period/"
+                  f"{period_id}?namespace={namespace}"
+              )
+
+              try:
+                  async with session.get(url, timeout=10) as response:
+                      result = {
+                          "realm_name": realm["name"],
+                          "realm_slug": realm["slug"],
+                          "realm_id": realm_id,
+                          "region": region,
+                          "dungeon_name": dungeon["name"],
+                          "dungeon_slug": dungeon["slug"],
+                          "dungeon_id": dungeon_id,
+                          "period_id": period_id,
+                          "status_code": response.status,
+                          "url": url
+                      }
+
+                      if response.status == 404:
+                          result["success"] = False
+                          result["error"] = "No data (404)"
+                          return result
+
+                      if response.status != 200:
+                          result["success"] = False
+                          result["error"] = f"HTTP {response.status}"
+                          return result
+
+                      data = await response.json()
+                      leading_groups = data.get("leading_groups", [])
+
+                      result["success"] = True
+                      result["run_count"] = len(leading_groups)
+                      result["has_runs"] = len(leading_groups) > 0
+
+                      if leading_groups:
+                          result["best_time"] = min(run.get("duration", float("in
f")) for run in leading_groups)
+                          result["most_recent"] = max(run.get("completed_timestam
p", 0) for run in leading_groups)
+
+                      return result
+
+              except Exception as e:
+                  return {
+                      "realm_name": realm["name"],
+                      "realm_slug": realm["slug"],
+                      "realm_id": realm_id,
+                      "region": region,
+                      "dungeon_name": dungeon["name"],
+                      "dungeon_slug": dungeon["slug"],
+                      "dungeon_id": dungeon_id,
+                      "period_id": period_id,
+                      "status_code": None,
+                      "url": url,
+                      "success": False,
+                      "error": str(e)
+                  }
+
+      async def main():
+          if not API_TOKEN:
+              print("FATAL: BLIZZARD_API_TOKEN environment variable not set.")
+              sys.exit(1)
+
+          print("=== WoW Challenge Mode Multi-Period Analyzer ===")
+          print(f"Testing {len(REALMS)} realms across {len(DUNGEONS)} dungeons")
+          print(f"Testing periods: {PERIOD_RANGE.start} to {PERIOD_RANGE.stop - 1
}")
+          print(f"Max concurrent requests: {MAX_CONCURRENT}")
+          print()
+
+          # Create all request combinations
+          all_requests = []
+          for realm in REALMS:
+              for dungeon in DUNGEONS:
+                  for period_id in PERIOD_RANGE:
+                      all_requests.append((realm, dungeon, period_id))
+
+          total_tests = len(all_requests)
+          print(f"Total API endpoint tests: {total_tests}")
+          print(f"({len(REALMS)} realms ? {len(DUNGEONS)} dungeons ? {len(PERIOD_
RANGE)} periods)")
+          print()
+
+          # Store all results for analysis
+          all_results = []
+          failed_results = []
+          successful_results = []
+
+          # Create semaphore to limit concurrent requests
+          semaphore = asyncio.Semaphore(MAX_CONCURRENT)
+
+          # Setup async HTTP session
+          timeout = aiohttp.ClientTimeout(total=15)
+          headers = {"Authorization": f"Bearer {API_TOKEN}"}
+
+          async with aiohttp.ClientSession(timeout=timeout, headers=headers) as s
ession:
+              print("Starting comprehensive API endpoint testing...")
+              start_time = time.time()
+
+              # Process in batches
+              completed_count = 0
+              for batch_idx in range(0, len(all_requests), BATCH_SIZE):
+                  batch = all_requests[batch_idx:batch_idx + BATCH_SIZE]
+                  batch_num = batch_idx // BATCH_SIZE + 1
+                  total_batches = (len(all_requests) + BATCH_SIZE - 1) // BATCH_S
IZE
+
+                  print(f"Processing batch {batch_num}/{total_batches} ({len(batc
h)} requests)")
+
+                  # Create tasks for this batch
+                  tasks = []
+                  for realm, dungeon, period_id in batch:
+                      task = test_realm_dungeon_period(session, semaphore, realm,
 dungeon, period_id)
+                      tasks.append(task)
+
+                  # Execute batch
+                  batch_results = await asyncio.gather(*tasks, return_exceptions=
True)
+
+                  # Process results
+                  for result in batch_results:
+                      completed_count += 1
+                      if result and not isinstance(result, Exception):
+                          all_results.append(result)
+                          if result["success"]:
+                              successful_results.append(result)
+                          else:
+                              failed_results.append(result)
+                      elif isinstance(result, Exception):
+                          print(f"    Unexpected error in batch: {result}")
+
+                  # Progress update
+                  elapsed = time.time() - start_time
+                  progress = (completed_count / total_tests) * 100
+                  rate = completed_count / elapsed if elapsed > 0 else 0
+                  print(f"  Batch complete: {progress:.1f}% total ({completed_cou
nt}/{total_tests}) - {rate:.1f} req/s avg")
+                  print(f"  Success: {len(successful_results)}, Failed: {len(fail
ed_results)}")
+
+                  # Sleep between batches to be API-friendly
+                  if batch_idx + BATCH_SIZE < len(all_requests):
+                      await asyncio.sleep(2.0)
+
+              elapsed = time.time() - start_time
+              print(f"\\nCompleted all {total_tests} requests in {elapsed:.1f}s (
{total_tests/elapsed:.1f} req/s avg)")
+
+          # Generate comprehensive report
+          print(f"\n=== COMPREHENSIVE API ENDPOINT ANALYSIS ===")
+          print(f"Total endpoints tested: {len(all_results)}")
+          print(f"Successful endpoints: {len(successful_results)} ({len(successfu
l_results)/len(all_results)*100:.1f}%)")
+          print(f"Failed endpoints: {len(failed_results)} ({len(failed_results)/l
en(all_results)*100:.1f}%)")
+
+          # Analyze failure patterns
+          if failed_results:
+              print(f"\n=== BROKEN ENDPOINT ANALYSIS ===")
+
+              # Group by error type
+              error_types = defaultdict(int)
+              for result in failed_results:
+                  error_types[result["error"]] += 1
+
+              print("Failure breakdown by error type:")
+              for error, count in sorted(error_types.items(), key=lambda x: x[1],
 reverse=True):
+                  print(f"  {error}: {count} endpoints")
+
+              # Group by realm
+              realm_failures = defaultdict(int)
+              for result in failed_results:
+                  realm_failures[f"{result['realm_name']} ({result['region'].uppe
r()})"] += 1
+
+              print(f"\nTop 10 realms with most failures:")
+              for realm, count in sorted(realm_failures.items(), key=lambda x: x[
1], reverse=True)[:10]:
+                  print(f"  {realm}: {count} failed endpoints")
+
+              # Group by dungeon
+              dungeon_failures = defaultdict(int)
+              for result in failed_results:
+                  dungeon_failures[result["dungeon_name"]] += 1
+
+              print(f"\nDungeons with most failures:")
+              for dungeon, count in sorted(dungeon_failures.items(), key=lambda x
: x[1], reverse=True):
+                  print(f"  {dungeon}: {count} failed endpoints")
+
+              # Group by period
+              period_failures = defaultdict(int)
+              for result in failed_results:
+                  period_failures[result["period_id"]] += 1
+
+              print(f"\nPeriods with most failures:")
+              for period, count in sorted(period_failures.items(), key=lambda x: 
x[1], reverse=True):
+                  print(f"  Period {period}: {count} failed endpoints")
+
+              # Focus on realm/dungeon combinations with no data across all perio
ds
+              print(f"\n=== REALM/DUNGEON COMBINATIONS WITH NO DATA ===")
+
+              # Group failed results by realm+dungeon combination
+              realm_dungeon_failures = defaultdict(set)  # key: (realm_slug, dung
eon_slug), value: set of failed periods
+
+              for result in failed_results:
+                  key = (result["realm_slug"], result["dungeon_slug"])
+                  realm_dungeon_failures[key].add(result["period_id"])
+
+              # Find combinations that failed across ALL tested periods
+              all_periods = set(PERIOD_RANGE)
+              completely_broken = []
+              partially_broken = []
+
+              for (realm_slug, dungeon_slug), failed_periods in realm_dungeon_fai
lures.items():
+                  if failed_periods == all_periods:
+                      # Failed in ALL periods
+                      completely_broken.append((realm_slug, dungeon_slug))
+                  else:
+                      # Failed in some periods
+                      partially_broken.append((realm_slug, dungeon_slug, failed_p
eriods))
+
+              print(f"\nCompletely broken realm/dungeon combinations (no data in 
ANY period {min(PERIOD_RANGE)}-{max(PERIOD_RANGE)}):")
+              if completely_broken:
+                  for i, (realm_slug, dungeon_slug) in enumerate(sorted(completel
y_broken), 1):
+                      # Find region for this realm
+                      realm_info = next((r for r in REALMS if r["slug"] == realm_
slug), None)
+                      region = realm_info["region"].upper() if realm_info else "?
?"
+                      print(f"  {i:2d}. {realm_slug} ({region}) + {dungeon_slug}"
)
+              else:
+                  print("  None! All realm/dungeon combinations have data in at l
east one period.")
+
+              print(f"\nPartially broken realm/dungeon combinations:")
+              if partially_broken:
+                  for i, (realm_slug, dungeon_slug, failed_periods) in enumerate(
sorted(partially_broken), 1):
+                      # Find region for this realm
+                      realm_info = next((r for r in REALMS if r["slug"] == realm_
slug), None)
+                      region = realm_info["region"].upper() if realm_info else "?
?"
+                      working_periods = all_periods - failed_periods
+                      print(f"  {i:2d}. {realm_slug} ({region}) + {dungeon_slug}"
)
+                      print(f"      Missing data in periods: {sorted(failed_perio
ds)}")
+                      print(f"      Has data in periods: {sorted(working_periods)
}")
+              else:
+                  print("  None! All realm/dungeon combinations work in all perio
ds.")
+
+          else:
+              print("\\nAll endpoints are working! ?")
+
+          # Summary of known problematic cases
+          print(f"\n=== SPECIFIC PROBLEMATIC CASES ===")
+          gehennas_mogushan = [r for r in failed_results if r["realm_slug"] == "g
ehennas" and r["dungeon_slug"] == "mogu-shan-palace"]
+          if gehennas_mogushan:
+              print(f"Gehennas + Mogu'shan Palace failures: {len(gehennas_mogusha
n)}")
+              for result in gehennas_mogushan:
+                  print(f"  Period {result['period_id']}: {result['error']}")
+          else:
+              print("Gehennas + Mogu'shan Palace: All working!")
+
+      if __name__ == "__main__":
+          asyncio.run(main())
+    '';
+in
+  multiPeriodAnalyzerScript
+

diff --git a/nix/apps/utils/multi-period-ana
lyzer.nix b/nix/apps/utils/multi-period-anal
yzer.nix
new file mode 100644
index 0000000..eb5986a
--- /dev/null
+++ b/nix/apps/utils/multi-period-analyzer.n
ix
@@ -0,0 +1,365 @@
+{
+  writers,
+  python3Packages,
+  api,
+  ...
+}: let
+  inherit (api) realm;
+
+  multiPeriodAnalyzerScript =
+    writers.writePython3Bin "multi-period-a
nalyzer" {
+      libraries = [python3Packages.aiohttp]
;
+      doCheck = false;
+    }
+    ''
+      import os
+      import aiohttp
+      import asyncio
+      import json
+      import sys
+      import time
+      from collections import defaultdict
+      import csv
+
+      # All Challenge Mode dungeons (from c
onstants.go)
+      DUNGEONS = [
+          {"id": 2, "name": "Temple of the 
Jade Serpent", "slug": "temple-of-the-jade-s
erpent"},
+          {"id": 56, "name": "Stormstout Br
ewery", "slug": "stormstout-brewery"},
+          {"id": 57, "name": "Gate of the S
etting Sun", "slug": "gate-of-the-setting-su
n"},
+          {"id": 58, "name": "Shado-Pan Mon
astery", "slug": "shado-pan-monastery"},
+          {"id": 59, "name": "Siege of Niuz
ao Temple", "slug": "siege-of-niuzao-temple"
},
+          {"id": 60, "name": "Mogu'shan Pal
ace", "slug": "mogu-shan-palace"},
+          {"id": 76, "name": "Scholomance",
 "slug": "scholomance"},
+          {"id": 77, "name": "Scarlet Halls
", "slug": "scarlet-halls"},
+          {"id": 78, "name": "Scarlet Monas
tery", "slug": "scarlet-monastery"},
+      ]
+
+      # All realms (from constants.go and n
ix/api/realm.nix)
+      REALMS = [
+          # US Realms
+          {"id": 4372, "region": "us", "nam
e": "Atiesh", "slug": "atiesh"},
+          {"id": 4373, "region": "us", "nam
e": "Myzrael", "slug": "myzrael"},
+          {"id": 4374, "region": "us", "nam
e": "Old Blanchy", "slug": "old-blanchy"},
+          {"id": 4376, "region": "us", "nam
e": "Azuresong", "slug": "azuresong"},
+          {"id": 4384, "region": "us", "nam
e": "Mankrik", "slug": "mankrik"},
+          {"id": 4385, "region": "us", "nam
e": "Pagle", "slug": "pagle"},
+          {"id": 4387, "region": "us", "nam
e": "Ashkandi", "slug": "ashkandi"},
+          {"id": 4388, "region": "us", "nam
e": "Westfall", "slug": "westfall"},
+          {"id": 4395, "region": "us", "nam
e": "Whitemane", "slug": "whitemane"},
+          {"id": 4408, "region": "us", "nam
e": "Faerlina", "slug": "faerlina"},
+          {"id": 4647, "region": "us", "nam
e": "Grobbulus", "slug": "grobbulus"},
+          {"id": 4648, "region": "us", "nam
e": "Bloodsail Buccaneers", "slug": "bloodsa
il-buccaneers"},
+          {"id": 4667, "region": "us", "nam
e": "Remulos", "slug": "remulos"},
+          {"id": 4669, "region": "us", "nam
e": "Arugal", "slug": "arugal"},
+          {"id": 4670, "region": "us", "nam
e": "Yojamba", "slug": "yojamba"},
+          {"id": 4725, "region": "us", "nam
e": "Skyfury", "slug": "skyfury"},
+          {"id": 4726, "region": "us", "nam
e": "Sulfuras", "slug": "sulfuras"},
+          {"id": 4727, "region": "us", "nam
e": "Windseeker", "slug": "windseeker"},
+          {"id": 4728, "region": "us", "nam
e": "Benediction", "slug": "benediction"},
+          {"id": 4731, "region": "us", "nam
e": "Earthfury", "slug": "earthfury"},
+          {"id": 4738, "region": "us", "nam
e": "Maladath", "slug": "maladath"},
+          {"id": 4795, "region": "us", "nam
e": "Angerforge", "slug": "angerforge"},
+          {"id": 4800, "region": "us", "nam
e": "Eranikus", "slug": "eranikus"},
+
+          # EU Realms
+          {"id": 4440, "region": "eu", "nam
e": "Everlook", "slug": "everlook"},
+          {"id": 4441, "region": "eu", "nam
e": "Auberdine", "slug": "auberdine"},
+          {"id": 4442, "region": "eu", "nam
e": "Lakeshire", "slug": "lakeshire"},
+          {"id": 4452, "region": "eu", "nam
e": "Chromie", "slug": "chromie"},
+          {"id": 4453, "region": "eu", "nam
e": "Pyrewood Village", "slug": "pyrewood-vi
llage"},
+          {"id": 4454, "region": "eu", "nam
e": "Mirage Raceway", "slug": "mirage-racewa
y"},
+          {"id": 4455, "region": "eu", "nam
e": "Razorfen", "slug": "razorfen"},
+          {"id": 4456, "region": "eu", "nam
e": "Nethergarde Keep", "slug": "nethergarde
-keep"},
+          {"id": 4464, "region": "eu", "nam
e": "Sulfuron", "slug": "sulfuron"},
+          {"id": 4465, "region": "eu", "nam
e": "Golemagg", "slug": "golemagg"},
+          {"id": 4466, "region": "eu", "nam
e": "Patchwerk", "slug": "patchwerk"},
+          {"id": 4467, "region": "eu", "nam
e": "Firemaw", "slug": "firemaw"},
+          {"id": 4474, "region": "eu", "nam
e": "Flamegor", "slug": "flamegor"},
+          {"id": 4476, "region": "eu", "nam
e": "Gehennas", "slug": "gehennas"},
+          {"id": 4477, "region": "eu", "nam
e": "Venoxis", "slug": "venoxis"},
+          {"id": 4678, "region": "eu", "nam
e": "Hydraxian Waterlords", "slug": "hydraxi
an-waterlords"},
+          {"id": 4701, "region": "eu", "nam
e": "Mograine", "slug": "mograine"},
+          {"id": 4703, "region": "eu", "nam
e": "Amnennar", "slug": "amnennar"},
+          {"id": 4742, "region": "eu", "nam
e": "Ashbringer", "slug": "ashbringer"},
+          {"id": 4745, "region": "eu", "nam
e": "Transcendence", "slug": "transcendence"
},
+          {"id": 4749, "region": "eu", "nam
e": "Earthshaker", "slug": "earthshaker"},
+          {"id": 4811, "region": "eu", "nam
e": "Giantstalker", "slug": "giantstalker"},
+          {"id": 4813, "region": "eu", "nam
e": "Mandokir", "slug": "mandokir"},
+          {"id": 4815, "region": "eu", "nam
e": "Thekal", "slug": "thekal"},
+          {"id": 4816, "region": "eu", "nam
e": "Jin'do", "slug": "jindo"},
+
+          # KR Realms
+          {"id": 4417, "region": "kr", "nam
e": "Shimmering Flats", "slug": "shimmering-
flats"},
+          {"id": 4419, "region": "kr", "nam
e": "Lokholar", "slug": "lokholar"},
+          {"id": 4420, "region": "kr", "nam
e": "Iceblood", "slug": "iceblood"},
+          {"id": 4421, "region": "kr", "nam
e": "Ragnaros", "slug": "ragnaros"},
+          {"id": 4840, "region": "kr", "nam
e": "Frostmourne", "slug": "frostmourne"},
+      ]
+
+      API_TOKEN = os.getenv("BLIZZARD_API_T
OKEN")
+      PERIOD_RANGE = range(1026, 1030)  # T
est periods 1026-1028
+      MAX_CONCURRENT = 50  # Reduced concur
rency for comprehensive testing
+      BATCH_SIZE = 50
+
+      async def test_realm_dungeon_period(s
ession, semaphore, realm, dungeon, period_id
):
+          """Test a specific realm/dungeon/
period combination asynchronously"""
+          async with semaphore:
+              region = realm["region"]
+              realm_id = realm["id"]
+              dungeon_id = dungeon["id"]
+              namespace = f"dynamic-classic
-{region}"
+
+              url = (
+                  f"https://{region}.api.bl
izzard.com/data/wow/connected-realm/"
+                  f"{realm_id}/mythic-leade
rboard/{dungeon_id}/period/"
+                  f"{period_id}?namespace={
namespace}"
+              )
+
+              try:
+                  async with session.get(ur
l, timeout=10) as response:
+                      result = {
+                          "realm_name": rea
lm["name"],
+                          "realm_slug": rea
lm["slug"],
+                          "realm_id": realm
_id,
+                          "region": region,
+                          "dungeon_name": d
ungeon["name"],
+                          "dungeon_slug": d
ungeon["slug"],
+                          "dungeon_id": dun
geon_id,
+                          "period_id": peri
od_id,
+                          "status_code": re
sponse.status,
+                          "url": url
+                      }
+
+                      if response.status ==
 404:
+                          result["success"]
 = False
+                          result["error"] =
 "No data (404)"
+                          return result
+
+                      if response.status !=
 200:
+                          result["success"]
 = False
+                          result["error"] =
 f"HTTP {response.status}"
+                          return result
+
+                      data = await response
.json()
+                      leading_groups = data
.get("leading_groups", [])
+
+                      result["success"] = T
rue
+                      result["run_count"] =
 len(leading_groups)
+                      result["has_runs"] = 
len(leading_groups) > 0
+
+                      if leading_groups:
+                          result["best_time
"] = min(run.get("duration", float("inf")) f
or run in leading_groups)
+                          result["most_rece
nt"] = max(run.get("completed_timestamp", 0)
 for run in leading_groups)
+
+                      return result
+
+              except Exception as e:
+                  return {
+                      "realm_name": realm["
name"],
+                      "realm_slug": realm["
slug"],
+                      "realm_id": realm_id,
+                      "region": region,
+                      "dungeon_name": dunge
on["name"],
+                      "dungeon_slug": dunge
on["slug"],
+                      "dungeon_id": dungeon
_id,
+                      "period_id": period_i
d,
+                      "status_code": None,
+                      "url": url,
+                      "success": False,
+                      "error": str(e)
+                  }
+
+      async def main():
+          if not API_TOKEN:
+              print("FATAL: BLIZZARD_API_TO
KEN environment variable not set.")
+              sys.exit(1)
+
+          print("=== WoW Challenge Mode Mul
ti-Period Analyzer ===")
+          print(f"Testing {len(REALMS)} rea
lms across {len(DUNGEONS)} dungeons")
+          print(f"Testing periods: {PERIOD_
RANGE.start} to {PERIOD_RANGE.stop - 1}")
+          print(f"Max concurrent requests: 
{MAX_CONCURRENT}")
+          print()
+
+          # Create all request combinations
+          all_requests = []
+          for realm in REALMS:
+              for dungeon in DUNGEONS:
+                  for period_id in PERIOD_R
ANGE:
+                      all_requests.append((
realm, dungeon, period_id))
+
+          total_tests = len(all_requests)
+          print(f"Total API endpoint tests:
 {total_tests}")
+          print(f"({len(REALMS)} realms ? {
len(DUNGEONS)} dungeons ? {len(PERIOD_RANGE)
} periods)")
+          print()
+
+          # Store all results for analysis
+          all_results = []
+          failed_results = []
+          successful_results = []
+
+          # Create semaphore to limit concu
rrent requests
+          semaphore = asyncio.Semaphore(MAX
_CONCURRENT)
+
+          # Setup async HTTP session
+          timeout = aiohttp.ClientTimeout(t
otal=15)
+          headers = {"Authorization": f"Bea
rer {API_TOKEN}"}
+
+          async with aiohttp.ClientSession(
timeout=timeout, headers=headers) as session
:
+              print("Starting comprehensive
 API endpoint testing...")
+              start_time = time.time()
+
+              # Process in batches
+              completed_count = 0
+              for batch_idx in range(0, len
(all_requests), BATCH_SIZE):
+                  batch = all_requests[batc
h_idx:batch_idx + BATCH_SIZE]
+                  batch_num = batch_idx // 
BATCH_SIZE + 1
+                  total_batches = (len(all_
requests) + BATCH_SIZE - 1) // BATCH_SIZE
+
+                  print(f"Processing batch 
{batch_num}/{total_batches} ({len(batch)} re
quests)")
+
+                  # Create tasks for this b
atch
+                  tasks = []
+                  for realm, dungeon, perio
d_id in batch:
+                      task = test_realm_dun
geon_period(session, semaphore, realm, dunge
on, period_id)
+                      tasks.append(task)
+
+                  # Execute batch
+                  batch_results = await asy
ncio.gather(*tasks, return_exceptions=True)
+
+                  # Process results
+                  for result in batch_resul
ts:
+                      completed_count += 1
+                      if result and not isi
nstance(result, Exception):
+                          all_results.appen
d(result)
+                          if result["succes
s"]:
+                              successful_re
sults.append(result)
+                          else:
+                              failed_result
s.append(result)
+                      elif isinstance(resul
t, Exception):
+                          print(f"    Unexp
ected error in batch: {result}")
+
+                  # Progress update
+                  elapsed = time.time() - s
tart_time
+                  progress = (completed_cou
nt / total_tests) * 100
+                  rate = completed_count / 
elapsed if elapsed > 0 else 0
+                  print(f"  Batch complete:
 {progress:.1f}% total ({completed_count}/{t
otal_tests}) - {rate:.1f} req/s avg")
+                  print(f"  Success: {len(s
uccessful_results)}, Failed: {len(failed_res
ults)}")
+
+                  # Sleep between batches t
o be API-friendly
+                  if batch_idx + BATCH_SIZE
 < len(all_requests):
+                      await asyncio.sleep(2
.0)
+
+              elapsed = time.time() - start
_time
+              print(f"\\nCompleted all {tot
al_tests} requests in {elapsed:.1f}s ({total
_tests/elapsed:.1f} req/s avg)")
+
+          # Generate comprehensive report
+          print(f"\n=== COMPREHENSIVE API E
NDPOINT ANALYSIS ===")
+          print(f"Total endpoints tested: {
len(all_results)}")
+          print(f"Successful endpoints: {le
n(successful_results)} ({len(successful_resu
lts)/len(all_results)*100:.1f}%)")
+          print(f"Failed endpoints: {len(fa
iled_results)} ({len(failed_results)/len(all
_results)*100:.1f}%)")
+
+          # Analyze failure patterns
+          if failed_results:
+              print(f"\n=== BROKEN ENDPOINT
 ANALYSIS ===")
+
+              # Group by error type
+              error_types = defaultdict(int
)
+              for result in failed_results:
+                  error_types[result["error
"]] += 1
+
+              print("Failure breakdown by e
rror type:")
+              for error, count in sorted(er
ror_types.items(), key=lambda x: x[1], rever
se=True):
+                  print(f"  {error}: {count
} endpoints")
+
+              # Group by realm
+              realm_failures = defaultdict(
int)
+              for result in failed_results:
+                  realm_failures[f"{result[
'realm_name']} ({result['region'].upper()})"
] += 1
+
+              print(f"\nTop 10 realms with 
most failures:")
+              for realm, count in sorted(re
alm_failures.items(), key=lambda x: x[1], re
verse=True)[:10]:
+                  print(f"  {realm}: {count
} failed endpoints")
+
+              # Group by dungeon
+              dungeon_failures = defaultdic
t(int)
+              for result in failed_results:
+                  dungeon_failures[result["
dungeon_name"]] += 1
+
+              print(f"\nDungeons with most 
failures:")
+              for dungeon, count in sorted(
dungeon_failures.items(), key=lambda x: x[1]
, reverse=True):
+                  print(f"  {dungeon}: {cou
nt} failed endpoints")
+
+              # Group by period
+              period_failures = defaultdict
(int)
+              for result in failed_results:
+                  period_failures[result["p
eriod_id"]] += 1
+
+              print(f"\nPeriods with most f
ailures:")
+              for period, count in sorted(p
eriod_failures.items(), key=lambda x: x[1], 
reverse=True):
+                  print(f"  Period {period}
: {count} failed endpoints")
+
+              # Focus on realm/dungeon comb
inations with no data across all periods
+              print(f"\n=== REALM/DUNGEON C
OMBINATIONS WITH NO DATA ===")
+
+              # Group failed results by rea
lm+dungeon combination
+              realm_dungeon_failures = defa
ultdict(set)  # key: (realm_slug, dungeon_sl
ug), value: set of failed periods
+
+              for result in failed_results:
+                  key = (result["realm_slug
"], result["dungeon_slug"])
+                  realm_dungeon_failures[ke
y].add(result["period_id"])
+
+              # Find combinations that fail
ed across ALL tested periods
+              all_periods = set(PERIOD_RANG
E)
+              completely_broken = []
+              partially_broken = []
+
+              for (realm_slug, dungeon_slug
), failed_periods in realm_dungeon_failures.
items():
+                  if failed_periods == all_
periods:
+                      # Failed in ALL perio
ds
+                      completely_broken.app
end((realm_slug, dungeon_slug))
+                  else:
+                      # Failed in some peri
ods
+                      partially_broken.appe
nd((realm_slug, dungeon_slug, failed_periods
))
+
+              print(f"\nCompletely broken r
ealm/dungeon combinations (no data in ANY pe
riod {min(PERIOD_RANGE)}-{max(PERIOD_RANGE)}
):")
+              if completely_broken:
+                  for i, (realm_slug, dunge
on_slug) in enumerate(sorted(completely_brok
en), 1):
+                      # Find region for thi
s realm
+                      realm_info = next((r 
for r in REALMS if r["slug"] == realm_slug),
 None)
+                      region = realm_info["
region"].upper() if realm_info else "??"
+                      print(f"  {i:2d}. {re
alm_slug} ({region}) + {dungeon_slug}")
+              else:
+                  print("  None! All realm/
dungeon combinations have data in at least o
ne period.")
+
+              print(f"\nPartially broken re
alm/dungeon combinations:")
+              if partially_broken:
+                  for i, (realm_slug, dunge
on_slug, failed_periods) in enumerate(sorted
(partially_broken), 1):
+                      # Find region for thi
s realm
+                      realm_info = next((r 
for r in REALMS if r["slug"] == realm_slug),
 None)
+                      region = realm_info["
region"].upper() if realm_info else "??"
+                      working_periods = all
_periods - failed_periods
+                      print(f"  {i:2d}. {re
alm_slug} ({region}) + {dungeon_slug}")
+                      print(f"      Missing
 data in periods: {sorted(failed_periods)}")
+                      print(f"      Has dat
a in periods: {sorted(working_periods)}")
+              else:
+                  print("  None! All realm/
dungeon combinations work in all periods.")
+
+          else:
+              print("\\nAll endpoints are w
orking! ?")
+
+          # Summary of known problematic ca
ses
+          print(f"\n=== SPECIFIC PROBLEMATI
C CASES ===")
+          gehennas_mogushan = [r for r in f
ailed_results if r["realm_slug"] == "gehenna
s" and r["dungeon_slug"] == "mogu-shan-palac
e"]
+          if gehennas_mogushan:
+              print(f"Gehennas + Mogu'shan 
Palace failures: {len(gehennas_mogushan)}")
+              for result in gehennas_mogush
an:
+                  print(f"  Period {result[
'period_id']}: {result['error']}")
+          else:
+              print("Gehennas + Mogu'shan P
alace: All working!")
+
+      if __name__ == "__main__":
+          asyncio.run(main())
+    '';
+in
+  multiPeriodAnalyzerScript
+
 

diff --git a/nix/pkgs/ookstats/src/cmd/fetch.go b/nix/pkgs/ookstats/src/cmd/fetch.
go
index 8743e7d..36b1de6 100644
--- a/nix/pkgs/ookstats/src/cmd/fetch.go
+++ b/nix/pkgs/ookstats/src/cmd/fetch.go
@@ -124,17 +124,20 @@ var fetchCMCmd = &cobra.Command{
 				}
 			}
 		}
-		if strings.TrimSpace(realmsCSV) != "" {
-			allowed := map[string]bool{}
-			for _, s := range strings.Split(realmsCSV, ",") {
-				allowed[strings.TrimSpace(s)] = true
-			}
-			for slug := range allRealms {
-				if !allowed[slug] {
-					delete(allRealms, slug)
-				}
-			}
-		}
+        if strings.TrimSpace(realmsCSV) != "" {
+            allowed := map[string]bool{}
+            for _, s := range strings.Split(realmsCSV, ",") {
+                s = strings.TrimSpace(s)
+                if s != "" { allowed[s] = true }
+            }
+            filtered := make(map[string]blizzard.RealmInfo)
+            for key, info := range allRealms {
+                if allowed[key] || allowed[info.Slug] {
+                    filtered[key] = info
+                }
+            }
+            allRealms = filtered
+        }
 		if strings.TrimSpace(dungeonsCSV) != "" {
 			// parse list of ids or slugs
 			allowed := map[string]bool{}
@@ -153,14 +156,9 @@ var fetchCMCmd = &cobra.Command{
 			}
 		}
 
-		// pre-populate reference data (optimized): insert all dungeons once, then batc
h insert realms
-		fmt.Printf("Pre-populating reference data...\n")
-		fmt.Printf("  - Ensuring dungeons (%d)\n", len(dungeons))
-		// ensure slugs are set on realmInfo entries
-		for realmSlug, realmInfo := range allRealms {
-			realmInfo.Slug = realmSlug
-			allRealms[realmSlug] = realmInfo
-		}
+        // pre-populate reference data (optimized): insert all dungeons once, the
n batch insert realms
+        fmt.Printf("Pre-populating reference data...\n")
+        fmt.Printf("  - Ensuring dungeons (%d)\n", len(dungeons))
 		if err := dbService.EnsureDungeonsOnce(dungeons); err != nil {
 			return fmt.Errorf("failed to ensure dungeons: %w", err)
 		}
@@ -403,7 +401,7 @@ func init() {
 	fetchCMCmd.Flags().Int("fallback-depth", 0, "Limit number of fallback periods to
 try per dungeon (0 = default)")
 	fetchCMCmd.Flags().Int("concurrency", 20, "Max concurrent API requests")
 	fetchCMCmd.Flags().Int("api-timeout-seconds", 15, "HTTP client timeout in second
s")
-	fetchCMCmd.Flags().String("regions", "", "Comma-separated regions to include (us
,eu,kr)")
+    fetchCMCmd.Flags().String("regions", "", "Comma-separated regions to include 
(us,eu,kr,tw)")
 	fetchCMCmd.Flags().String("realms", "", "Comma-separated realm slugs to include"
)
 	fetchCMCmd.Flags().String("dungeons", "", "Comma-separated dungeon IDs or slugs 
to include")
 	// period strategy

diff --git a/nix/pkgs/ookstats/src/cmd/fetch
.go b/nix/pkgs/ookstats/src/cmd/fetch.go
index 8743e7d..36b1de6 100644
--- a/nix/pkgs/ookstats/src/cmd/fetch.go
+++ b/nix/pkgs/ookstats/src/cmd/fetch.go
@@ -124,17 +124,20 @@ var fetchCMCmd = &cobr
a.Command{
 				}
 			}
 		}
-		if strings.TrimSpace(realmsCSV) != "" {
-			allowed := map[string]bool{}
-			for _, s := range strings.Split(realmsCS
V, ",") {
-				allowed[strings.TrimSpace(s)] = true
-			}
-			for slug := range allRealms {
-				if !allowed[slug] {
-					delete(allRealms, slug)
-				}
-			}
-		}
+        if strings.TrimSpace(realmsCSV) != 
"" {
+            allowed := map[string]bool{}
+            for _, s := range strings.Split
(realmsCSV, ",") {
+                s = strings.TrimSpace(s)
+                if s != "" { allowed[s] = t
rue }
+            }
+            filtered := make(map[string]bli
zzard.RealmInfo)
+            for key, info := range allRealm
s {
+                if allowed[key] || allowed[
info.Slug] {
+                    filtered[key] = info
+                }
+            }
+            allRealms = filtered
+        }
 		if strings.TrimSpace(dungeonsCSV) != "" {
 			// parse list of ids or slugs
 			allowed := map[string]bool{}
@@ -153,14 +156,9 @@ var fetchCMCmd = &cobra
.Command{
 			}
 		}
 
-		// pre-populate reference data (optimized
): insert all dungeons once, then batch inse
rt realms
-		fmt.Printf("Pre-populating reference data
...\n")
-		fmt.Printf("  - Ensuring dungeons (%d)\n"
, len(dungeons))
-		// ensure slugs are set on realmInfo entr
ies
-		for realmSlug, realmInfo := range allReal
ms {
-			realmInfo.Slug = realmSlug
-			allRealms[realmSlug] = realmInfo
-		}
+        // pre-populate reference data (opt
imized): insert all dungeons once, then batc
h insert realms
+        fmt.Printf("Pre-populating referenc
e data...\n")
+        fmt.Printf("  - Ensuring dungeons (
%d)\n", len(dungeons))
 		if err := dbService.EnsureDungeonsOnce(du
ngeons); err != nil {
 			return fmt.Errorf("failed to ensure dung
eons: %w", err)
 		}
@@ -403,7 +401,7 @@ func init() {
 	fetchCMCmd.Flags().Int("fallback-depth", 0
, "Limit number of fallback periods to try p
er dungeon (0 = default)")
 	fetchCMCmd.Flags().Int("concurrency", 20, 
"Max concurrent API requests")
 	fetchCMCmd.Flags().Int("api-timeout-second
s", 15, "HTTP client timeout in seconds")
-	fetchCMCmd.Flags().String("regions", "", "
Comma-separated regions to include (us,eu,kr
)")
+    fetchCMCmd.Flags().String("regions", ""
, "Comma-separated regions to include (us,eu
,kr,tw)")
 	fetchCMCmd.Flags().String("realms", "", "C
omma-separated realm slugs to include")
 	fetchCMCmd.Flags().String("dungeons", "", 
"Comma-separated dungeon IDs or slugs to inc
lude")
 	// period strategy
 

diff --git a/nix/pkgs/ookstats/src/cmd/generate.go b/nix/pkgs/ookstats/src/cmd/gen
erate.go
index 3fd926f..25fadc8 100644
--- a/nix/pkgs/ookstats/src/cmd/generate.go
+++ b/nix/pkgs/ookstats/src/cmd/generate.go
@@ -955,7 +955,7 @@ func generateLeaderboards(db *sql.DB, out string, pageSize int
, regions []string
     for _, d := range dungeons { if err := writeGlobal(d); err != nil { return er
r } }
 
     // Regions
-    if len(regions) == 0 { regions = []string{"us","eu","kr"} }
+    if len(regions) == 0 { regions = []string{"us","eu","kr","tw"} }
     for _, reg := range regions {
         fmt.Printf("Generating %s leaderboards...\n", strings.ToUpper(reg))
         for _, d := range dungeons { if err := writeRegional(reg, d); err != nil 
{ return err } }
@@ -1215,7 +1215,7 @@ func generatePlayerLeaderboards(db *sql.DB, out string, page
Size int, regions []
     // global
     if err := writeScope("global", ""); err != nil { return err }
     // regional
-    if len(regions) == 0 { regions = []string{"us","eu","kr"} }
+    if len(regions) == 0 { regions = []string{"us","eu","kr","tw"} }
     for _, reg := range regions {
         if err := writeScope("regional", reg); err != nil { return err }
     }
@@ -1541,5 +1541,5 @@ func init() {
     generateAPICmd.Flags().Bool("search", true, "Generate search index JSON shard
s")
     generateAPICmd.Flags().Int("page-size", 25, "Leaderboard page size")
     generateAPICmd.Flags().Int("shard-size", 5000, "Search index shard size")
-    generateAPICmd.Flags().String("regions", "us,eu,kr", "Regions to include for 
regional leaderboards")
+    generateAPICmd.Flags().String("regions", "us,eu,kr,tw", "Regions to include f
or regional leaderboards")
 }

diff --git a/nix/pkgs/ookstats/src/cmd/gener
ate.go b/nix/pkgs/ookstats/src/cmd/generate.
go
index 3fd926f..25fadc8 100644
--- a/nix/pkgs/ookstats/src/cmd/generate.go
+++ b/nix/pkgs/ookstats/src/cmd/generate.go
@@ -955,7 +955,7 @@ func generateLeaderboard
s(db *sql.DB, out string, pageSize int, regi
ons []string
     for _, d := range dungeons { if err := 
writeGlobal(d); err != nil { return err } }
 
     // Regions
-    if len(regions) == 0 { regions = []stri
ng{"us","eu","kr"} }
+    if len(regions) == 0 { regions = []stri
ng{"us","eu","kr","tw"} }
     for _, reg := range regions {
         fmt.Printf("Generating %s leaderboa
rds...\n", strings.ToUpper(reg))
         for _, d := range dungeons { if err
 := writeRegional(reg, d); err != nil { retu
rn err } }
@@ -1215,7 +1215,7 @@ func generatePlayerLea
derboards(db *sql.DB, out string, pageSize i
nt, regions []
     // global
     if err := writeScope("global", ""); err
 != nil { return err }
     // regional
-    if len(regions) == 0 { regions = []stri
ng{"us","eu","kr"} }
+    if len(regions) == 0 { regions = []stri
ng{"us","eu","kr","tw"} }
     for _, reg := range regions {
         if err := writeScope("regional", re
g); err != nil { return err }
     }
@@ -1541,5 +1541,5 @@ func init() {
     generateAPICmd.Flags().Bool("search", t
rue, "Generate search index JSON shards")
     generateAPICmd.Flags().Int("page-size",
 25, "Leaderboard page size")
     generateAPICmd.Flags().Int("shard-size"
, 5000, "Search index shard size")
-    generateAPICmd.Flags().String("regions"
, "us,eu,kr", "Regions to include for region
al leaderboards")
+    generateAPICmd.Flags().String("regions"
, "us,eu,kr,tw", "Regions to include for reg
ional leaderboards")
 }
 

diff --git a/nix/pkgs/ookstats/src/internal/blizzard/constants.go b/nix/pkgs/ookst
ats/src/internal/blizzard/constants.go
index a163d3d..c656fe0 100644
--- a/nix/pkgs/ookstats/src/internal/blizzard/constants.go
+++ b/nix/pkgs/ookstats/src/internal/blizzard/constants.go
@@ -34,25 +34,28 @@ func GetGlobalPeriods() []string {
 // GetRegionFallbackPeriods prioritizes the period order per region based on obse
rved data
 // This reduces 404 churn before finding data.
 func GetRegionFallbackPeriods(region string) []string {
-	switch region {
-	case "eu":
-		// EU often has most data in 1025, then 1026
-		return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
-	case "us":
-		// US commonly 1026 first
-		return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
-	case "kr":
-		// KR follows US pattern in our observations
-		return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
-	default:
-		return GetFallbackPeriods()
-	}
+    switch region {
+    case "eu":
+        // EU often has most data in 1025, then 1026
+        return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "
1022", "1021", "1020"}
+    case "us":
+        // US commonly 1026 first
+        return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "
1022", "1021", "1020"}
+    case "kr":
+        // KR follows US pattern in our observations
+        return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "
1022", "1021", "1020"}
+    case "tw":
+        // TW expected to mirror US/KR period availability
+        return []string{"1029", "1028", "1027", "1026", "1025", "1024", "1023", "
1022", "1021", "1020"}
+    default:
+        return GetFallbackPeriods()
+    }
 }
 
 // GetAllRealms returns the complete realm configuration
 // this data comes from nix/api/realm.nix
 func GetAllRealms() map[string]RealmInfo {
-	return map[string]RealmInfo{
+    return map[string]RealmInfo{
 		// us realms
 		"atiesh":               {ID: 4372, Region: "us", Name: "Atiesh", Slug: "atiesh"
},
 		"myzrael":              {ID: 4373, Region: "us", Name: "Myzrael", Slug: "myzrae
l"},
@@ -105,11 +108,22 @@ func GetAllRealms() map[string]RealmInfo {
 		"thekal":               {ID: 4815, Region: "eu", Name: "Thekal", Slug: "thekal"
},
 		"jindo":                {ID: 4816, Region: "eu", Name: "Jin'do", Slug: "jindo"}
,
 
-		// kr realms
-		"shimmering-flats": {ID: 4417, Region: "kr", Name: "Shimmering Flats", Slug: "s
himmering-flats"},
-		"lokholar":         {ID: 4419, Region: "kr", Name: "Lokholar", Slug: "lokholar"
},
-		"iceblood":         {ID: 4420, Region: "kr", Name: "Iceblood", Slug: "iceblood"
},
-		"ragnaros":         {ID: 4421, Region: "kr", Name: "Ragnaros", Slug: "ragnaros"
},
-		"frostmourne":      {ID: 4840, Region: "kr", Name: "Frostmourne", Slug: "frostm
ourne"},
-	}
+        // kr realms
+        "shimmering-flats": {ID: 4417, Region: "kr", Name: "Shimmering Flats", Sl
ug: "shimmering-flats"},
+        "lokholar":         {ID: 4419, Region: "kr", Name: "Lokholar", Slug: "lok
holar"},
+        "iceblood":         {ID: 4420, Region: "kr", Name: "Iceblood", Slug: "ice
blood"},
+        "ragnaros":         {ID: 4421, Region: "kr", Name: "Ragnaros", Slug: "rag
naros"},
+        "frostmourne":      {ID: 4840, Region: "kr", Name: "Frostmourne", Slug: "
frostmourne"},
+
+        // tw realms (exclude PTR realms TW4 CWOW GMSS 1/2)
+        "maraudon":     {ID: 4485, Region: "tw", Name: "Maraudon", Slug: "maraudo
n"},
+        "ivus":         {ID: 4487, Region: "tw", Name: "Ivus", Slug: "ivus"},
+        "wushoolay":    {ID: 4488, Region: "tw", Name: "Wushoolay", Slug: "wushoo
lay"},
+        "zeliek":       {ID: 4489, Region: "tw", Name: "Zeliek", Slug: "zeliek"},
+        "arathi-basin": {ID: 5740, Region: "tw", Name: "Arathi Basin", Slug: "ara
thi-basin"},
+        "murloc":       {ID: 5741, Region: "tw", Name: "Murloc", Slug: "murloc"},
+        // Use disambiguated map keys for slugs colliding across regions; Slug fi
eld remains the Blizzard slug.
+        "golemagg-tw":   {ID: 5742, Region: "tw", Name: "Golemagg", Slug: "golema
gg"},
+        "windseeker-tw": {ID: 5743, Region: "tw", Name: "Windseeker", Slug: "wind
seeker"},
+    }
 }

diff --git a/nix/pkgs/ookstats/src/internal/
blizzard/constants.go b/nix/pkgs/ookstats/sr
c/internal/blizzard/constants.go
index a163d3d..c656fe0 100644
--- a/nix/pkgs/ookstats/src/internal/blizzar
d/constants.go
+++ b/nix/pkgs/ookstats/src/internal/blizzar
d/constants.go
@@ -34,25 +34,28 @@ func GetGlobalPeriods() 
[]string {
 // GetRegionFallbackPeriods prioritizes the
 period order per region based on observed d
ata
 // This reduces 404 churn before finding da
ta.
 func GetRegionFallbackPeriods(region string
) []string {
-	switch region {
-	case "eu":
-		// EU often has most data in 1025, then 1
026
-		return []string{"1029", "1028", "1027", "
1026", "1025", "1024", "1023", "1022", "1021
", "1020"}
-	case "us":
-		// US commonly 1026 first
-		return []string{"1029", "1028", "1027", "
1026", "1025", "1024", "1023", "1022", "1021
", "1020"}
-	case "kr":
-		// KR follows US pattern in our observati
ons
-		return []string{"1029", "1028", "1027", "
1026", "1025", "1024", "1023", "1022", "1021
", "1020"}
-	default:
-		return GetFallbackPeriods()
-	}
+    switch region {
+    case "eu":
+        // EU often has most data in 1025, 
then 1026
+        return []string{"1029", "1028", "10
27", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
+    case "us":
+        // US commonly 1026 first
+        return []string{"1029", "1028", "10
27", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
+    case "kr":
+        // KR follows US pattern in our obs
ervations
+        return []string{"1029", "1028", "10
27", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
+    case "tw":
+        // TW expected to mirror US/KR peri
od availability
+        return []string{"1029", "1028", "10
27", "1026", "1025", "1024", "1023", "1022",
 "1021", "1020"}
+    default:
+        return GetFallbackPeriods()
+    }
 }
 
 // GetAllRealms returns the complete realm 
configuration
 // this data comes from nix/api/realm.nix
 func GetAllRealms() map[string]RealmInfo {
-	return map[string]RealmInfo{
+    return map[string]RealmInfo{
 		// us realms
 		"atiesh":               {ID: 4372, Region
: "us", Name: "Atiesh", Slug: "atiesh"},
 		"myzrael":              {ID: 4373, Region
: "us", Name: "Myzrael", Slug: "myzrael"},
@@ -105,11 +108,22 @@ func GetAllRealms() ma
p[string]RealmInfo {
 		"thekal":               {ID: 4815, Region
: "eu", Name: "Thekal", Slug: "thekal"},
 		"jindo":                {ID: 4816, Region
: "eu", Name: "Jin'do", Slug: "jindo"},
 
-		// kr realms
-		"shimmering-flats": {ID: 4417, Region: "k
r", Name: "Shimmering Flats", Slug: "shimmer
ing-flats"},
-		"lokholar":         {ID: 4419, Region: "k
r", Name: "Lokholar", Slug: "lokholar"},
-		"iceblood":         {ID: 4420, Region: "k
r", Name: "Iceblood", Slug: "iceblood"},
-		"ragnaros":         {ID: 4421, Region: "k
r", Name: "Ragnaros", Slug: "ragnaros"},
-		"frostmourne":      {ID: 4840, Region: "k
r", Name: "Frostmourne", Slug: "frostmourne"
},
-	}
+        // kr realms
+        "shimmering-flats": {ID: 4417, Regi
on: "kr", Name: "Shimmering Flats", Slug: "s
himmering-flats"},
+        "lokholar":         {ID: 4419, Regi
on: "kr", Name: "Lokholar", Slug: "lokholar"
},
+        "iceblood":         {ID: 4420, Regi
on: "kr", Name: "Iceblood", Slug: "iceblood"
},
+        "ragnaros":         {ID: 4421, Regi
on: "kr", Name: "Ragnaros", Slug: "ragnaros"
},
+        "frostmourne":      {ID: 4840, Regi
on: "kr", Name: "Frostmourne", Slug: "frostm
ourne"},
+
+        // tw realms (exclude PTR realms TW
4 CWOW GMSS 1/2)
+        "maraudon":     {ID: 4485, Region: 
"tw", Name: "Maraudon", Slug: "maraudon"},
+        "ivus":         {ID: 4487, Region: 
"tw", Name: "Ivus", Slug: "ivus"},
+        "wushoolay":    {ID: 4488, Region: 
"tw", Name: "Wushoolay", Slug: "wushoolay"},
+        "zeliek":       {ID: 4489, Region: 
"tw", Name: "Zeliek", Slug: "zeliek"},
+        "arathi-basin": {ID: 5740, Region: 
"tw", Name: "Arathi Basin", Slug: "arathi-ba
sin"},
+        "murloc":       {ID: 5741, Region: 
"tw", Name: "Murloc", Slug: "murloc"},
+        // Use disambiguated map keys for s
lugs colliding across regions; Slug field re
mains the Blizzard slug.
+        "golemagg-tw":   {ID: 5742, Region:
 "tw", Name: "Golemagg", Slug: "golemagg"},
+        "windseeker-tw": {ID: 5743, Region:
 "tw", Name: "Windseeker", Slug: "windseeker
"},
+    }
 }
 

diff --git a/nix/pkgs/ookstats/src/internal/database/client.go b/nix/pkgs/ookstats
/src/internal/database/client.go
index 6f42807..f5410c9 100644
--- a/nix/pkgs/ookstats/src/internal/database/client.go
+++ b/nix/pkgs/ookstats/src/internal/database/client.go
@@ -232,13 +232,13 @@ func EnsureCompleteSchema(db *sql.DB) error {
 			map_challenge_mode_id INTEGER UNIQUE
 		)`,
 		
-		`CREATE TABLE IF NOT EXISTS realms (
-			id INTEGER PRIMARY KEY,
-			slug TEXT UNIQUE,
-			name TEXT,
-			region TEXT,
-			connected_realm_id INTEGER UNIQUE
-		)`,
+        `CREATE TABLE IF NOT EXISTS realms (
+            id INTEGER PRIMARY KEY,
+            slug TEXT,
+            name TEXT,
+            region TEXT,
+            connected_realm_id INTEGER UNIQUE
+        )`,
 		
 		// Core leaderboard data
 		`CREATE TABLE IF NOT EXISTS challenge_runs (
@@ -405,13 +405,20 @@ func EnsureCompleteSchema(db *sql.DB) error {
 	
 fmt.Printf("[OK] All tables created\n")
 	
-	// Create indexes
-	return ensureRecommendedIndexes(db)
+    // Migrate realms schema if needed (ensure (region, slug) composite uniquenes
s)
+    if err := migrateRealmsCompositeSlug(db); err != nil {
+        return err
+    }
+
+    // Create indexes
+    return ensureRecommendedIndexes(db)
 }
 
 // ensureRecommendedIndexes creates indexes used by hot paths if missing
 func ensureRecommendedIndexes(db *sql.DB) error {
     stmts := []string{
+        // Ensure composite uniqueness for realms
+        "CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slug ON realms(regio
n, slug)",
         // Fast path for high-water checks
         "CREATE INDEX IF NOT EXISTS idx_runs_realm_dungeon_ct ON challenge_runs(r
ealm_id, dungeon_id, completed_timestamp)",
         // Uniqueness key to avoid duplicates
@@ -435,3 +442,52 @@ func ensureRecommendedIndexes(db *sql.DB) error {
     fmt.Printf("[OK] All indexes ensured\n")
     return nil
 }
+
+// migrateRealmsCompositeSlug upgrades the realms table from slug-unique to (regi
on,slug)-unique if necessary.
+func migrateRealmsCompositeSlug(db *sql.DB) error {
+    // Inspect table SQL
+    var createSQL string
+    _ = db.QueryRow(`SELECT sql FROM sqlite_master WHERE type='table' AND name='r
ealms'`).Scan(&createSQL)
+    // If table already created without UNIQUE on slug, nothing to do
+    if !strings.Contains(strings.ToLower(createSQL), "slug text unique") {
+        return nil
+    }
+
+    fmt.Printf("[MIGRATE] Upgrading realms table to composite (region,slug) uniqu
eness...\n")
+    tx, err := db.Begin()
+    if err != nil { return err }
+    defer tx.Rollback()
+
+    // Create new table without UNIQUE on slug
+    if _, err := tx.Exec(`
+        CREATE TABLE IF NOT EXISTS realms_new (
+            id INTEGER PRIMARY KEY,
+            slug TEXT,
+            name TEXT,
+            region TEXT,
+            connected_realm_id INTEGER UNIQUE
+        )
+    `); err != nil { return fmt.Errorf("create realms_new: %w", err) }
+
+    // Copy data
+    if _, err := tx.Exec(`INSERT INTO realms_new (id, slug, name, region, connect
ed_realm_id)
+                          SELECT id, slug, name, region, connected_realm_id FROM 
realms`); err != nil {
+        return fmt.Errorf("copy realms: %w", err)
+    }
+
+    // Rename old and new
+    if _, err := tx.Exec(`ALTER TABLE realms RENAME TO realms_old`); err != nil {
 return fmt.Errorf("rename old: %w", err) }
+    if _, err := tx.Exec(`ALTER TABLE realms_new RENAME TO realms`); err != nil {
 return fmt.Errorf("rename new: %w", err) }
+
+    // Drop old
+    if _, err := tx.Exec(`DROP TABLE realms_old`); err != nil { return fmt.Errorf
("drop old: %w", err) }
+
+    // Ensure composite unique index
+    if _, err := tx.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slu
g ON realms(region, slug)`); err != nil {
+        return fmt.Errorf("create composite unique index: %w", err)
+    }
+
+    if err := tx.Commit(); err != nil { return err }
+    fmt.Printf("[OK] Realms table migrated\n")
+    return nil
+}

diff --git a/nix/pkgs/ookstats/src/internal/
database/client.go b/nix/pkgs/ookstats/src/i
nternal/database/client.go
index 6f42807..f5410c9 100644
--- a/nix/pkgs/ookstats/src/internal/databas
e/client.go
+++ b/nix/pkgs/ookstats/src/internal/databas
e/client.go
@@ -232,13 +232,13 @@ func EnsureCompleteSch
ema(db *sql.DB) error {
 			map_challenge_mode_id INTEGER UNIQUE
 		)`,
 		
-		`CREATE TABLE IF NOT EXISTS realms (
-			id INTEGER PRIMARY KEY,
-			slug TEXT UNIQUE,
-			name TEXT,
-			region TEXT,
-			connected_realm_id INTEGER UNIQUE
-		)`,
+        `CREATE TABLE IF NOT EXISTS realms 
(
+            id INTEGER PRIMARY KEY,
+            slug TEXT,
+            name TEXT,
+            region TEXT,
+            connected_realm_id INTEGER UNIQ
UE
+        )`,
 		
 		// Core leaderboard data
 		`CREATE TABLE IF NOT EXISTS challenge_run
s (
@@ -405,13 +405,20 @@ func EnsureCompleteSch
ema(db *sql.DB) error {
 	
 fmt.Printf("[OK] All tables created\n")
 	
-	// Create indexes
-	return ensureRecommendedIndexes(db)
+    // Migrate realms schema if needed (ens
ure (region, slug) composite uniqueness)
+    if err := migrateRealmsCompositeSlug(db
); err != nil {
+        return err
+    }
+
+    // Create indexes
+    return ensureRecommendedIndexes(db)
 }
 
 // ensureRecommendedIndexes creates indexes
 used by hot paths if missing
 func ensureRecommendedIndexes(db *sql.DB) e
rror {
     stmts := []string{
+        // Ensure composite uniqueness for 
realms
+        "CREATE UNIQUE INDEX IF NOT EXISTS 
idx_realms_region_slug ON realms(region, slu
g)",
         // Fast path for high-water checks
         "CREATE INDEX IF NOT EXISTS idx_run
s_realm_dungeon_ct ON challenge_runs(realm_i
d, dungeon_id, completed_timestamp)",
         // Uniqueness key to avoid duplicat
es
@@ -435,3 +442,52 @@ func ensureRecommendedI
ndexes(db *sql.DB) error {
     fmt.Printf("[OK] All indexes ensured\n"
)
     return nil
 }
+
+// migrateRealmsCompositeSlug upgrades the 
realms table from slug-unique to (region,slu
g)-unique if necessary.
+func migrateRealmsCompositeSlug(db *sql.DB)
 error {
+    // Inspect table SQL
+    var createSQL string
+    _ = db.QueryRow(`SELECT sql FROM sqlite
_master WHERE type='table' AND name='realms'
`).Scan(&createSQL)
+    // If table already created without UNI
QUE on slug, nothing to do
+    if !strings.Contains(strings.ToLower(cr
eateSQL), "slug text unique") {
+        return nil
+    }
+
+    fmt.Printf("[MIGRATE] Upgrading realms 
table to composite (region,slug) uniqueness.
..\n")
+    tx, err := db.Begin()
+    if err != nil { return err }
+    defer tx.Rollback()
+
+    // Create new table without UNIQUE on s
lug
+    if _, err := tx.Exec(`
+        CREATE TABLE IF NOT EXISTS realms_n
ew (
+            id INTEGER PRIMARY KEY,
+            slug TEXT,
+            name TEXT,
+            region TEXT,
+            connected_realm_id INTEGER UNIQ
UE
+        )
+    `); err != nil { return fmt.Errorf("cre
ate realms_new: %w", err) }
+
+    // Copy data
+    if _, err := tx.Exec(`INSERT INTO realm
s_new (id, slug, name, region, connected_rea
lm_id)
+                          SELECT id, slug, 
name, region, connected_realm_id FROM realms
`); err != nil {
+        return fmt.Errorf("copy realms: %w"
, err)
+    }
+
+    // Rename old and new
+    if _, err := tx.Exec(`ALTER TABLE realm
s RENAME TO realms_old`); err != nil { retur
n fmt.Errorf("rename old: %w", err) }
+    if _, err := tx.Exec(`ALTER TABLE realm
s_new RENAME TO realms`); err != nil { retur
n fmt.Errorf("rename new: %w", err) }
+
+    // Drop old
+    if _, err := tx.Exec(`DROP TABLE realms
_old`); err != nil { return fmt.Errorf("drop
 old: %w", err) }
+
+    // Ensure composite unique index
+    if _, err := tx.Exec(`CREATE UNIQUE IND
EX IF NOT EXISTS idx_realms_region_slug ON r
ealms(region, slug)`); err != nil {
+        return fmt.Errorf("create composite
 unique index: %w", err)
+    }
+
+    if err := tx.Commit(); err != nil { ret
urn err }
+    fmt.Printf("[OK] Realms table migrated\
n")
+    return nil
+}
 

diff --git a/nix/pkgs/ookstats/src/internal/database/models.go b/nix/pkgs/ookstats
/src/internal/database/models.go
index 604f2b6..a35ad09 100644
--- a/nix/pkgs/ookstats/src/internal/database/models.go
+++ b/nix/pkgs/ookstats/src/internal/database/models.go
@@ -130,7 +130,8 @@ func (ds *DatabaseService) UpdateFetchMetadata(fetchType strin
g, runsFetched, pl
 
 // GetRealmID retrieves realm ID by slug, returns 0 if not found
 func (ds *DatabaseService) GetRealmID(slug string) (int, error) {
-	query := `SELECT id FROM realms WHERE slug = ?`
+    // Deprecated: prefer GetRealmIDByRegionAndSlug
+    query := `SELECT id FROM realms WHERE slug = ?`
 
 	var realmID int
 	err := ds.db.QueryRow(query, slug).Scan(&realmID)
@@ -144,6 +145,21 @@ func (ds *DatabaseService) GetRealmID(slug string) (int, erro
r) {
 	return realmID, nil
 }
 
+// GetRealmIDByRegionAndSlug retrieves realm ID by composite (region, slug), retu
rns 0 if not found
+func (ds *DatabaseService) GetRealmIDByRegionAndSlug(region, slug string) (int, e
rror) {
+    query := `SELECT id FROM realms WHERE region = ? AND slug = ?`
+
+    var realmID int
+    err := ds.db.QueryRow(query, region, slug).Scan(&realmID)
+    if err == sql.ErrNoRows {
+        return 0, nil
+    }
+    if err != nil {
+        return 0, err
+    }
+    return realmID, nil
+}
+
 // GetDungeonID retrieves dungeon ID by slug, returns 0 if not found
 func (ds *DatabaseService) GetDungeonID(slug string) (int, error) {
 	query := `SELECT id FROM dungeons WHERE slug = ?`

diff --git a/nix/pkgs/ookstats/src/internal/
database/models.go b/nix/pkgs/ookstats/src/i
nternal/database/models.go
index 604f2b6..a35ad09 100644
--- a/nix/pkgs/ookstats/src/internal/databas
e/models.go
+++ b/nix/pkgs/ookstats/src/internal/databas
e/models.go
@@ -130,7 +130,8 @@ func (ds *DatabaseServic
e) UpdateFetchMetadata(fetchType string, run
sFetched, pl
 
 // GetRealmID retrieves realm ID by slug, r
eturns 0 if not found
 func (ds *DatabaseService) GetRealmID(slug 
string) (int, error) {
-	query := `SELECT id FROM realms WHERE slug
 = ?`
+    // Deprecated: prefer GetRealmIDByRegio
nAndSlug
+    query := `SELECT id FROM realms WHERE s
lug = ?`
 
 	var realmID int
 	err := ds.db.QueryRow(query, slug).Scan(&r
ealmID)
@@ -144,6 +145,21 @@ func (ds *DatabaseServi
ce) GetRealmID(slug string) (int, error) {
 	return realmID, nil
 }
 
+// GetRealmIDByRegionAndSlug retrieves real
m ID by composite (region, slug), returns 0 
if not found
+func (ds *DatabaseService) GetRealmIDByRegi
onAndSlug(region, slug string) (int, error) 
{
+    query := `SELECT id FROM realms WHERE r
egion = ? AND slug = ?`
+
+    var realmID int
+    err := ds.db.QueryRow(query, region, sl
ug).Scan(&realmID)
+    if err == sql.ErrNoRows {
+        return 0, nil
+    }
+    if err != nil {
+        return 0, err
+    }
+    return realmID, nil
+}
+
 // GetDungeonID retrieves dungeon ID by slu
g, returns 0 if not found
 func (ds *DatabaseService) GetDungeonID(slu
g string) (int, error) {
 	query := `SELECT id FROM dungeons WHERE sl
ug = ?`
 

diff --git a/nix/pkgs/ookstats/src/internal/database/operations.go b/nix/pkgs/ooks
tats/src/internal/database/operations.go
index 06083a2..1444492 100644
--- a/nix/pkgs/ookstats/src/internal/database/operations.go
+++ b/nix/pkgs/ookstats/src/internal/database/operations.go
@@ -118,8 +118,8 @@ func (ds *DatabaseService) InsertLeaderboardData(leaderboard *
blizzard.Leaderboa
 		return 0, 0, nil
 	}
 
-	// Get realm and dungeon IDs
-	realmID, err := ds.GetRealmID(realmInfo.Slug)
+    // Get realm and dungeon IDs
+    realmID, err := ds.GetRealmIDByRegionAndSlug(realmInfo.Region, realmInfo.Slug
)
 	if err != nil {
 		return 0, 0, fmt.Errorf("failed to get realm ID: %w", err)
 	}
@@ -213,7 +213,7 @@ func (ds *DatabaseService) InsertLeaderboardData(leaderboard *
blizzard.Leaderboa
 			// get or create player realm
 			var playerRealmID int
 			if hasRealmSlug {
-				playerRealmID, err = ds.getOrCreateRealm(tx, playerRealmSlug, allRealms)
+				playerRealmID, err = ds.getOrCreateRealmByRegion(tx, playerRealmSlug, realmIn
fo.Region, allRealms)
 				if err != nil {
 					return 0, 0, fmt.Errorf("failed to get/create player realm: %w", err)
 				}
@@ -462,7 +462,7 @@ func (ds *DatabaseService) processBatch(batch []blizzard.Fetch
Result) (int, int,
             continue
         }
         // resolve IDs (read-only)
-        realmID, err := ds.GetRealmID(res.RealmInfo.Slug)
+        realmID, err := ds.GetRealmIDByRegionAndSlug(res.RealmInfo.Region, res.Re
almInfo.Slug)
         if err != nil {
             return 0, 0, fmt.Errorf("failed to resolve realm id: %w", err)
         }
@@ -573,7 +573,7 @@ func (ds *DatabaseService) ensureReferenceDataTx(tx *sql.Tx, r
ealmInfo blizzard.
 // insertLeaderboardDataTx inserts leaderboard data within a transaction
 func (ds *DatabaseService) insertLeaderboardDataTx(tx *sql.Tx, leaderboard *blizz
ard.LeaderboardResponse, realmInfo blizzard.RealmInfo, dungeon blizzard.DungeonInf
o) (int, int, error) {
     // Resolve realm and dungeon IDs (read-only; realms/dungeons are pre-populate
d)
-    realmID, err := ds.getRealmIDTx(tx, realmInfo.Slug)
+    realmID, err := ds.getRealmIDTx(tx, realmInfo.Slug, realmInfo.Region)
     if err != nil {
         return 0, 0, fmt.Errorf("failed to get realm ID: %w", err)
     }
@@ -681,7 +681,7 @@ func (ds *DatabaseService) insertLeaderboardDataTx(tx *sql.Tx,
 leaderboard *bliz
 			var playerRealmID int
             if hasRealmSlug {
                 // resolve player realm id (realms are pre-populated; create only
 if truly unknown)
-                playerRealmID, err = ds.getRealmIDTx(tx, playerRealmSlug)
+                playerRealmID, err = ds.getRealmIDTx(tx, playerRealmSlug, realmIn
fo.Region)
                 if err != nil {
                     return 0, 0, fmt.Errorf("failed to resolve player realm: %w",
 err)
                 }
@@ -690,7 +690,7 @@ func (ds *DatabaseService) insertLeaderboardDataTx(tx *sql.Tx,
 leaderboard *bliz
                         playerRealmSlug, playerRealmSlug, realmInfo.Region, 0); e
rr != nil {
                         return 0, 0, fmt.Errorf("failed to create placeholder rea
lm: %w", err)
                     }
-                    id2, err := ds.getRealmIDTx(tx, playerRealmSlug)
+                    id2, err := ds.getRealmIDTx(tx, playerRealmSlug, realmInfo.Re
gion)
                     if err != nil || id2 == 0 {
                         return 0, 0, fmt.Errorf("failed to resolve placeholder re
alm id: %w", err)
                     }
@@ -761,13 +761,13 @@ func (ds *DatabaseService) insertLeaderboardDataTx(tx *sql.T
x, leaderboard *bliz
 }
 
 // helper functions for transaction-based operations
-func (ds *DatabaseService) getRealmIDTx(tx *sql.Tx, slug string) (int, error) {
-	var realmID int
-	err := tx.QueryRow("SELECT id FROM realms WHERE slug = ?", slug).Scan(&realmID)
-	if err == sql.ErrNoRows {
-		return 0, fmt.Errorf("realm not found: %s", slug)
-	}
-	return realmID, err
+func (ds *DatabaseService) getRealmIDTx(tx *sql.Tx, slug string, region string) (
int, error) {
+    var realmID int
+    err := tx.QueryRow("SELECT id FROM realms WHERE slug = ? AND region = ?", slu
g, region).Scan(&realmID)
+    if err == sql.ErrNoRows {
+        return 0, fmt.Errorf("realm not found: %s/%s", region, slug)
+    }
+    return realmID, err
 }
 
 func (ds *DatabaseService) getDungeonIDTx(tx *sql.Tx, slug string) (int, error) {
@@ -816,6 +816,43 @@ func (ds *DatabaseService) getOrCreateRealmTx(tx *sql.Tx, rea
lmSlug string, allR
 	}
 }
 
+// getOrCreateRealmByRegion resolves a realm by region+slug or creates a placehol
der/known realm
+func (ds *DatabaseService) getOrCreateRealmByRegion(tx *sql.Tx, realmSlug string,
 region string, allRealms map[string]blizzard.RealmInfo) (int, error) {
+    // try to get existing realm by composite key
+    var realmID int
+    err := tx.QueryRow("SELECT id FROM realms WHERE slug = ? AND region = ?", rea
lmSlug, region).Scan(&realmID)
+    if err == nil {
+        return realmID, nil
+    }
+    if err != sql.ErrNoRows {
+        return 0, err
+    }
+
+    // If we know this realm (by slug) from constants, use its canonical region/n
ame/id
+    if realmInfo, ok := allRealms[realmSlug]; ok {
+        result, err := tx.Exec(`
+            INSERT INTO realms (slug, name, region, connected_realm_id)
+            VALUES (?, ?, ?, ?)
+        `, realmSlug, realmInfo.Name, realmInfo.Region, realmInfo.ID)
+        if err != nil {
+            return 0, err
+        }
+        newID, err := result.LastInsertId()
+        return int(newID), err
+    }
+
+    // otherwise create a placeholder scoped to the provided region
+    result, err := tx.Exec(`
+        INSERT INTO realms (slug, name, region, connected_realm_id)
+        VALUES (?, ?, ?, ?)
+    `, realmSlug, utils.Slugify(realmSlug), region, 0)
+    if err != nil {
+        return 0, err
+    }
+    newID, err := result.LastInsertId()
+    return int(newID), err
+}
+
 // player profile database operations
 
 // GetEligiblePlayersForProfileFetch returns players with complete coverage (9/9 
dungeons)

diff --git a/nix/pkgs/ookstats/src/internal/
database/operations.go b/nix/pkgs/ookstats/s
rc/internal/database/operations.go
index 06083a2..1444492 100644
--- a/nix/pkgs/ookstats/src/internal/databas
e/operations.go
+++ b/nix/pkgs/ookstats/src/internal/databas
e/operations.go
@@ -118,8 +118,8 @@ func (ds *DatabaseServic
e) InsertLeaderboardData(leaderboard *blizza
rd.Leaderboa
 		return 0, 0, nil
 	}
 
-	// Get realm and dungeon IDs
-	realmID, err := ds.GetRealmID(realmInfo.Sl
ug)
+    // Get realm and dungeon IDs
+    realmID, err := ds.GetRealmIDByRegionAn
dSlug(realmInfo.Region, realmInfo.Slug)
 	if err != nil {
 		return 0, 0, fmt.Errorf("failed to get re
alm ID: %w", err)
 	}
@@ -213,7 +213,7 @@ func (ds *DatabaseServic
e) InsertLeaderboardData(leaderboard *blizza
rd.Leaderboa
 			// get or create player realm
 			var playerRealmID int
 			if hasRealmSlug {
-				playerRealmID, err = ds.getOrCreateReal
m(tx, playerRealmSlug, allRealms)
+				playerRealmID, err = ds.getOrCreateReal
mByRegion(tx, playerRealmSlug, realmInfo.Reg
ion, allRealms)
 				if err != nil {
 					return 0, 0, fmt.Errorf("failed to get
/create player realm: %w", err)
 				}
@@ -462,7 +462,7 @@ func (ds *DatabaseServic
e) processBatch(batch []blizzard.FetchResult
) (int, int,
             continue
         }
         // resolve IDs (read-only)
-        realmID, err := ds.GetRealmID(res.R
ealmInfo.Slug)
+        realmID, err := ds.GetRealmIDByRegi
onAndSlug(res.RealmInfo.Region, res.RealmInf
o.Slug)
         if err != nil {
             return 0, 0, fmt.Errorf("failed
 to resolve realm id: %w", err)
         }
@@ -573,7 +573,7 @@ func (ds *DatabaseServic
e) ensureReferenceDataTx(tx *sql.Tx, realmIn
fo blizzard.
 // insertLeaderboardDataTx inserts leaderbo
ard data within a transaction
 func (ds *DatabaseService) insertLeaderboar
dDataTx(tx *sql.Tx, leaderboard *blizzard.Le
aderboardResponse, realmInfo blizzard.RealmI
nfo, dungeon blizzard.DungeonInfo) (int, int
, error) {
     // Resolve realm and dungeon IDs (read-
only; realms/dungeons are pre-populated)
-    realmID, err := ds.getRealmIDTx(tx, rea
lmInfo.Slug)
+    realmID, err := ds.getRealmIDTx(tx, rea
lmInfo.Slug, realmInfo.Region)
     if err != nil {
         return 0, 0, fmt.Errorf("failed to 
get realm ID: %w", err)
     }
@@ -681,7 +681,7 @@ func (ds *DatabaseServic
e) insertLeaderboardDataTx(tx *sql.Tx, leade
rboard *bliz
 			var playerRealmID int
             if hasRealmSlug {
                 // resolve player realm id 
(realms are pre-populated; create only if tr
uly unknown)
-                playerRealmID, err = ds.get
RealmIDTx(tx, playerRealmSlug)
+                playerRealmID, err = ds.get
RealmIDTx(tx, playerRealmSlug, realmInfo.Reg
ion)
                 if err != nil {
                     return 0, 0, fmt.Errorf
("failed to resolve player realm: %w", err)
                 }
@@ -690,7 +690,7 @@ func (ds *DatabaseServic
e) insertLeaderboardDataTx(tx *sql.Tx, leade
rboard *bliz
                         playerRealmSlug, pl
ayerRealmSlug, realmInfo.Region, 0); err != 
nil {
                         return 0, 0, fmt.Er
rorf("failed to create placeholder realm: %w
", err)
                     }
-                    id2, err := ds.getRealm
IDTx(tx, playerRealmSlug)
+                    id2, err := ds.getRealm
IDTx(tx, playerRealmSlug, realmInfo.Region)
                     if err != nil || id2 ==
 0 {
                         return 0, 0, fmt.Er
rorf("failed to resolve placeholder realm id
: %w", err)
                     }
@@ -761,13 +761,13 @@ func (ds *DatabaseServ
ice) insertLeaderboardDataTx(tx *sql.Tx, lea
derboard *bliz
 }
 
 // helper functions for transaction-based o
perations
-func (ds *DatabaseService) getRealmIDTx(tx 
*sql.Tx, slug string) (int, error) {
-	var realmID int
-	err := tx.QueryRow("SELECT id FROM realms 
WHERE slug = ?", slug).Scan(&realmID)
-	if err == sql.ErrNoRows {
-		return 0, fmt.Errorf("realm not found: %s
", slug)
-	}
-	return realmID, err
+func (ds *DatabaseService) getRealmIDTx(tx 
*sql.Tx, slug string, region string) (int, e
rror) {
+    var realmID int
+    err := tx.QueryRow("SELECT id FROM real
ms WHERE slug = ? AND region = ?", slug, reg
ion).Scan(&realmID)
+    if err == sql.ErrNoRows {
+        return 0, fmt.Errorf("realm not fou
nd: %s/%s", region, slug)
+    }
+    return realmID, err
 }
 
 func (ds *DatabaseService) getDungeonIDTx(t
x *sql.Tx, slug string) (int, error) {
@@ -816,6 +816,43 @@ func (ds *DatabaseServi
ce) getOrCreateRealmTx(tx *sql.Tx, realmSlug
 string, allR
 	}
 }
 
+// getOrCreateRealmByRegion resolves a real
m by region+slug or creates a placeholder/kn
own realm
+func (ds *DatabaseService) getOrCreateRealm
ByRegion(tx *sql.Tx, realmSlug string, regio
n string, allRealms map[string]blizzard.Real
mInfo) (int, error) {
+    // try to get existing realm by composi
te key
+    var realmID int
+    err := tx.QueryRow("SELECT id FROM real
ms WHERE slug = ? AND region = ?", realmSlug
, region).Scan(&realmID)
+    if err == nil {
+        return realmID, nil
+    }
+    if err != sql.ErrNoRows {
+        return 0, err
+    }
+
+    // If we know this realm (by slug) from
 constants, use its canonical region/name/id
+    if realmInfo, ok := allRealms[realmSlug
]; ok {
+        result, err := tx.Exec(`
+            INSERT INTO realms (slug, name,
 region, connected_realm_id)
+            VALUES (?, ?, ?, ?)
+        `, realmSlug, realmInfo.Name, realm
Info.Region, realmInfo.ID)
+        if err != nil {
+            return 0, err
+        }
+        newID, err := result.LastInsertId()
+        return int(newID), err
+    }
+
+    // otherwise create a placeholder scope
d to the provided region
+    result, err := tx.Exec(`
+        INSERT INTO realms (slug, name, reg
ion, connected_realm_id)
+        VALUES (?, ?, ?, ?)
+    `, realmSlug, utils.Slugify(realmSlug),
 region, 0)
+    if err != nil {
+        return 0, err
+    }
+    newID, err := result.LastInsertId()
+    return int(newID), err
+}
+
 // player profile database operations
 
 // GetEligiblePlayersForProfileFetch return
s players with complete coverage (9/9 dungeo
ns)
 

diff --git a/web/.astro/data-store.json b/web/.astro/data-store.json
index 3aef997..11f4145 100644
--- a/web/.astro/data-store.json
+++ b/web/.astro/data-store.json
@@ -1 +1 @@
-[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config-
digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{}
,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail
ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",
\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr
o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto
\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":30711,\"s
treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r
oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"
config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de
vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\
",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th
eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl
ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t
rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\
":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false
,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\
":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}"
]
\ No newline at end of file
+[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config-
digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{}
,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail
ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",
\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr
o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto
\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":29567,\"s
treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r
oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"
config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de
vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\
",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th
eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl
ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t
rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\
":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false
,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\
":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}"
]
\ No newline at end of file

diff --git a/web/.astro/data-store.json b/we
b/.astro/data-store.json
index 3aef997..11f4145 100644
--- a/web/.astro/data-store.json
+++ b/web/.astro/data-store.json
@@ -1 +1 @@
-[["Map",1,2],"meta::meta",["Map",3,4,5,6],"
astro-version","5.12.0","astro-config-digest
","{\"root\":{},\"srcDir\":{},\"publicDir\":
{},\"outDir\":{},\"cacheDir\":{},\"site\":\"
https://wowsimstats.com\",\"compressHTML\":t
rue,\"base\":\"/\",\"trailingSlash\":\"ignor
e\",\"output\":\"server\",\"scopedStyleStrat
egy\":\"attribute\",\"build\":{\"format\":\"
directory\",\"client\":{},\"server\":{},\"as
sets\":\"_astro\",\"serverEntry\":\"entry.mj
s\",\"redirects\":false,\"inlineStylesheets\
":\"auto\",\"concurrency\":1},\"server\":{\"
open\":false,\"host\":false,\"port\":30711,\
"streaming\":true,\"allowedHosts\":[]},\"red
irects\":{},\"image\":{\"endpoint\":{\"route
\":\"/_image\"},\"service\":{\"entrypoint\":
\"astro/assets/services/sharp\",\"config\":{
}},\"domains\":[],\"remotePatterns\":[],\"re
sponsiveStyles\":false},\"devToolbar\":{\"en
abled\":true},\"markdown\":{\"syntaxHighligh
t\":{\"type\":\"shiki\",\"excludeLangs\":[\"
math\"]},\"shikiConfig\":{\"langs\":[],\"lan
gAlias\":{},\"theme\":\"github-dark\",\"them
es\":{},\"wrap\":false,\"transformers\":[]},
\"remarkPlugins\":[],\"rehypePlugins\":[],\"
remarkRehype\":{},\"gfm\":true,\"smartypants
\":true},\"security\":{\"checkOrigin\":true}
,\"env\":{\"schema\":{},\"validateSecrets\":
false},\"experimental\":{\"clientPrerender\"
:false,\"contentIntellisense\":false,\"headi
ngIdCompat\":false,\"preserveScriptOrder\":f
alse,\"liveContentCollections\":false,\"csp\
":false,\"rawEnvValues\":false},\"legacy\":{
\"collections\":false}}"]
\ No newline at end of file
+[["Map",1,2],"meta::meta",["Map",3,4,5,6],"
astro-version","5.12.0","astro-config-digest
","{\"root\":{},\"srcDir\":{},\"publicDir\":
{},\"outDir\":{},\"cacheDir\":{},\"site\":\"
https://wowsimstats.com\",\"compressHTML\":t
rue,\"base\":\"/\",\"trailingSlash\":\"ignor
e\",\"output\":\"server\",\"scopedStyleStrat
egy\":\"attribute\",\"build\":{\"format\":\"
directory\",\"client\":{},\"server\":{},\"as
sets\":\"_astro\",\"serverEntry\":\"entry.mj
s\",\"redirects\":false,\"inlineStylesheets\
":\"auto\",\"concurrency\":1},\"server\":{\"
open\":false,\"host\":false,\"port\":29567,\
"streaming\":true,\"allowedHosts\":[]},\"red
irects\":{},\"image\":{\"endpoint\":{\"route
\":\"/_image\"},\"service\":{\"entrypoint\":
\"astro/assets/services/sharp\",\"config\":{
}},\"domains\":[],\"remotePatterns\":[],\"re
sponsiveStyles\":false},\"devToolbar\":{\"en
abled\":true},\"markdown\":{\"syntaxHighligh
t\":{\"type\":\"shiki\",\"excludeLangs\":[\"
math\"]},\"shikiConfig\":{\"langs\":[],\"lan
gAlias\":{},\"theme\":\"github-dark\",\"them
es\":{},\"wrap\":false,\"transformers\":[]},
\"remarkPlugins\":[],\"rehypePlugins\":[],\"
remarkRehype\":{},\"gfm\":true,\"smartypants
\":true},\"security\":{\"checkOrigin\":true}
,\"env\":{\"schema\":{},\"validateSecrets\":
false},\"experimental\":{\"clientPrerender\"
:false,\"contentIntellisense\":false,\"headi
ngIdCompat\":false,\"preserveScriptOrder\":f
alse,\"liveContentCollections\":false,\"csp\
":false,\"rawEnvValues\":false},\"legacy\":{
\"collections\":false}}"]
\ No newline at end of file
 

diff --git a/web/src/components/LeaderboardControls.astro b/web/src/components/Lea
derboardControls.astro
index 92d3433..2db15bc 100644
--- a/web/src/components/LeaderboardControls.astro
+++ b/web/src/components/LeaderboardControls.astro
@@ -47,6 +47,7 @@ const {
         { value: "us", label: "US", selected: initialRegion === "us" },
         { value: "eu", label: "EU", selected: initialRegion === "eu" },
         { value: "kr", label: "KR", selected: initialRegion === "kr" },
+        { value: "tw", label: "TW", selected: initialRegion === "tw" },
         {
           value: "global",
           label: "Global",

diff --git a/web/src/components/LeaderboardC
ontrols.astro b/web/src/components/Leaderboa
rdControls.astro
index 92d3433..2db15bc 100644
--- a/web/src/components/LeaderboardControls
.astro
+++ b/web/src/components/LeaderboardControls
.astro
@@ -47,6 +47,7 @@ const {
         { value: "us", label: "US", selecte
d: initialRegion === "us" },
         { value: "eu", label: "EU", selecte
d: initialRegion === "eu" },
         { value: "kr", label: "KR", selecte
d: initialRegion === "kr" },
+        { value: "tw", label: "TW", selecte
d: initialRegion === "tw" },
         {
           value: "global",
           label: "Global",
 

diff --git a/web/src/components/islands/FilterPanel.astro b/web/src/components/isl
ands/FilterPanel.astro
index d9a8131..cf734bc 100644
--- a/web/src/components/islands/FilterPanel.astro
+++ b/web/src/components/islands/FilterPanel.astro
@@ -32,6 +32,7 @@ const {
         <option value="us" selected={initialRegion === "us"}>US</option>
         <option value="eu" selected={initialRegion === "eu"}>EU</option>
         <option value="kr" selected={initialRegion === "kr"}>KR</option>
+        <option value="tw" selected={initialRegion === "tw"}>TW</option>
       </select>
     </div>
 
@@ -71,6 +72,15 @@ const {
               </option>
             ))
         }
+        {
+          Object.entries(REALM_DATA.tw)
+            .sort((a, b) => a[1].localeCompare(b[1]))
+            .map(([slug, name]) => (
+              <option value={slug} data-region="tw" style="display: none;">
+                {name}
+              </option>
+            ))
+        }
       </select>
     </div>
 

diff --git a/web/src/components/islands/Filt
erPanel.astro b/web/src/components/islands/F
ilterPanel.astro
index d9a8131..cf734bc 100644
--- a/web/src/components/islands/FilterPanel
.astro
+++ b/web/src/components/islands/FilterPanel
.astro
@@ -32,6 +32,7 @@ const {
         <option value="us" selected={initia
lRegion === "us"}>US</option>
         <option value="eu" selected={initia
lRegion === "eu"}>EU</option>
         <option value="kr" selected={initia
lRegion === "kr"}>KR</option>
+        <option value="tw" selected={initia
lRegion === "tw"}>TW</option>
       </select>
     </div>
 
@@ -71,6 +72,15 @@ const {
               </option>
             ))
         }
+        {
+          Object.entries(REALM_DATA.tw)
+            .sort((a, b) => a[1].localeComp
are(b[1]))
+            .map(([slug, name]) => (
+              <option value={slug} data-reg
ion="tw" style="display: none;">
+                {name}
+              </option>
+            ))
+        }
       </select>
     </div>
 
 

diff --git a/web/src/components/islands/PlayerFilterPanel.astro b/web/src/componen
ts/islands/PlayerFilterPanel.astro
index 417247d..c31092c 100644
--- a/web/src/components/islands/PlayerFilterPanel.astro
+++ b/web/src/components/islands/PlayerFilterPanel.astro
@@ -31,6 +31,7 @@ const {
         <option value="us" selected={initialRegion === "us"}>US</option>
         <option value="eu" selected={initialRegion === "eu"}>EU</option>
         <option value="kr" selected={initialRegion === "kr"}>KR</option>
+        <option value="tw" selected={initialRegion === "tw"}>TW</option>
       </select>
     </div>
 
@@ -59,6 +60,13 @@ const {
               <option value={slug} data-region="kr" style="display: none;">{name}
</option>
             ))
         }
+        {
+          Object.entries(REALM_DATA.tw)
+            .sort((a, b) => a[1].localeCompare(b[1]))
+            .map(([slug, name]) => (
+              <option value={slug} data-region="tw" style="display: none;">{name}
</option>
+            ))
+        }
       </select>
     </div>
 
@@ -95,4 +103,3 @@ const {
   .filter-select { background: var(--bg-primary); color: var(--text-primary); bor
der: 1px solid var(--border-color); border-radius: 4px; padding: 8px 10px; }
   @media (max-width: 768px) { .filter-row { grid-template-columns: 1fr; } }
 </style>
-

diff --git a/web/src/components/islands/Play
erFilterPanel.astro b/web/src/components/isl
ands/PlayerFilterPanel.astro
index 417247d..c31092c 100644
--- a/web/src/components/islands/PlayerFilte
rPanel.astro
+++ b/web/src/components/islands/PlayerFilte
rPanel.astro
@@ -31,6 +31,7 @@ const {
         <option value="us" selected={initia
lRegion === "us"}>US</option>
         <option value="eu" selected={initia
lRegion === "eu"}>EU</option>
         <option value="kr" selected={initia
lRegion === "kr"}>KR</option>
+        <option value="tw" selected={initia
lRegion === "tw"}>TW</option>
       </select>
     </div>
 
@@ -59,6 +60,13 @@ const {
               <option value={slug} data-reg
ion="kr" style="display: none;">{name}</opti
on>
             ))
         }
+        {
+          Object.entries(REALM_DATA.tw)
+            .sort((a, b) => a[1].localeComp
are(b[1]))
+            .map(([slug, name]) => (
+              <option value={slug} data-reg
ion="tw" style="display: none;">{name}</opti
on>
+            ))
+        }
       </select>
     </div>
 
@@ -95,4 +103,3 @@ const {
   .filter-select { background: var(--bg-pri
mary); color: var(--text-primary); border: 1
px solid var(--border-color); border-radius:
 4px; padding: 8px 10px; }
   @media (max-width: 768px) { .filter-row {
 grid-template-columns: 1fr; } }
 </style>
-
 

diff --git a/web/src/lib/realms.ts b/web/src/lib/realms.ts
index 1bdb222..fd2e987 100644
--- a/web/src/lib/realms.ts
+++ b/web/src/lib/realms.ts
@@ -60,6 +60,16 @@ export const REALM_DATA = {
     ragnaros: "Ragnaros",
     frostmourne: "Frostmourne",
   },
+  tw: {
+    maraudon: "Maraudon",
+    ivus: "Ivus",
+    wushoolay: "Wushoolay",
+    zeliek: "Zeliek",
+    "arathi-basin": "Arathi Basin",
+    murloc: "Murloc",
+    golemagg: "Golemagg",
+    windseeker: "Windseeker",
+  },
 } as const;
 
 export type Region = keyof typeof REALM_DATA;

diff --git a/web/src/lib/realms.ts b/web/src
/lib/realms.ts
index 1bdb222..fd2e987 100644
--- a/web/src/lib/realms.ts
+++ b/web/src/lib/realms.ts
@@ -60,6 +60,16 @@ export const REALM_DATA =
 {
     ragnaros: "Ragnaros",
     frostmourne: "Frostmourne",
   },
+  tw: {
+    maraudon: "Maraudon",
+    ivus: "Ivus",
+    wushoolay: "Wushoolay",
+    zeliek: "Zeliek",
+    "arathi-basin": "Arathi Basin",
+    murloc: "Murloc",
+    golemagg: "Golemagg",
+    windseeker: "Windseeker",
+  },
 } as const;
 
 export type Region = keyof typeof REALM_DAT
A;
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET