OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      206da8556966
DATE      2026-05-06
SUBJECT   ookstats: cross-season total runs leaderboard
FILES     3 CHANGED
HASH      206da8556966
DATE      2026-05-06
SUBJECT   ookstats: cross-season total runs
          leaderboard
FILES     3 CHANGED
 

diff --git a/nix/pkgs/ookstats/src/cmd/generate.go b/nix/pkgs/ookstats/src/cmd/gen
erate.go
index 89ed309..ffba9f3 100644
--- a/nix/pkgs/ookstats/src/cmd/generate.go
+++ b/nix/pkgs/ookstats/src/cmd/generate.go
@@ -56,21 +56,16 @@ var generateAPICmd = &cobra.Command{
 		}
 
 		if doLeaderboards {
-			regions := []string{}
-			if strings.TrimSpace(regionsCSV) != "" {
-				for _, r := range strings.Split(regionsCSV, ",") {
-					rr := strings.TrimSpace(r)
-					if rr != "" {
-						regions = append(regions, rr)
-					}
-				}
-			}
+			regions := parseRegions(regionsCSV)
 			if err := generator.GenerateLeaderboards(db, filepath.Join(base, "leaderboard"
), pageSize, regions, workers); err != nil {
 				return err
 			}
 			if err := generator.GeneratePlayerLeaderboards(db, filepath.Join(base, "leader
board"), pageSize, regions, workers); err != nil {
 				return err
 			}
+			if err := generator.GenerateTotalRunsLeaderboard(db, filepath.Join(base, "lead
erboard"), pageSize, regions, workers); err != nil {
+				return err
+			}
 		}
 
 		if doSearch {
@@ -142,6 +137,84 @@ var generateStatsCmd = &cobra.Command{
 	},
 }
 
+var generatePlayerLeaderboardsCmd = &cobra.Command{
+	Use:   "player-leaderboards",
+	Short: "Generate the per-season player leaderboard JSON (Overall Time, all scope
s)",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		outDir, _ := cmd.Flags().GetString("out")
+		pageSize, _ := cmd.Flags().GetInt("page-size")
+		regionsCSV, _ := cmd.Flags().GetString("regions")
+		workers, _ := cmd.Flags().GetInt("workers")
+
+		if strings.TrimSpace(outDir) == "" {
+			return errors.New("--out is required")
+		}
+		db, err := database.Connect()
+		if err != nil {
+			return fmt.Errorf("failed to connect to db: %w", err)
+		}
+		defer db.Close()
+
+		base := filepath.Join(outDir, "api", "leaderboard")
+		if err := os.MkdirAll(base, 0o755); err != nil {
+			return fmt.Errorf("mkdir base: %w", err)
+		}
+
+		regions := parseRegions(regionsCSV)
+		if err := generator.GeneratePlayerLeaderboards(db, base, pageSize, regions, wor
kers); err != nil {
+			return err
+		}
+		fmt.Printf("\nPer-season player leaderboards generated at %s/season/<id>/player
s/...\n", base)
+		return nil
+	},
+}
+
+var generateTotalRunsLeaderboardCmd = &cobra.Command{
+	Use:   "total-runs-leaderboard",
+	Short: "Generate the cross-season Total Runs leaderboard JSON (all scopes)",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		outDir, _ := cmd.Flags().GetString("out")
+		pageSize, _ := cmd.Flags().GetInt("page-size")
+		regionsCSV, _ := cmd.Flags().GetString("regions")
+		workers, _ := cmd.Flags().GetInt("workers")
+
+		if strings.TrimSpace(outDir) == "" {
+			return errors.New("--out is required")
+		}
+		db, err := database.Connect()
+		if err != nil {
+			return fmt.Errorf("failed to connect to db: %w", err)
+		}
+		defer db.Close()
+
+		base := filepath.Join(outDir, "api", "leaderboard")
+		if err := os.MkdirAll(base, 0o755); err != nil {
+			return fmt.Errorf("mkdir base: %w", err)
+		}
+
+		regions := parseRegions(regionsCSV)
+		if err := generator.GenerateTotalRunsLeaderboard(db, base, pageSize, regions, w
orkers); err != nil {
+			return err
+		}
+		fmt.Printf("\nTotal Runs leaderboard generated at %s/players/total-runs/...\n",
 base)
+		return nil
+	},
+}
+
+func parseRegions(csv string) []string {
+	out := []string{}
+	if strings.TrimSpace(csv) == "" {
+		return out
+	}
+	for _, r := range strings.Split(csv, ",") {
+		rr := strings.TrimSpace(r)
+		if rr != "" {
+			out = append(out, rr)
+		}
+	}
+	return out
+}
+
 var generateGearCmd = &cobra.Command{
 	Use:   "gear",
 	Short: "Generate gear popularity JSON (per-spec top items per slot, validated by
 spec primary stat)",
@@ -189,4 +262,16 @@ func init() {
 
 	generateCmd.AddCommand(generateGearCmd)
 	generateGearCmd.Flags().String("out", "web/public", "Output directory (api/gear.
json will be written under it)")
+
+	generateCmd.AddCommand(generatePlayerLeaderboardsCmd)
+	generatePlayerLeaderboardsCmd.Flags().String("out", "web/public", "Output direct
ory (api/leaderboard/... will be written under it)")
+	generatePlayerLeaderboardsCmd.Flags().Int("page-size", 25, "Leaderboard page siz
e")
+	generatePlayerLeaderboardsCmd.Flags().String("regions", "us,eu,kr,tw", "Regions 
to include for regional/realm/class leaderboards")
+	generatePlayerLeaderboardsCmd.Flags().Int("workers", 10, "Number of parallel wor
kers for leaderboard generation")
+
+	generateCmd.AddCommand(generateTotalRunsLeaderboardCmd)
+	generateTotalRunsLeaderboardCmd.Flags().String("out", "web/public", "Output dire
ctory (api/leaderboard/players/total-runs/... will be written under it)")
+	generateTotalRunsLeaderboardCmd.Flags().Int("page-size", 25, "Leaderboard page s
ize")
+	generateTotalRunsLeaderboardCmd.Flags().String("regions", "us,eu,kr,tw", "Region
s to include for regional/realm/class leaderboards")
+	generateTotalRunsLeaderboardCmd.Flags().Int("workers", 10, "Number of parallel w
orkers for leaderboard generation")
 }

diff --git a/nix/pkgs/ookstats/src/cmd/gener
ate.go b/nix/pkgs/ookstats/src/cmd/generate.
go
index 89ed309..ffba9f3 100644
--- a/nix/pkgs/ookstats/src/cmd/generate.go
+++ b/nix/pkgs/ookstats/src/cmd/generate.go
@@ -56,21 +56,16 @@ var generateAPICmd = &co
bra.Command{
 		}
 
 		if doLeaderboards {
-			regions := []string{}
-			if strings.TrimSpace(regionsCSV) != "" {
-				for _, r := range strings.Split(regions
CSV, ",") {
-					rr := strings.TrimSpace(r)
-					if rr != "" {
-						regions = append(regions, rr)
-					}
-				}
-			}
+			regions := parseRegions(regionsCSV)
 			if err := generator.GenerateLeaderboards
(db, filepath.Join(base, "leaderboard"), pag
eSize, regions, workers); err != nil {
 				return err
 			}
 			if err := generator.GeneratePlayerLeader
boards(db, filepath.Join(base, "leaderboard"
), pageSize, regions, workers); err != nil {
 				return err
 			}
+			if err := generator.GenerateTotalRunsLea
derboard(db, filepath.Join(base, "leaderboar
d"), pageSize, regions, workers); err != nil
 {
+				return err
+			}
 		}
 
 		if doSearch {
@@ -142,6 +137,84 @@ var generateStatsCmd = 
&cobra.Command{
 	},
 }
 
+var generatePlayerLeaderboardsCmd = &cobra.
Command{
+	Use:   "player-leaderboards",
+	Short: "Generate the per-season player lea
derboard JSON (Overall Time, all scopes)",
+	RunE: func(cmd *cobra.Command, args []stri
ng) error {
+		outDir, _ := cmd.Flags().GetString("out")
+		pageSize, _ := cmd.Flags().GetInt("page-s
ize")
+		regionsCSV, _ := cmd.Flags().GetString("r
egions")
+		workers, _ := cmd.Flags().GetInt("workers
")
+
+		if strings.TrimSpace(outDir) == "" {
+			return errors.New("--out is required")
+		}
+		db, err := database.Connect()
+		if err != nil {
+			return fmt.Errorf("failed to connect to 
db: %w", err)
+		}
+		defer db.Close()
+
+		base := filepath.Join(outDir, "api", "lea
derboard")
+		if err := os.MkdirAll(base, 0o755); err !
= nil {
+			return fmt.Errorf("mkdir base: %w", err)
+		}
+
+		regions := parseRegions(regionsCSV)
+		if err := generator.GeneratePlayerLeaderb
oards(db, base, pageSize, regions, workers);
 err != nil {
+			return err
+		}
+		fmt.Printf("\nPer-season player leaderboa
rds generated at %s/season/<id>/players/...\
n", base)
+		return nil
+	},
+}
+
+var generateTotalRunsLeaderboardCmd = &cobr
a.Command{
+	Use:   "total-runs-leaderboard",
+	Short: "Generate the cross-season Total Ru
ns leaderboard JSON (all scopes)",
+	RunE: func(cmd *cobra.Command, args []stri
ng) error {
+		outDir, _ := cmd.Flags().GetString("out")
+		pageSize, _ := cmd.Flags().GetInt("page-s
ize")
+		regionsCSV, _ := cmd.Flags().GetString("r
egions")
+		workers, _ := cmd.Flags().GetInt("workers
")
+
+		if strings.TrimSpace(outDir) == "" {
+			return errors.New("--out is required")
+		}
+		db, err := database.Connect()
+		if err != nil {
+			return fmt.Errorf("failed to connect to 
db: %w", err)
+		}
+		defer db.Close()
+
+		base := filepath.Join(outDir, "api", "lea
derboard")
+		if err := os.MkdirAll(base, 0o755); err !
= nil {
+			return fmt.Errorf("mkdir base: %w", err)
+		}
+
+		regions := parseRegions(regionsCSV)
+		if err := generator.GenerateTotalRunsLead
erboard(db, base, pageSize, regions, workers
); err != nil {
+			return err
+		}
+		fmt.Printf("\nTotal Runs leaderboard gene
rated at %s/players/total-runs/...\n", base)
+		return nil
+	},
+}
+
+func parseRegions(csv string) []string {
+	out := []string{}
+	if strings.TrimSpace(csv) == "" {
+		return out
+	}
+	for _, r := range strings.Split(csv, ",") 
{
+		rr := strings.TrimSpace(r)
+		if rr != "" {
+			out = append(out, rr)
+		}
+	}
+	return out
+}
+
 var generateGearCmd = &cobra.Command{
 	Use:   "gear",
 	Short: "Generate gear popularity JSON (per
-spec top items per slot, validated by spec 
primary stat)",
@@ -189,4 +262,16 @@ func init() {
 
 	generateCmd.AddCommand(generateGearCmd)
 	generateGearCmd.Flags().String("out", "web
/public", "Output directory (api/gear.json w
ill be written under it)")
+
+	generateCmd.AddCommand(generatePlayerLeade
rboardsCmd)
+	generatePlayerLeaderboardsCmd.Flags().Stri
ng("out", "web/public", "Output directory (a
pi/leaderboard/... will be written under it)
")
+	generatePlayerLeaderboardsCmd.Flags().Int(
"page-size", 25, "Leaderboard page size")
+	generatePlayerLeaderboardsCmd.Flags().Stri
ng("regions", "us,eu,kr,tw", "Regions to inc
lude for regional/realm/class leaderboards")
+	generatePlayerLeaderboardsCmd.Flags().Int(
"workers", 10, "Number of parallel workers f
or leaderboard generation")
+
+	generateCmd.AddCommand(generateTotalRunsLe
aderboardCmd)
+	generateTotalRunsLeaderboardCmd.Flags().St
ring("out", "web/public", "Output directory 
(api/leaderboard/players/total-runs/... will
 be written under it)")
+	generateTotalRunsLeaderboardCmd.Flags().In
t("page-size", 25, "Leaderboard page size")
+	generateTotalRunsLeaderboardCmd.Flags().St
ring("regions", "us,eu,kr,tw", "Regions to i
nclude for regional/realm/class leaderboards
")
+	generateTotalRunsLeaderboardCmd.Flags().In
t("workers", 10, "Number of parallel workers
 for leaderboard generation")
 }
 

diff --git a/nix/pkgs/ookstats/src/internal/generator/players.go b/nix/pkgs/ooksta
ts/src/internal/generator/players.go
index 95620a2..72f8daf 100644
--- a/nix/pkgs/ookstats/src/internal/generator/players.go
+++ b/nix/pkgs/ookstats/src/internal/generator/players.go
@@ -28,6 +28,7 @@ type PlayerJSON struct {
 	RaceName          string                      `json:"race_name,omitempty"`
 	AverageItemLevel  *int                        `json:"average_item_level,omitempt
y"`
 	EquippedItemLevel *int                        `json:"equipped_item_level,omitemp
ty"`
+	AllTimeTotalRuns  int                         `json:"all_time_total_runs"`
 	Seasons           map[string]PlayerSeasonJSON `json:"seasons"`
 }
 
@@ -218,8 +219,8 @@ func generateSinglePlayerJSON(player loader.PlayerData, player
SeasonsMap map[int
 		pj.EquippedItemLevel = &v
 	}
 
-	// Build seasons data
 	for _, seasonData := range playerSeasonsMap[player.ID] {
+		pj.AllTimeTotalRuns += seasonData.TotalRuns
 		seasonJSON := PlayerSeasonJSON{
 			DungeonsCompleted: seasonData.DungeonsCompleted,
 			TotalRuns:         seasonData.TotalRuns,

diff --git a/nix/pkgs/ookstats/src/internal/
generator/players.go b/nix/pkgs/ookstats/src
/internal/generator/players.go
index 95620a2..72f8daf 100644
--- a/nix/pkgs/ookstats/src/internal/generat
or/players.go
+++ b/nix/pkgs/ookstats/src/internal/generat
or/players.go
@@ -28,6 +28,7 @@ type PlayerJSON struct {
 	RaceName          string                  
    `json:"race_name,omitempty"`
 	AverageItemLevel  *int                    
    `json:"average_item_level,omitempty"`
 	EquippedItemLevel *int                    
    `json:"equipped_item_level,omitempty"`
+	AllTimeTotalRuns  int                     
    `json:"all_time_total_runs"`
 	Seasons           map[string]PlayerSeasonJ
SON `json:"seasons"`
 }
 
@@ -218,8 +219,8 @@ func generateSinglePlaye
rJSON(player loader.PlayerData, playerSeason
sMap map[int
 		pj.EquippedItemLevel = &v
 	}
 
-	// Build seasons data
 	for _, seasonData := range playerSeasonsMa
p[player.ID] {
+		pj.AllTimeTotalRuns += seasonData.TotalRu
ns
 		seasonJSON := PlayerSeasonJSON{
 			DungeonsCompleted: seasonData.DungeonsCo
mpleted,
 			TotalRuns:         seasonData.TotalRuns,
 

diff --git a/nix/pkgs/ookstats/src/internal/generator/total_runs_leaderboard.go b/
nix/pkgs/ookstats/src/internal/generator/total_runs_leaderboard.go
new file mode 100644
index 0000000..b5677dc
--- /dev/null
+++ b/nix/pkgs/ookstats/src/internal/generator/total_runs_leaderboard.go
@@ -0,0 +1,463 @@
+package generator
+
+import (
+	"database/sql"
+	"fmt"
+	"ookstats/internal/wow"
+	"ookstats/internal/writer"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+	"sync/atomic"
+)
+
+// cross-season total runs: SUM(pp.total_runs) per character, gated by
+// has_complete_coverage = 1 in any season (kept loose so a top grinder
+// isn't dropped for skipping one dungeon in the latest season).
+
+type totalRunsJob struct {
+	scope     string
+	region    string
+	realmSlug string
+	classKey  string
+	out       string
+	pageSize  int
+	regions   []string
+}
+
+// writes to <out>/players/total-runs/...
+func GenerateTotalRunsLeaderboard(db *sql.DB, out string, pageSize int, regions [
]string, workers int) error {
+	if pageSize <= 0 {
+		pageSize = 25
+	}
+	if workers <= 0 {
+		workers = 10
+	}
+	if len(regions) == 0 {
+		regions = []string{"us", "eu", "kr", "tw"}
+	}
+
+	root := filepath.Join(out, "players", "total-runs")
+	// wipe so realms dropping out of the data don't leave stale JSON
+	if err := os.RemoveAll(root); err != nil {
+		return fmt.Errorf("clean total-runs tree: %w", err)
+	}
+
+	realmSlugs := make(map[string][]string)
+	for _, reg := range regions {
+		rrows, err := db.Query(`
+			SELECT slug
+			FROM realms
+			WHERE region = ? AND (parent_realm_slug IS NULL OR parent_realm_slug = '')
+			ORDER BY slug
+		`, reg)
+		if err != nil {
+			return fmt.Errorf("load realm slugs: %w", err)
+		}
+		var slugs []string
+		for rrows.Next() {
+			var s string
+			if err := rrows.Scan(&s); err != nil {
+				rrows.Close()
+				return err
+			}
+			slugs = append(slugs, s)
+		}
+		rrows.Close()
+		realmSlugs[reg] = slugs
+	}
+
+	classKeys := []string{"death_knight", "druid", "hunter", "mage", "monk", "paladi
n", "priest", "rogue", "shaman", "warlock", "warrior"}
+
+	totalJobs := 1
+	totalJobs += len(regions)
+	for _, reg := range regions {
+		totalJobs += len(realmSlugs[reg])
+	}
+	totalJobs += len(classKeys)
+
+	fmt.Printf("Generating Total Runs leaderboard with %d workers (%d total jobs)...
\n", workers, totalJobs)
+
+	jobs := make(chan totalRunsJob, 100)
+	var firstErr atomic.Value
+	var completed atomic.Int64
+	var wg sync.WaitGroup
+
+	for i := 0; i < workers; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for job := range jobs {
+				if firstErr.Load() != nil {
+					continue
+				}
+				var err error
+				switch job.scope {
+				case "global":
+					err = generateTotalRunsGlobal(db, job.out, job.pageSize)
+				case "regional":
+					err = generateTotalRunsRegional(db, job.out, job.region, job.pageSize)
+				case "realm":
+					err = generateTotalRunsRealm(db, job.out, job.region, job.realmSlug, job.pag
eSize)
+				case "class":
+					err = generateTotalRunsClass(db, job.out, job.classKey, job.pageSize, job.re
gions)
+				}
+				if err != nil {
+					firstErr.CompareAndSwap(nil, err)
+					continue
+				}
+				c := completed.Add(1)
+				if c%20 == 0 {
+					fmt.Printf("  ... %d/%d total-runs leaderboards generated\n", c, totalJobs)
+				}
+			}
+		}()
+	}
+
+	jobs <- totalRunsJob{scope: "global", out: root, pageSize: pageSize}
+	for _, reg := range regions {
+		jobs <- totalRunsJob{scope: "regional", region: reg, out: root, pageSize: pageS
ize}
+	}
+	for _, reg := range regions {
+		for _, rslug := range realmSlugs[reg] {
+			jobs <- totalRunsJob{scope: "realm", region: reg, realmSlug: rslug, out: root,
 pageSize: pageSize}
+		}
+	}
+	for _, cls := range classKeys {
+		jobs <- totalRunsJob{scope: "class", classKey: cls, out: root, pageSize: pageSi
ze, regions: regions}
+	}
+	close(jobs)
+	wg.Wait()
+
+	if err := firstErr.Load(); err != nil {
+		return err.(error)
+	}
+	fmt.Printf("\n[OK] Generated %d total-runs leaderboards\n", completed.Load())
+	return nil
+}
+
+func totalRunsBaseSelect() string {
+	return `
+		SELECT p.id,
+		       p.name,
+		       r.slug         AS realm_slug,
+		       r.name         AS realm_name,
+		       r.region,
+		       COALESCE(pd.class_name, '')       AS class_name,
+		       COALESCE(pd.active_spec_name, '') AS active_spec_name,
+		       MAX(pp.main_spec_id)              AS main_spec_id,
+		       SUM(pp.total_runs)                AS all_time_runs
+		FROM players p
+		JOIN realms r ON p.realm_id = r.id
+		JOIN player_profiles pp ON p.id = pp.player_id
+		LEFT JOIN player_details pd ON p.id = pd.player_id
+	`
+}
+
+const totalRunsHaving = `
+	GROUP BY p.id, p.name, r.slug, r.name, r.region, pd.class_name, pd.active_spec_n
ame
+	HAVING MAX(pp.has_complete_coverage) = 1 AND SUM(pp.total_runs) > 0
+`
+
+func generateTotalRunsGlobal(db *sql.DB, root string, pageSize int) error {
+	dir := filepath.Join(root, "global")
+	if err := os.MkdirAll(dir, 0o755); err != nil {
+		return err
+	}
+
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN player_profiles pp ON p.id = pp.player_id
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1 AND SUM(pp.total_runs) > 0
+		)
+	`).Scan(&total); err != nil {
+		return fmt.Errorf("total-runs count (global): %w", err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect()+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, pageSize, offset)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		page := buildTotalRunsPage(list, "Global Total Runs", total, pages, p, pageSize
)
+		if err := writer.WriteJSONFileCompact(filepath.Join(dir, fmt.Sprintf("%d.json",
 p)), page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsRegional(db *sql.DB, root, region string, pageSize int) err
or {
+	dir := filepath.Join(root, "regional", region)
+	if err := os.MkdirAll(dir, 0o755); err != nil {
+		return err
+	}
+
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN realms r ON p.realm_id = r.id
+			JOIN player_profiles pp ON p.id = pp.player_id
+			WHERE r.region = ?
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1 AND SUM(pp.total_runs) > 0
+		)
+	`, region).Scan(&total); err != nil {
+		return fmt.Errorf("total-runs count (regional %s): %w", region, err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect()+`
+			WHERE r.region = ?
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, region, pageSize, offset)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		title := strings.ToUpper(region) + " Total Runs"
+		page := buildTotalRunsPage(list, title, total, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(filepath.Join(dir, fmt.Sprintf("%d.json",
 p)), page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsRealm(db *sql.DB, root, region, rslug string, pageSize int)
 error {
+	dir := filepath.Join(root, "realm", region, rslug)
+	if err := os.MkdirAll(dir, 0o755); err != nil {
+		return err
+	}
+
+	// pool = parent + child realms (matches per-season realm leaderboard)
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN realms r ON p.realm_id = r.id
+			JOIN player_profiles pp ON p.id = pp.player_id
+			WHERE r.region = ? AND (r.slug = ? OR r.parent_realm_slug = ?)
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1 AND SUM(pp.total_runs) > 0
+		)
+	`, region, rslug, rslug).Scan(&total); err != nil {
+		return fmt.Errorf("total-runs count (realm %s/%s): %w", region, rslug, err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect()+`
+			WHERE r.region = ? AND (r.slug = ? OR r.parent_realm_slug = ?)
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, region, rslug, rslug, pageSize, offset)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		title := strings.ToUpper(region) + "/" + rslug + " Total Runs"
+		page := buildTotalRunsPage(list, title, total, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(filepath.Join(dir, fmt.Sprintf("%d.json",
 p)), page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// filters in Go so we can reuse the wow.GetClassAndSpec fallback when
+// pd.class_name is missing
+func generateTotalRunsClass(db *sql.DB, root, classKey string, pageSize int, regi
ons []string) error {
+	if err := generateTotalRunsClassScope(db, root, "global", "", "", classKey, page
Size); err != nil {
+		return err
+	}
+	for _, reg := range regions {
+		if err := generateTotalRunsClassScope(db, root, "regional", reg, "", classKey, 
pageSize); err != nil {
+			return err
+		}
+		rrows, err := db.Query(`
+			SELECT slug
+			FROM realms
+			WHERE region = ? AND (parent_realm_slug IS NULL OR parent_realm_slug = '')
+			ORDER BY slug
+		`, reg)
+		if err != nil {
+			return fmt.Errorf("total-runs class realms list: %w", err)
+		}
+		var slugs []string
+		for rrows.Next() {
+			var s string
+			if err := rrows.Scan(&s); err != nil {
+				rrows.Close()
+				return err
+			}
+			slugs = append(slugs, s)
+		}
+		rrows.Close()
+		for _, rslug := range slugs {
+			if err := generateTotalRunsClassScope(db, root, "realm", reg, rslug, classKey,
 pageSize); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsClassScope(db *sql.DB, root, scope, region, rslug, classKey
 string, pageSize int) error {
+	var dir string
+	switch scope {
+	case "global":
+		dir = filepath.Join(root, "class", classKey, "global")
+	case "regional":
+		dir = filepath.Join(root, "class", classKey, "regional", region)
+	default:
+		dir = filepath.Join(root, "class", classKey, "realm", region, rslug)
+	}
+	if err := os.MkdirAll(dir, 0o755); err != nil {
+		return err
+	}
+
+	var rows *sql.Rows
+	var err error
+	switch scope {
+	case "global":
+		rows, err = db.Query(totalRunsBaseSelect() + totalRunsHaving + `
+			ORDER BY all_time_runs DESC, p.name ASC
+		`)
+	case "regional":
+		rows, err = db.Query(totalRunsBaseSelect()+`
+			WHERE r.region = ?
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+		`, region)
+	default:
+		rows, err = db.Query(totalRunsBaseSelect()+`
+			WHERE r.region = ? AND (r.slug = ? OR r.parent_realm_slug = ?)
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+		`, region, rslug, rslug)
+	}
+	if err != nil {
+		return err
+	}
+	all, err := scanTotalRunsRows(rows)
+	if err != nil {
+		return err
+	}
+
+	matching := make([]map[string]any, 0, len(all)/4)
+	for _, r := range all {
+		cls, _ := r["class_name"].(string)
+		key := strings.ReplaceAll(strings.ToLower(cls), " ", "_")
+		if key == classKey {
+			matching = append(matching, r)
+		}
+	}
+
+	total := len(matching)
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		end := offset + pageSize
+		if end > total {
+			end = total
+		}
+		title := "Global Total Runs"
+		switch scope {
+		case "regional":
+			title = strings.ToUpper(region) + " Total Runs"
+		case "realm":
+			title = strings.ToUpper(region) + "/" + rslug + " Total Runs"
+		}
+		page := buildTotalRunsPage(matching[offset:end], title, total, pages, p, pageSi
ze)
+		if err := writer.WriteJSONFileCompact(filepath.Join(dir, fmt.Sprintf("%d.json",
 p)), page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// field names mirror scanPlayerRows so the frontend table component can
+// render either tree without branching
+func scanTotalRunsRows(rows *sql.Rows) ([]map[string]any, error) {
+	defer rows.Close()
+	var out []map[string]any
+	for rows.Next() {
+		var (
+			id                                int64
+			name, realmSlug, realmName        string
+			region, className, activeSpecName string
+			mainSpecID                        sql.NullInt64
+			allTimeRuns                       sql.NullInt64
+		)
+		if err := rows.Scan(&id, &name, &realmSlug, &realmName, &region, &className, &a
ctiveSpecName, &mainSpecID, &allTimeRuns); err != nil {
+			return nil, err
+		}
+		obj := map[string]any{
+			"player_id":  id,
+			"name":       name,
+			"realm_slug": realmSlug,
+			"realm_name": realmName,
+			"region":     region,
+			"class_name": className,
+			"total_runs": allTimeRuns.Int64,
+		}
+		if mainSpecID.Valid {
+			v := int(mainSpecID.Int64)
+			cls, spec := wow.FallbackClassAndSpec(className, activeSpecName, &v)
+			obj["class_name"] = cls
+			obj["active_spec_name"] = spec
+			obj["main_spec_id"] = v
+		} else if activeSpecName != "" {
+			obj["active_spec_name"] = activeSpecName
+		}
+		out = append(out, obj)
+	}
+	return out, nil
+}
+
+// shape mirrors buildPlayerLeaderboardPage so Pagination and the table
+// component can render either tree without branching
+func buildTotalRunsPage(list []map[string]any, title string, total, totalPages, c
urrentPage, pageSize int) map[string]any {
+	return map[string]any{
+		"leaderboard": list,
+		"title":       title,
+		"pagination": map[string]any{
+			"currentPage":  currentPage,
+			"pageSize":     pageSize,
+			"totalPlayers": total,
+			"totalPages":   totalPages,
+			"hasNextPage":  currentPage < totalPages,
+			"hasPrevPage":  currentPage > 1,
+		},
+	}
+}

diff --git a/nix/pkgs/ookstats/src/internal/
generator/total_runs_leaderboard.go b/nix/pk
gs/ookstats/src/internal/generator/total_run
s_leaderboard.go
new file mode 100644
index 0000000..b5677dc
--- /dev/null
+++ b/nix/pkgs/ookstats/src/internal/generat
or/total_runs_leaderboard.go
@@ -0,0 +1,463 @@
+package generator
+
+import (
+	"database/sql"
+	"fmt"
+	"ookstats/internal/wow"
+	"ookstats/internal/writer"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+	"sync/atomic"
+)
+
+// cross-season total runs: SUM(pp.total_ru
ns) per character, gated by
+// has_complete_coverage = 1 in any season 
(kept loose so a top grinder
+// isn't dropped for skipping one dungeon i
n the latest season).
+
+type totalRunsJob struct {
+	scope     string
+	region    string
+	realmSlug string
+	classKey  string
+	out       string
+	pageSize  int
+	regions   []string
+}
+
+// writes to <out>/players/total-runs/...
+func GenerateTotalRunsLeaderboard(db *sql.D
B, out string, pageSize int, regions []strin
g, workers int) error {
+	if pageSize <= 0 {
+		pageSize = 25
+	}
+	if workers <= 0 {
+		workers = 10
+	}
+	if len(regions) == 0 {
+		regions = []string{"us", "eu", "kr", "tw"
}
+	}
+
+	root := filepath.Join(out, "players", "tot
al-runs")
+	// wipe so realms dropping out of the data
 don't leave stale JSON
+	if err := os.RemoveAll(root); err != nil {
+		return fmt.Errorf("clean total-runs tree:
 %w", err)
+	}
+
+	realmSlugs := make(map[string][]string)
+	for _, reg := range regions {
+		rrows, err := db.Query(`
+			SELECT slug
+			FROM realms
+			WHERE region = ? AND (parent_realm_slug 
IS NULL OR parent_realm_slug = '')
+			ORDER BY slug
+		`, reg)
+		if err != nil {
+			return fmt.Errorf("load realm slugs: %w"
, err)
+		}
+		var slugs []string
+		for rrows.Next() {
+			var s string
+			if err := rrows.Scan(&s); err != nil {
+				rrows.Close()
+				return err
+			}
+			slugs = append(slugs, s)
+		}
+		rrows.Close()
+		realmSlugs[reg] = slugs
+	}
+
+	classKeys := []string{"death_knight", "dru
id", "hunter", "mage", "monk", "paladin", "p
riest", "rogue", "shaman", "warlock", "warri
or"}
+
+	totalJobs := 1
+	totalJobs += len(regions)
+	for _, reg := range regions {
+		totalJobs += len(realmSlugs[reg])
+	}
+	totalJobs += len(classKeys)
+
+	fmt.Printf("Generating Total Runs leaderbo
ard with %d workers (%d total jobs)...\n", w
orkers, totalJobs)
+
+	jobs := make(chan totalRunsJob, 100)
+	var firstErr atomic.Value
+	var completed atomic.Int64
+	var wg sync.WaitGroup
+
+	for i := 0; i < workers; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for job := range jobs {
+				if firstErr.Load() != nil {
+					continue
+				}
+				var err error
+				switch job.scope {
+				case "global":
+					err = generateTotalRunsGlobal(db, job.
out, job.pageSize)
+				case "regional":
+					err = generateTotalRunsRegional(db, jo
b.out, job.region, job.pageSize)
+				case "realm":
+					err = generateTotalRunsRealm(db, job.o
ut, job.region, job.realmSlug, job.pageSize)
+				case "class":
+					err = generateTotalRunsClass(db, job.o
ut, job.classKey, job.pageSize, job.regions)
+				}
+				if err != nil {
+					firstErr.CompareAndSwap(nil, err)
+					continue
+				}
+				c := completed.Add(1)
+				if c%20 == 0 {
+					fmt.Printf("  ... %d/%d total-runs lea
derboards generated\n", c, totalJobs)
+				}
+			}
+		}()
+	}
+
+	jobs <- totalRunsJob{scope: "global", out:
 root, pageSize: pageSize}
+	for _, reg := range regions {
+		jobs <- totalRunsJob{scope: "regional", r
egion: reg, out: root, pageSize: pageSize}
+	}
+	for _, reg := range regions {
+		for _, rslug := range realmSlugs[reg] {
+			jobs <- totalRunsJob{scope: "realm", reg
ion: reg, realmSlug: rslug, out: root, pageS
ize: pageSize}
+		}
+	}
+	for _, cls := range classKeys {
+		jobs <- totalRunsJob{scope: "class", clas
sKey: cls, out: root, pageSize: pageSize, re
gions: regions}
+	}
+	close(jobs)
+	wg.Wait()
+
+	if err := firstErr.Load(); err != nil {
+		return err.(error)
+	}
+	fmt.Printf("\n[OK] Generated %d total-runs
 leaderboards\n", completed.Load())
+	return nil
+}
+
+func totalRunsBaseSelect() string {
+	return `
+		SELECT p.id,
+		       p.name,
+		       r.slug         AS realm_slug,
+		       r.name         AS realm_name,
+		       r.region,
+		       COALESCE(pd.class_name, '')       
AS class_name,
+		       COALESCE(pd.active_spec_name, '') 
AS active_spec_name,
+		       MAX(pp.main_spec_id)              
AS main_spec_id,
+		       SUM(pp.total_runs)                
AS all_time_runs
+		FROM players p
+		JOIN realms r ON p.realm_id = r.id
+		JOIN player_profiles pp ON p.id = pp.play
er_id
+		LEFT JOIN player_details pd ON p.id = pd.
player_id
+	`
+}
+
+const totalRunsHaving = `
+	GROUP BY p.id, p.name, r.slug, r.name, r.r
egion, pd.class_name, pd.active_spec_name
+	HAVING MAX(pp.has_complete_coverage) = 1 A
ND SUM(pp.total_runs) > 0
+`
+
+func generateTotalRunsGlobal(db *sql.DB, ro
ot string, pageSize int) error {
+	dir := filepath.Join(root, "global")
+	if err := os.MkdirAll(dir, 0o755); err != 
nil {
+		return err
+	}
+
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN player_profiles pp ON p.id = pp.pla
yer_id
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1
 AND SUM(pp.total_runs) > 0
+		)
+	`).Scan(&total); err != nil {
+		return fmt.Errorf("total-runs count (glob
al): %w", err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect
()+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, pageSize, offset)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		page := buildTotalRunsPage(list, "Global 
Total Runs", total, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(fil
epath.Join(dir, fmt.Sprintf("%d.json", p)), 
page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsRegional(db *sql.DB, 
root, region string, pageSize int) error {
+	dir := filepath.Join(root, "regional", reg
ion)
+	if err := os.MkdirAll(dir, 0o755); err != 
nil {
+		return err
+	}
+
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN realms r ON p.realm_id = r.id
+			JOIN player_profiles pp ON p.id = pp.pla
yer_id
+			WHERE r.region = ?
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1
 AND SUM(pp.total_runs) > 0
+		)
+	`, region).Scan(&total); err != nil {
+		return fmt.Errorf("total-runs count (regi
onal %s): %w", region, err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect
()+`
+			WHERE r.region = ?
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, region, pageSize, offset)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		title := strings.ToUpper(region) + " Tota
l Runs"
+		page := buildTotalRunsPage(list, title, t
otal, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(fil
epath.Join(dir, fmt.Sprintf("%d.json", p)), 
page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsRealm(db *sql.DB, roo
t, region, rslug string, pageSize int) error
 {
+	dir := filepath.Join(root, "realm", region
, rslug)
+	if err := os.MkdirAll(dir, 0o755); err != 
nil {
+		return err
+	}
+
+	// pool = parent + child realms (matches p
er-season realm leaderboard)
+	var total int
+	if err := db.QueryRow(`
+		SELECT COUNT(*) FROM (
+			SELECT 1
+			FROM players p
+			JOIN realms r ON p.realm_id = r.id
+			JOIN player_profiles pp ON p.id = pp.pla
yer_id
+			WHERE r.region = ? AND (r.slug = ? OR r.
parent_realm_slug = ?)
+			GROUP BY p.id
+			HAVING MAX(pp.has_complete_coverage) = 1
 AND SUM(pp.total_runs) > 0
+		)
+	`, region, rslug, rslug).Scan(&total); err
 != nil {
+		return fmt.Errorf("total-runs count (real
m %s/%s): %w", region, rslug, err)
+	}
+
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		rows, err := db.Query(totalRunsBaseSelect
()+`
+			WHERE r.region = ? AND (r.slug = ? OR r.
parent_realm_slug = ?)
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+			LIMIT ? OFFSET ?
+		`, region, rslug, rslug, pageSize, offset
)
+		if err != nil {
+			return err
+		}
+		list, err := scanTotalRunsRows(rows)
+		if err != nil {
+			return err
+		}
+		title := strings.ToUpper(region) + "/" + 
rslug + " Total Runs"
+		page := buildTotalRunsPage(list, title, t
otal, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(fil
epath.Join(dir, fmt.Sprintf("%d.json", p)), 
page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// filters in Go so we can reuse the wow.Ge
tClassAndSpec fallback when
+// pd.class_name is missing
+func generateTotalRunsClass(db *sql.DB, roo
t, classKey string, pageSize int, regions []
string) error {
+	if err := generateTotalRunsClassScope(db, 
root, "global", "", "", classKey, pageSize);
 err != nil {
+		return err
+	}
+	for _, reg := range regions {
+		if err := generateTotalRunsClassScope(db,
 root, "regional", reg, "", classKey, pageSi
ze); err != nil {
+			return err
+		}
+		rrows, err := db.Query(`
+			SELECT slug
+			FROM realms
+			WHERE region = ? AND (parent_realm_slug 
IS NULL OR parent_realm_slug = '')
+			ORDER BY slug
+		`, reg)
+		if err != nil {
+			return fmt.Errorf("total-runs class real
ms list: %w", err)
+		}
+		var slugs []string
+		for rrows.Next() {
+			var s string
+			if err := rrows.Scan(&s); err != nil {
+				rrows.Close()
+				return err
+			}
+			slugs = append(slugs, s)
+		}
+		rrows.Close()
+		for _, rslug := range slugs {
+			if err := generateTotalRunsClassScope(db
, root, "realm", reg, rslug, classKey, pageS
ize); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func generateTotalRunsClassScope(db *sql.DB
, root, scope, region, rslug, classKey strin
g, pageSize int) error {
+	var dir string
+	switch scope {
+	case "global":
+		dir = filepath.Join(root, "class", classK
ey, "global")
+	case "regional":
+		dir = filepath.Join(root, "class", classK
ey, "regional", region)
+	default:
+		dir = filepath.Join(root, "class", classK
ey, "realm", region, rslug)
+	}
+	if err := os.MkdirAll(dir, 0o755); err != 
nil {
+		return err
+	}
+
+	var rows *sql.Rows
+	var err error
+	switch scope {
+	case "global":
+		rows, err = db.Query(totalRunsBaseSelect(
) + totalRunsHaving + `
+			ORDER BY all_time_runs DESC, p.name ASC
+		`)
+	case "regional":
+		rows, err = db.Query(totalRunsBaseSelect(
)+`
+			WHERE r.region = ?
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+		`, region)
+	default:
+		rows, err = db.Query(totalRunsBaseSelect(
)+`
+			WHERE r.region = ? AND (r.slug = ? OR r.
parent_realm_slug = ?)
+		`+totalRunsHaving+`
+			ORDER BY all_time_runs DESC, p.name ASC
+		`, region, rslug, rslug)
+	}
+	if err != nil {
+		return err
+	}
+	all, err := scanTotalRunsRows(rows)
+	if err != nil {
+		return err
+	}
+
+	matching := make([]map[string]any, 0, len(
all)/4)
+	for _, r := range all {
+		cls, _ := r["class_name"].(string)
+		key := strings.ReplaceAll(strings.ToLower
(cls), " ", "_")
+		if key == classKey {
+			matching = append(matching, r)
+		}
+	}
+
+	total := len(matching)
+	pages := (total + pageSize - 1) / pageSize
+	for p := 1; p <= pages; p++ {
+		offset := (p - 1) * pageSize
+		end := offset + pageSize
+		if end > total {
+			end = total
+		}
+		title := "Global Total Runs"
+		switch scope {
+		case "regional":
+			title = strings.ToUpper(region) + " Tota
l Runs"
+		case "realm":
+			title = strings.ToUpper(region) + "/" + 
rslug + " Total Runs"
+		}
+		page := buildTotalRunsPage(matching[offse
t:end], title, total, pages, p, pageSize)
+		if err := writer.WriteJSONFileCompact(fil
epath.Join(dir, fmt.Sprintf("%d.json", p)), 
page); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// field names mirror scanPlayerRows so the
 frontend table component can
+// render either tree without branching
+func scanTotalRunsRows(rows *sql.Rows) ([]m
ap[string]any, error) {
+	defer rows.Close()
+	var out []map[string]any
+	for rows.Next() {
+		var (
+			id                                int64
+			name, realmSlug, realmName        string
+			region, className, activeSpecName string
+			mainSpecID                        sql.Nu
llInt64
+			allTimeRuns                       sql.Nu
llInt64
+		)
+		if err := rows.Scan(&id, &name, &realmSlu
g, &realmName, &region, &className, &activeS
pecName, &mainSpecID, &allTimeRuns); err != 
nil {
+			return nil, err
+		}
+		obj := map[string]any{
+			"player_id":  id,
+			"name":       name,
+			"realm_slug": realmSlug,
+			"realm_name": realmName,
+			"region":     region,
+			"class_name": className,
+			"total_runs": allTimeRuns.Int64,
+		}
+		if mainSpecID.Valid {
+			v := int(mainSpecID.Int64)
+			cls, spec := wow.FallbackClassAndSpec(cl
assName, activeSpecName, &v)
+			obj["class_name"] = cls
+			obj["active_spec_name"] = spec
+			obj["main_spec_id"] = v
+		} else if activeSpecName != "" {
+			obj["active_spec_name"] = activeSpecName
+		}
+		out = append(out, obj)
+	}
+	return out, nil
+}
+
+// shape mirrors buildPlayerLeaderboardPage
 so Pagination and the table
+// component can render either tree without
 branching
+func buildTotalRunsPage(list []map[string]a
ny, title string, total, totalPages, current
Page, pageSize int) map[string]any {
+	return map[string]any{
+		"leaderboard": list,
+		"title":       title,
+		"pagination": map[string]any{
+			"currentPage":  currentPage,
+			"pageSize":     pageSize,
+			"totalPlayers": total,
+			"totalPages":   totalPages,
+			"hasNextPage":  currentPage < totalPages
,
+			"hasPrevPage":  currentPage > 1,
+		},
+	}
+}
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET