Skip to content

feat(auth/overview): wire real login API and connect overview dashboard endpoints#15

Merged
mrcoded merged 4 commits into
devfrom
feat/admin-auth-integration
Jul 2, 2026
Merged

feat(auth/overview): wire real login API and connect overview dashboard endpoints#15
mrcoded merged 4 commits into
devfrom
feat/admin-auth-integration

Conversation

@ayomikun-ade

@ayomikun-ade ayomikun-ade commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

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/login with proper route protection via proxy.ts, and connect
GET /admin/overview/stats, /score-distribution, /ai-generation-consumption, and
/new-users to the Overview page components using the authApi + unwrapData + server
action + React Query hook pattern.

What did you do?

Auth

  • Replaced mock auth with publicApi.post("/admin/auth/login") + unwrapData in
    src/actions/auth.ts; added refreshTokens() server action stub
  • Added useLogin / useRefresh mutation hooks in src/hooks/api/use-auth.ts
  • Updated admin-login-form.tsx to use the useLogin mutation; passes
    admin_tier ?? role to NextAuth signIn since admin_tier is the authoritative
    permission field
  • Added persistServerCookies inside login() to forward the API's Set-Cookie
    response headers to the browser — without this, server actions have no auth cookies to
    proxy on subsequent requests
  • Updated the authApi request interceptor to call getServerCookieHeader() server-side,
    forwarding browser cookies to the API on every call
  • Implemented proxy.ts with NextAuth cookie detection, auth-route redirect, and early
    pass-through for /api/auth/* to prevent the proxy intercepting NextAuth's own session
    calls
  • Cleaned up src/types/api/auth.ts: removed unused token types, added
    RefreshResponseData, typed admin_tier as AdminRole | null

Overview page

  • Updated src/types/api/overview.ts to match API response shapes: snake_case fields,
    StatTrend with direction + change_percent, AIConsumptionData using buckets
  • Rewrote src/actions/overview.ts to call real authApi endpoints; the API wraps
    payloads in an extra { status, data } layer handled via a local Nested<T> type
  • overview-stat-cards.tsx: full ?. optional chaining on nested fields so stale cache
    degrades gracefully; null trend renders as no badge
  • score-distribution-chart.tsx: total_completed + empty flag for the empty-state gate
  • ai-consumption-chart.tsx: data.buckets + dataKey="range" to match bucket format
  • new-users-table.tsx: signup_date accessor and date formatter

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (changes that do not relate to a fix or feature and don't modify src or test files)

Check List

  • My code follows the code style of this project.
  • This PR does not contain plagiarized content.
  • The title and description of the PR are clear and explain the approach.
  • I am making a pull request against the dev branch (left side).
  • My commit message style matches our requested structure.
  • My code additions will not fail code linting checks or unit tests.
  • I am only making changes to files I was requested to.

Summary by CodeRabbit

  • New Features

    • Admin sign-in now uses the live authentication flow, with session refresh support and improved post-login routing.
    • Dashboard overview data now loads from real backend data, including stats, new users, score distribution, and AI usage charts.
  • Bug Fixes

    • Updated dashboard charts and tables to match the latest data format.
    • Improved login and route handling for signed-in and signed-out users.
  • Style

    • Interactive elements now show a pointer cursor for clearer clickability.

@ayomikun-ade ayomikun-ade requested a review from mrcoded July 2, 2026 14:07
@ayomikun-ade ayomikun-ade self-assigned this Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ayomikun-ade, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2fd8a0d7-c074-431f-972a-32fd3af35100

📥 Commits

Reviewing files that changed from the base of the PR and between 9ddf87f and ba7fa69.

📒 Files selected for processing (7)
  • src/actions/auth.ts
  • src/app/(dashboard)/talents/page.tsx
  • src/app/globals.css
  • src/components/integrity/voided-attempts-table.tsx
  • src/components/talents/talents-table.tsx
  • src/mocks/overview.ts
  • src/proxy.ts
📝 Walkthrough

Walkthrough

This 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.

Changes

Authentication flow with real API and cookie-based sessions

Layer / File(s) Summary
Auth type and constant changes
src/types/api/auth.ts, src/types/api/index.ts, src/constants/auth.ts
AdminAuthUser expanded with new fields, RefreshResponseData added, LoginErrorCode/AuthTokens/LoginResult removed, and AUTH_COOKIE_NAME replaces login error message constants.
Login and refresh server actions
src/actions/auth.ts
login and refreshTokens POST to backend endpoints, parse/persist auth cookies server-side, and return unwrapped data; logout remains a TODO.
Login hooks and form wiring
src/hooks/api/use-auth.ts, src/components/auth/admin-login-form.tsx
New useLogin/useRefresh React Query hooks call the actions; the login form switches to try/catch error handling and passes richer user fields to `signIn`.
Server-side cookie forwarding and route protection
src/lib/api/interceptors.ts, src/proxy.ts
Interceptors forward cookies server-side via `getServerCookieHeader`; proxy middleware checks session cookies to redirect authenticated/unauthenticated users between auth and protected routes.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Overview dashboard data from real API

Layer / File(s) Summary
Overview type contract updates
src/types/api/overview.ts, src/types/api/index.ts
OverviewStats, new StatMetric/StatTrend, AIConsumptionData bucket shape, and NewUser renamed to snake_case fields.
Overview server actions
src/actions/overview.ts
getOverviewStats, getScoreDistribution, getAIConsumption, and getNewUsers switch from mocks to real `authApi` GET calls returning unwrapped nested data.
Dashboard components consuming new data shapes
src/components/dashboard/overview-stat-cards.tsx, src/components/dashboard/ai-consumption-chart.tsx, src/components/dashboard/score-distribution-chart.tsx, src/components/dashboard/new-users-table.tsx
Stat cards, charts, and table updated to read snake_case fields, bucket data, and nested trend/empty flags from the new API shapes.

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
Loading
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
Loading

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)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: real auth login integration and live overview dashboard endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/admin-auth-integration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Re-export RefreshResponseData from the API barrel.

RefreshResponseData is now part of the auth response contract, but consumers importing from @/types/api cannot 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 win

Use the same effective role for session creation and redirect.

Line 63 stores user.admin_tier ?? user.role in the session, but Line 74 routes with user.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 win

Unused empty flag — chart renders blank instead of an empty state.

AIConsumptionData.empty is now available (same as ScoreDistribution.empty, which score-distribution-chart.tsx uses to show a "Not enough data yet" message), but this component ignores it and will just render an empty BarChart when 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

📥 Commits

Reviewing files that changed from the base of the PR and between 08e934f and 9ddf87f.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/app/favicon.ico is excluded by !**/*.ico
📒 Files selected for processing (15)
  • src/actions/auth.ts
  • src/actions/overview.ts
  • src/app/globals.css
  • src/components/auth/admin-login-form.tsx
  • src/components/dashboard/ai-consumption-chart.tsx
  • src/components/dashboard/new-users-table.tsx
  • src/components/dashboard/overview-stat-cards.tsx
  • src/components/dashboard/score-distribution-chart.tsx
  • src/constants/auth.ts
  • src/hooks/api/use-auth.ts
  • src/lib/api/interceptors.ts
  • src/proxy.ts
  • src/types/api/auth.ts
  • src/types/api/index.ts
  • src/types/api/overview.ts

Comment thread src/actions/auth.ts
Comment thread src/actions/auth.ts
Comment thread src/app/globals.css Outdated
Comment thread src/lib/api/interceptors.ts
Comment thread src/proxy.ts Outdated
@mrcoded mrcoded merged commit c6bae3a into dev Jul 2, 2026
10 checks passed
@mrcoded mrcoded deleted the feat/admin-auth-integration branch July 2, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants