Repository navigation
feat(web): top cities card on the Artist Dashboard - #14770
Merged
Merged
Conversation
Shows the cities whose listeners played the artist's tracks the most for the last 7 days, 30 days or all time, from the new /v1/users/:id/listener_cities endpoint. Behind dashboard_top_cities (dev on, prod off). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 3a43617 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
dylanjeffers
added a commit
to AudiusProject/api
that referenced
this pull request
Nov 12, 2026
Adds `GET /v1/users/:id/listener_cities?time=week|month|all&limit=10` for the Artist Dashboard's new Top Cities card. It returns the cities whose listeners played the artist's tracks the most: `city`, `region`, `country`, `play_count`. Only the artist or one of their managers can call it (`requireAuthForUserId`). Counting matches the weekly artist recap: plays of the artist's current tracks, trimmed city, empty cities skipped, the artist's own plays skipped. Locations come from the listener's IP (MaxMind on the streaming node), so VPN and mobile carrier traffic can land in the wrong city. ### Why a rollup table `plays` has no index by track (only `created_at`, `slot`, `signature` and two user-first indexes), so a per-artist query would scan every play in the window, or the whole table for `all`. `aggregate_monthly_plays` has country but not city. So this adds `aggregate_daily_city_plays` (track, UTC day, country, region, city, count), with the primary key leading on `play_item_id`. The endpoint reads it through `track_owner_id_idx`, then the primary key. A new indexer job, `CityPlaysJob`, fills it every 15s from `plays`, checkpointed on `plays.id` in `indexing_checkpoints` (same pattern as `hourly_play_counts`). Each run handles at most 250k play ids. On first deploy it backfills whatever `plays` still holds (prune keeps about 400 days), starting at the lowest remaining id. After that, `all` keeps growing even as old plays are pruned. - `week` = today plus the 6 days before (UTC), `month` = 30 days - The migration only creates the table, so it is quick. The backfill runs in the job. ### Not measured City coverage and backfill time in prod: there's no prod DB access from here. Worth checking `SELECT last_checkpoint FROM indexing_checkpoints WHERE tablename = 'aggregate_daily_city_plays'` against `MAX(plays.id)` after deploy. ### Tests - `TestV1UsersListenerCities`: week/month/all windows, limit, other artists' tracks excluded, manager access, 403 for other users, 400 for a bad `time` - `TestCityPlaysJob`: batching across runs, owner plays and empty or NULL cities skipped, trimming, day bucketing - `TestCityPlaysJob_SkipsPrunedIds` Also ran it end to end with a local api and the web dashboard ((AudiusProject/apps#14770)). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a Top Cities card to the web Artist Dashboard, under the stat tiles. It lists the 10 cities whose listeners played the artist's tracks the most, for the last 7 days, last 30 days (default) or all time, with a bar and play count for each. This matches the "top city" line in the weekly artist recap notification.
Depends on AudiusProject/api#1072 (
GET /v1/users/:id/listener_cities). That endpoint only answers the artist or their managers, so manager mode works.dashboard_top_citiesflag: on in development, off in productionuseListenerCitiestan-query hook in commonusers.getListenerCitiesand its two models, generated from the api PR's swagger. Unrelated drift from the generator was left out. Changeset included.Mobile is not included.
Tested locally against the api branch with a seeded artist: the week/month/all switch, the artist's own plays and plays with no city left out, empty and error states.
🤖 Generated with Claude Code