Skip to content

Scoreboard Feature Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Frontend (Svelte/TS) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ /scoreboard β”‚ β”‚ Homepage section β”‚ β”‚
β”‚ β”‚ (Public) β”‚ β”‚ (random sample) β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ - Paginated table β”‚ β”‚ - Pipeline cards β”‚ β”‚
β”‚ β”‚ - Sortable columns β”‚ β”‚ - Success summary β”‚ β”‚
β”‚ β”‚ - Entity display β”‚ β”‚ - Entity links β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PocketBase API β”‚
β”‚ pipeline_scoreboard_ β”‚
β”‚ cache β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–²
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Backend (Go + Temporal) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ AggregateScoreboardWorkflow (Temporal) β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ 1. List org namespaces β”‚ β”‚
β”‚ β”‚ 2. GET /api/pipeline/scoreboard/{namespace} per tenant β”‚ β”‚
β”‚ β”‚ 3. Merge pipeline stats β”‚ β”‚
β”‚ β”‚ 4. POST /api/pipeline/scoreboard/save-results β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Scoreboard handlers (pkg/internal/apis/handlers) β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ - GET /api/pipeline/scoreboard/{namespace} β”‚ β”‚
β”‚ β”‚ - POST /api/pipeline/scoreboard/save-results β”‚ β”‚
β”‚ β”‚ - POST /api/pipeline/scoreboard/aggregate/start β”‚ β”‚
β”‚ β”‚ - DELETE /api/pipeline/scoreboard/aggregate/schedule/{id} β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PocketBase Collections β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ - pipeline_scoreboard_ β”‚
β”‚ cache (read model) β”‚
β”‚ - pipeline_results β”‚
β”‚ - pipelines β”‚
β”‚ - wallets, issuers, β”‚
β”‚ verifiers, etc. β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. User navigates to /scoreboard
  2. SvelteKit load calls Scoreboard.loadData() from $lib/scoreboard
  3. Frontend queries PocketBase pipeline_scoreboard_cache with expanded relations
  4. ScoreboardTable renders a paginated, sortable TanStack table
  5. Rows link to Hub pipeline pages via entity display helpers
  1. Public homepage loads loadScoreboardSummary() from scoreboard-section.svelte
  2. Frontend fetches a small random sample from pipeline_scoreboard_cache
  3. Cards show pipeline name, success rate, and related entities
  1. An operator or scheduler starts POST /api/pipeline/scoreboard/aggregate/start
  2. Temporal runs AggregateScoreboardWorkflow in the default namespace
  3. For each org namespace, the workflow calls GET /api/pipeline/scoreboard/{namespace}
  4. Per-namespace stats are merged and posted to POST /api/pipeline/scoreboard/save-results
  5. pipeline_scoreboard_cache is refreshed (truncate + upsert by pipeline)
  • Public scoreboard UI at /scoreboard
  • Homepage scoreboard section on the public landing page
  • PocketBase-backed read model (pipeline_scoreboard_cache)
  • Temporal aggregation workflow and save endpoint
  • Shared frontend module at webapp/src/lib/scoreboard
  • /my/scoreboard and /my/scoreboard/[type]/[id] routes
  • Legacy tabbed scoreboard UI and OpenTelemetry viewer
  • /api/my/results and /api/all-results handlers (commented out in scoreboard_handler.go)
credimi/
β”œβ”€β”€ pkg/internal/apis/handlers/
β”‚ β”œβ”€β”€ scoreboard.go (active aggregation + save handlers)
β”‚ β”œβ”€β”€ scoreboard_handler.go (legacy OTel handler, commented out)
β”‚ └── scoreboard_test.go
β”œβ”€β”€ pkg/workflowengine/workflows/
β”‚ └── scoreboard.go (AggregateScoreboardWorkflow)
β”œβ”€β”€ webapp/src/lib/scoreboard/
β”‚ β”œβ”€β”€ index.ts
β”‚ β”œβ”€β”€ functions.ts (PocketBase query)
β”‚ β”œβ”€β”€ table.svelte / table.svelte.ts
β”‚ β”œβ”€β”€ columns/ (TanStack column definitions)
β”‚ β”œβ”€β”€ entity-display/ (avatars, lists, links)
β”‚ └── extras/pipeline-content-summary.svelte
β”œβ”€β”€ webapp/src/routes/
β”‚ β”œβ”€β”€ (public)/scoreboard/
β”‚ β”‚ β”œβ”€β”€ +page.ts
β”‚ β”‚ └── +page.svelte
β”‚ └── (public)/_partials/scoreboard-section.svelte
└── docs/
β”œβ”€β”€ SCOREBOARD.md
β”œβ”€β”€ ARCHITECTURE.md (this file)
└── SUMMARY.md