Skip to content

Commit 5ef2cc6

Browse files
daksh-rDakshclaude
authored
feat: add query_team_usage_stats API for multi-tenant metrics (#195)
* feat: add query_team_usage_stats API for multi-tenant metrics Add query_team_usage_stats method for querying team-level usage statistics from the warehouse database. - Returns all 16 metrics grouped by team with cursor-based pagination - Supports monthly aggregation (month param) or daily breakdown (start_date/end_date) - Includes Sorbet type signatures and comprehensive test coverage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update shadow ban test to match API behavior The API now returns shadowed=true when sending a message as a shadow banned user. Updated test expectation to match current behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Daksh <daksh.rinwan@getstream.io> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 59f877c commit 5ef2cc6

2 files changed

Lines changed: 106 additions & 1 deletion

File tree

lib/stream-chat/client.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,27 @@ def channel_batch_updater
11951195
ChannelBatchUpdater.new(self)
11961196
end
11971197

1198+
# Queries team-level usage statistics from the warehouse database.
1199+
#
1200+
# Returns all 16 metrics grouped by team with cursor-based pagination.
1201+
# This endpoint is server-side only.
1202+
#
1203+
# Date Range Options (mutually exclusive):
1204+
# - Use 'month' parameter (YYYY-MM format) for monthly aggregated values
1205+
# - Use 'start_date'/'end_date' parameters (YYYY-MM-DD format) for daily breakdown
1206+
# - If neither provided, defaults to current month (monthly mode)
1207+
#
1208+
# @param month [String, nil] Month in YYYY-MM format (e.g., '2026-01')
1209+
# @param start_date [String, nil] Start date in YYYY-MM-DD format
1210+
# @param end_date [String, nil] End date in YYYY-MM-DD format
1211+
# @param limit [Integer, nil] Maximum number of teams to return per page (default: 30, max: 30)
1212+
# @param next_cursor [String, nil] Cursor for pagination to fetch next page of teams
1213+
# @return [StreamChat::StreamResponse] Response with teams array and optional next cursor
1214+
sig { params(options: T.untyped).returns(StreamChat::StreamResponse) }
1215+
def query_team_usage_stats(**options)
1216+
post('stats/team_usage', data: options)
1217+
end
1218+
11981219
private
11991220

12001221
sig { returns(T::Hash[String, String]) }

spec/client_spec.rb

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def loop_times(times)
245245
id: msg_id,
246246
text: 'Hello world'
247247
}, @random_user[:id])
248-
expect(response['message']['shadowed']).to eq(false)
248+
expect(response['message']['shadowed']).to eq(true)
249249
response = @client.get_message(msg_id)
250250
expect(response['message']['shadowed']).to eq(true)
251251

@@ -1475,4 +1475,88 @@ def loop_times(times)
14751475
expect(response.status_code).to eq(201)
14761476
end
14771477
end
1478+
1479+
describe '#query_team_usage_stats' do
1480+
it 'queries team usage stats with default options' do
1481+
response = @client.query_team_usage_stats
1482+
expect(response).to include 'teams'
1483+
expect(response['teams']).to be_an(Array)
1484+
end
1485+
1486+
it 'queries team usage stats with month parameter' do
1487+
current_month = Time.now.strftime('%Y-%m')
1488+
response = @client.query_team_usage_stats(month: current_month)
1489+
expect(response).to include 'teams'
1490+
expect(response['teams']).to be_an(Array)
1491+
end
1492+
1493+
it 'queries team usage stats with date range' do
1494+
end_date = Date.today
1495+
start_date = end_date - 7
1496+
response = @client.query_team_usage_stats(
1497+
start_date: start_date.strftime('%Y-%m-%d'),
1498+
end_date: end_date.strftime('%Y-%m-%d')
1499+
)
1500+
expect(response).to include 'teams'
1501+
expect(response['teams']).to be_an(Array)
1502+
end
1503+
1504+
it 'queries team usage stats with pagination' do
1505+
response = @client.query_team_usage_stats(limit: 10)
1506+
expect(response).to include 'teams'
1507+
expect(response['teams']).to be_an(Array)
1508+
1509+
# If there's a next cursor, fetch the next page
1510+
if response['next'] && !response['next'].empty?
1511+
next_response = @client.query_team_usage_stats(limit: 10, next: response['next'])
1512+
expect(next_response).to include 'teams'
1513+
expect(next_response['teams']).to be_an(Array)
1514+
end
1515+
end
1516+
1517+
it 'returns proper response structure when data exists' do
1518+
# Query last year to maximize chance of getting data
1519+
end_date = Date.today
1520+
start_date = end_date - 365
1521+
response = @client.query_team_usage_stats(
1522+
start_date: start_date.strftime('%Y-%m-%d'),
1523+
end_date: end_date.strftime('%Y-%m-%d')
1524+
)
1525+
1526+
expect(response).to include 'teams'
1527+
teams = response['teams']
1528+
1529+
next unless teams && !teams.empty?
1530+
1531+
team = teams[0]
1532+
1533+
# Verify team identifier
1534+
expect(team).to include 'team'
1535+
1536+
# Verify daily activity metrics
1537+
expect(team).to include 'users_daily'
1538+
expect(team).to include 'messages_daily'
1539+
expect(team).to include 'translations_daily'
1540+
expect(team).to include 'image_moderations_daily'
1541+
1542+
# Verify peak metrics
1543+
expect(team).to include 'concurrent_users'
1544+
expect(team).to include 'concurrent_connections'
1545+
1546+
# Verify rolling/cumulative metrics
1547+
expect(team).to include 'users_total'
1548+
expect(team).to include 'users_last_24_hours'
1549+
expect(team).to include 'users_last_30_days'
1550+
expect(team).to include 'users_month_to_date'
1551+
expect(team).to include 'users_engaged_last_30_days'
1552+
expect(team).to include 'users_engaged_month_to_date'
1553+
expect(team).to include 'messages_total'
1554+
expect(team).to include 'messages_last_24_hours'
1555+
expect(team).to include 'messages_last_30_days'
1556+
expect(team).to include 'messages_month_to_date'
1557+
1558+
# Verify metric structure
1559+
expect(team['users_daily']).to include 'total'
1560+
end
1561+
end
14781562
end

0 commit comments

Comments
 (0)