@@ -44,15 +44,12 @@ class PerformanceController < Api::V1::BaseController
4444 # @param player_id [Integer] Player ID for individual stats (optional)
4545 # @return [JSON] Performance analytics data
4646 def index
47- matches = apply_date_filters ( organization_scoped ( Match ) )
48-
4947 # Use active players for team-wide stats (best performers, role breakdown, etc.)
5048 # but validate player_id against ALL org players so that bench/trial/inactive
5149 # players can still have their individual stats viewed.
52- active_players = organization_scoped ( Player ) . includes ( :organization ) . active
5350 all_org_players = organization_scoped ( Player ) . includes ( :organization )
54-
5551 player_id = params [ :player_id ] . presence
52+
5653 if player_id . present? && !all_org_players . exists? ( id : player_id )
5754 return render_error (
5855 message : 'Player not found' ,
@@ -61,11 +58,12 @@ def index
6158 )
6259 end
6360
64- service = PerformanceAnalyticsService . new ( matches , active_players )
65- performance_data = service . calculate_performance_data ( player_id : player_id , all_players : all_org_players )
66-
67- data = cache_response ( 'analytics/performance' , expires_in : 15 . minutes ) do
68- performance_data
61+ cache_key = performance_cache_key ( player_id )
62+ data = cache_response ( cache_key , expires_in : 15 . minutes ) do
63+ matches = apply_date_filters ( organization_scoped ( Match ) )
64+ active_players = organization_scoped ( Player ) . includes ( :organization ) . active
65+ service = PerformanceAnalyticsService . new ( matches , active_players )
66+ service . calculate_performance_data ( player_id : player_id , all_players : all_org_players )
6967 end
7068
7169 render_success ( data )
@@ -96,6 +94,24 @@ def apply_date_filters(matches)
9694 end
9795 end
9896
97+ # Builds a cache key segment that distinguishes team vs player requests
98+ # and incorporates active date-filter params so that different filter
99+ # combinations never share a cached result.
100+ #
101+ # The key is intentionally short and URL-safe; the org-scoping prefix
102+ # is added by the Cacheable concern's +build_cache_key+ method.
103+ #
104+ # @param player_id [String, nil] player_id param value (nil for team view)
105+ # @return [String] cache key segment, e.g.
106+ # "analytics/performance/team",
107+ # "analytics/performance/team/month",
108+ # "analytics/performance/player/42/2025-01-01-2025-01-31"
109+ def performance_cache_key ( player_id )
110+ base = player_id ? "analytics/performance/player/#{ player_id } " : 'analytics/performance/team'
111+ suffix = [ params [ :time_period ] , params [ :start_date ] , params [ :end_date ] ] . compact . join ( '-' )
112+ suffix . present? ? "#{ base } /#{ suffix } " : base
113+ end
114+
99115 # Converts time period string to number of days
100116 #
101117 # @param period [String] Time period (week, month, season)
0 commit comments