feat(auth/overview): wire real login API and connect overview dashboard endpoints#15
Conversation
|
Warning Review limit reached
Next review available in: 1 minute Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR replaces mocked authentication and overview dashboard data with real backend API calls. Login/refresh actions persist auth cookies server-side, proxy middleware enforces route-based auth redirects, interceptors forward cookies server-side, and related types and dashboard components are updated to snake_case API response shapes. ChangesAuthentication flow with real API and cookie-based sessions
Estimated code review effort: 3 (Moderate) | ~30 minutes Overview dashboard data from real API
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant AdminLoginForm
participant loginAction as login (server action)
participant publicApi
participant CookieStore
AdminLoginForm->>loginAction: login(body)
loginAction->>publicApi: POST /admin/auth/login
publicApi-->>loginAction: response with Set-Cookie headers
loginAction->>CookieStore: persist parsed auth cookies
loginAction-->>AdminLoginForm: unwrapped LoginResponseData
sequenceDiagram
participant Browser
participant ProxyMiddleware as proxy
participant Cookies
Browser->>ProxyMiddleware: request pathname
ProxyMiddleware->>Cookies: check session-token cookies
Cookies-->>ProxyMiddleware: authenticated true/false
alt authenticated and AUTH_ROUTES
ProxyMiddleware-->>Browser: redirect /dashboard
else unauthenticated and protected route
ProxyMiddleware-->>Browser: redirect /login with callbackUrl
else
ProxyMiddleware-->>Browser: continue with security headers
end
Related PRs: None identified from the provided information. Suggested labels: authentication, api-integration, dashboard Suggested reviewers: None specified. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/types/api/index.ts (1)
7-12: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winRe-export
RefreshResponseDatafrom the API barrel.
RefreshResponseDatais now part of the auth response contract, but consumers importing from@/types/apicannot access it.Proposed fix
export type { AdminAuthUser, AdminRole, LoginInput, LoginResponseData, + RefreshResponseData, } from "./auth";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types/api/index.ts` around lines 7 - 12, The API barrel export in the `src/types/api/index.ts` re-export list is missing `RefreshResponseData`, so consumers of `@/types/api` cannot import the new auth response type. Update the existing export block alongside `LoginResponseData` to also re-export `RefreshResponseData` from the `auth` module, keeping the barrel in sync with the auth contract.src/components/auth/admin-login-form.tsx (1)
57-74: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the same effective role for session creation and redirect.
Line 63 stores
user.admin_tier ?? user.rolein the session, but Line 74 routes withuser.role. If those differ, the user lands on a path for a different role.Proposed fix
+ const effectiveRole = user.admin_tier ?? user.role; const signInResult = await signIn("credentials", { sessionUser: "true", userId: user.id, email: user.email, name: user.fullname, image: user.avatar_url ?? undefined, - role: user.admin_tier ?? user.role, + role: effectiveRole, redirect: false, }); @@ - router.replace(getPostLoginPath(user.role)); + router.replace(getPostLoginPath(effectiveRole));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/auth/admin-login-form.tsx` around lines 57 - 74, The admin login flow in admin-login-form.tsx is using different roles for session creation and post-login routing. In the signIn call, use the same effective role value that you pass to the session payload when calling router.replace(getPostLoginPath(...)) so both actions rely on one shared role source. Update the admin login handler in the admin-login-form component to compute a single role from user.admin_tier ?? user.role and reuse it for both signIn and getPostLoginPath.src/components/dashboard/ai-consumption-chart.tsx (1)
56-84: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winUnused
emptyflag — chart renders blank instead of an empty state.
AIConsumptionData.emptyis now available (same asScoreDistribution.empty, whichscore-distribution-chart.tsxuses to show a "Not enough data yet" message), but this component ignores it and will just render an emptyBarChartwhen there's no data.♻️ Suggested empty-state handling
<CardContent> {isLoading ? ( <Skeleton className="h-52 w-full rounded-xl" /> + ) : data?.empty ? ( + <Empty className="h-52 border-0"> + <EmptyHeader> + <EmptyTitle className="text-sm font-medium">No data yet</EmptyTitle> + <EmptyDescription>No AI generation activity for this period.</EmptyDescription> + </EmptyHeader> + </Empty> ) : ( <ChartContainer config={chartConfig} className="h-52 w-full">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/dashboard/ai-consumption-chart.tsx` around lines 56 - 84, The AIConsumption chart currently ignores the available empty flag and renders a blank BarChart when there is no data. Update the AIConsumptionData handling in ai-consumption-chart.tsx to check the empty state before rendering the chart, similar to score-distribution-chart.tsx, and show an explicit empty-state message instead of the chart when data is unavailable. Use the existing chart rendering path and add the empty-state branch around the ChartContainer/BarChart logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/actions/auth.ts`:
- Around line 25-28: The login flow in auth.ts currently persists cookies even
when the backend does not return usable Set-Cookie headers, which can leave a
NextAuth session active but break later dashboard requests. In the login action
that uses setCookieHeadersFrom, parseSetCookieHeader, and persistServerCookies,
validate that at least one cookie was successfully parsed before continuing; if
the cookie list is empty or all entries are null, treat it as a login failure
and return an error instead of calling persistServerCookies.
- Around line 33-36: `refreshTokens()` currently calls `/auth/refresh` without
forwarding the incoming server `Cookie` header and does not persist any
`Set-Cookie` values from the response. Update `refreshTokens()` to reuse the
same cookie-forward/persist flow already used by `refreshAuthCookies()`: pass
through the request cookie header when posting with `publicApi.post`, then
collect and reapply any rotated cookies from the refresh response before
returning `unwrapData(res)`.
In `@src/app/globals.css`:
- Around line 172-179: The pointer-cursor rule in globals.css is too broad
because the bare a selector matches non-link anchors without href. Update the
selector list to scope anchor styling to interactive links only by using the
existing cursor rule with a[href] instead of a, while leaving the other
interactive selectors unchanged.
- Around line 172-179: The global cursor rule in the base stylesheet is too
broad because the `button` selector also matches disabled buttons, causing
`button:disabled` to show a pointer cursor. Update the selector near the
existing `button`, `[role="button"]`, `a`, `label[for]`, `select`, and
`[tabindex]:not([tabindex="-1"])` rule so disabled buttons/inputs are excluded
or overridden, and keep the pointer cursor only for actually interactive
controls.
In `@src/lib/api/interceptors.ts`:
- Around line 20-26: The server-side cookie forwarding in interceptors.ts
currently proxies the entire Cookie header from getServerCookieHeader(), which
can leak unrelated app cookies to the API. Update the logic in the interceptor
that builds config.headers so it allow-lists only the backend auth cookie names
(for example, the auth/refresh tokens) and assembles a Cookie header from just
those values, rather than forwarding every cookie returned by
getServerCookieHeader().
In `@src/proxy.ts`:
- Around line 55-63: Redirect responses from the auth guard in proxy.ts
currently bypass continueWithSecurityHeaders(), so both the
authenticated-to-/dashboard and unauthenticated-to-/login branches return
without the configured security headers and x-request-id. Update the redirect
handling in the proxy logic to wrap or post-process the NextResponse.redirect
results through continueWithSecurityHeaders() before returning, using the
existing auth-route and protected-route branches as the integration points.
---
Outside diff comments:
In `@src/components/auth/admin-login-form.tsx`:
- Around line 57-74: The admin login flow in admin-login-form.tsx is using
different roles for session creation and post-login routing. In the signIn call,
use the same effective role value that you pass to the session payload when
calling router.replace(getPostLoginPath(...)) so both actions rely on one shared
role source. Update the admin login handler in the admin-login-form component to
compute a single role from user.admin_tier ?? user.role and reuse it for both
signIn and getPostLoginPath.
In `@src/components/dashboard/ai-consumption-chart.tsx`:
- Around line 56-84: The AIConsumption chart currently ignores the available
empty flag and renders a blank BarChart when there is no data. Update the
AIConsumptionData handling in ai-consumption-chart.tsx to check the empty state
before rendering the chart, similar to score-distribution-chart.tsx, and show an
explicit empty-state message instead of the chart when data is unavailable. Use
the existing chart rendering path and add the empty-state branch around the
ChartContainer/BarChart logic.
In `@src/types/api/index.ts`:
- Around line 7-12: The API barrel export in the `src/types/api/index.ts`
re-export list is missing `RefreshResponseData`, so consumers of `@/types/api`
cannot import the new auth response type. Update the existing export block
alongside `LoginResponseData` to also re-export `RefreshResponseData` from the
`auth` module, keeping the barrel in sync with the auth contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 095f5f0b-0878-4c67-9c59-b39cffcd78c0
⛔ Files ignored due to path filters (2)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/app/favicon.icois excluded by!**/*.ico
📒 Files selected for processing (15)
src/actions/auth.tssrc/actions/overview.tssrc/app/globals.csssrc/components/auth/admin-login-form.tsxsrc/components/dashboard/ai-consumption-chart.tsxsrc/components/dashboard/new-users-table.tsxsrc/components/dashboard/overview-stat-cards.tsxsrc/components/dashboard/score-distribution-chart.tsxsrc/constants/auth.tssrc/hooks/api/use-auth.tssrc/lib/api/interceptors.tssrc/proxy.tssrc/types/api/auth.tssrc/types/api/index.tssrc/types/api/overview.ts
Description
This PR wires up real API authentication and connects all four Overview dashboard
endpoints, replacing the previous mock credential flow and mock data.
Changes Proposed
What were you told to do?
Connect
POST /admin/auth/loginwith proper route protection viaproxy.ts, and connectGET /admin/overview/stats,/score-distribution,/ai-generation-consumption, and/new-usersto the Overview page components using theauthApi+unwrapData+ serveraction + React Query hook pattern.
What did you do?
Auth
publicApi.post("/admin/auth/login")+unwrapDatainsrc/actions/auth.ts; addedrefreshTokens()server action stubuseLogin/useRefreshmutation hooks insrc/hooks/api/use-auth.tsadmin-login-form.tsxto use theuseLoginmutation; passesadmin_tier ?? roleto NextAuthsignInsinceadmin_tieris the authoritativepermission field
persistServerCookiesinsidelogin()to forward the API'sSet-Cookieresponse headers to the browser — without this, server actions have no auth cookies to
proxy on subsequent requests
authApirequest interceptor to callgetServerCookieHeader()server-side,forwarding browser cookies to the API on every call
proxy.tswith NextAuth cookie detection, auth-route redirect, and earlypass-through for
/api/auth/*to prevent the proxy intercepting NextAuth's own sessioncalls
src/types/api/auth.ts: removed unused token types, addedRefreshResponseData, typedadmin_tierasAdminRole | nullOverview page
src/types/api/overview.tsto match API response shapes: snake_case fields,StatTrendwithdirection+change_percent,AIConsumptionDatausingbucketssrc/actions/overview.tsto call realauthApiendpoints; the API wrapspayloads in an extra
{ status, data }layer handled via a localNested<T>typeoverview-stat-cards.tsx: full?.optional chaining on nested fields so stale cachedegrades gracefully;
nulltrend renders as no badgescore-distribution-chart.tsx:total_completed+emptyflag for the empty-state gateai-consumption-chart.tsx:data.buckets+dataKey="range"to match bucket formatnew-users-table.tsx:signup_dateaccessor and date formatterTypes of changes
Check List
Summary by CodeRabbit
New Features
Bug Fixes
Style