Skip to content

Commit 6e6f3bb

Browse files
committed
feat: dynamic tier limit from backend instead of hardcoded constant (OPE-118)
New useUserUsage hook calls GET /api/v1/users/usage (React Query, 60s stale). Returns actual max_functions_per_repo for the user's tier from backend. DashboardHome now passes usage?.limits?.max_functions_per_repo to DirectoryPicker instead of TIER_FUNCTION_LIMITS[userTier]. Removed: TIER_FUNCTION_LIMITS import, TierName import, rawTier/userTier derivation from session metadata. All gone from DashboardHome. If user is on Pro (20K limit), budget bar shows X/20,000. If admin bumps them to Enterprise (500K), it updates on next page load. No frontend deploy needed when tier limits change on backend.
1 parent eabf178 commit 6e6f3bb

2 files changed

Lines changed: 24 additions & 8 deletions

File tree

frontend/src/components/dashboard/DashboardHome.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useSearchParams } from 'react-router-dom'
66
import { AnimatePresence } from 'framer-motion'
77
import { toast } from 'sonner'
88
import { useAuth } from '../../contexts/AuthContext'
9-
import { useRepos } from '../../hooks/useCachedQuery'
9+
import { useRepos, useUserUsage } from '../../hooks/useCachedQuery'
1010
import { API_URL, MAX_FREE_REPOS } from '../../config/api'
1111
import { extractErrorMessage, isUpgradeError } from '../../lib/api-errors'
1212
import { RepoListView } from './RepoListView'
@@ -16,18 +16,14 @@ import { DirectoryPicker } from '../DirectoryPicker'
1616
import { GitHubRepoSelector } from '../GitHubRepoSelector'
1717
import { IndexingProgressModal } from '../IndexingProgressModal'
1818
import { UpgradeLimitModal } from '../UpgradeLimitModal'
19-
import { TIER_FUNCTION_LIMITS, type TierName } from '../../config/api'
2019
import type { GitHubRepo } from '../../hooks/useGitHubRepos'
2120
import type { AnalyzeResult, RepoTab } from '../../types'
2221

2322
export function DashboardHome() {
2423
const { session } = useAuth()
2524
const [searchParams, setSearchParams] = useSearchParams()
2625
const { data: repos = [], isLoading: reposLoading, invalidate: refreshRepos } = useRepos(session?.access_token)
27-
28-
// User tier -- validate against known tiers, fall back to free for unknown values
29-
const rawTier = session?.user?.user_metadata?.tier as string
30-
const userTier: TierName = rawTier && rawTier in TIER_FUNCTION_LIMITS ? (rawTier as TierName) : 'free'
26+
const { data: usage } = useUserUsage(session?.access_token)
3127

3228
const [selectedRepo, setSelectedRepo] = useState<string | null>(null)
3329
const [activeTab, setActiveTab] = useState<RepoTab>('overview')
@@ -260,8 +256,7 @@ export function DashboardHome() {
260256
repoInfo={analyzeResult}
261257
onConfirm={handleDirectoryConfirm}
262258
loading={loading}
263-
// TODO: replace with actual user tier once GET /users/me returns tier
264-
functionLimit={TIER_FUNCTION_LIMITS[userTier]}
259+
functionLimit={usage?.limits?.max_functions_per_repo}
265260
/>
266261
)}
267262

frontend/src/hooks/useCachedQuery.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,24 @@ export function useRepos(apiKey: string | undefined) {
189189

190190
return { ...query, invalidate }
191191
}
192+
193+
194+
/** User usage and tier limits from backend -- single source of truth */
195+
export function useUserUsage(apiKey: string | undefined) {
196+
return useQuery({
197+
queryKey: ['user', 'usage'],
198+
queryFn: async () => {
199+
const data = await fetchWithAuth(`${API_URL}/users/usage`, apiKey!)
200+
return data as {
201+
tier: string
202+
limits: {
203+
max_files_per_repo: number
204+
max_functions_per_repo: number
205+
playground_searches_per_day: number | null
206+
}
207+
}
208+
},
209+
enabled: !!apiKey,
210+
staleTime: 60_000,
211+
})
212+
}

0 commit comments

Comments
 (0)