Conversation
…I/kaapi-frontend into feat/google-integration
…I/kaapi-frontend into feat/google-integration
…ntend into feat/admin-flow
…I/kaapi-frontend into feat/google-integration
…ntend into feat/admin-flow
…I/kaapi-frontend into feat/admin-flow
…I/kaapi-frontend into feat/google-integration
📝 WalkthroughWalkthroughA new invite verification flow is introduced, enabling users to authenticate via email tokens. A client-side page component verifies tokens through an API route that forwards to a backend service. Upon successful verification, the user is logged in via a renamed context method and redirected to the evaluations dashboard. Changes
Sequence DiagramsequenceDiagram
participant User as User/Browser
participant Page as Invite Page
participant API as Next.js API Route
participant Backend as Backend Service
participant Auth as Auth Context
User->>Page: Visit /invite?token=xxx
Page->>API: fetch /api/auth/invite?token=xxx
API->>Backend: POST /api/v1/auth/invite/verify
Backend-->>API: {success, data: {access_token, user}}
API-->>Page: Response + Set-Cookie headers
Page->>Auth: loginWithToken(access_token, user)
Auth->>Auth: Update auth state
Page->>Page: Show success + progress animation
Page->>User: Redirect to /evaluations
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
…ntend into feat/invitation-flow
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/globals.css (1)
165-172: Remove or wire the unusedprogresskeyframes.The invite progress bar currently animates via inline
widthupdates (app/(auth)/invite/page.tsx, Line 166-168), so this keyframes block is unused right now.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/globals.css` around lines 165 - 172, The `@keyframes` progress block in globals.css is unused; either delete it or wire it up from the invite UI: remove the `@keyframes` progress declaration if you prefer inline width updates, or update the invite progress element in app/(auth)/invite/page.tsx to use the keyframes by applying an animation (e.g., animation-name: progress plus duration/timing) or a CSS class that references it so the keyframes actually drive the progress bar instead of inline width styles.app/(auth)/invite/page.tsx (1)
33-65: PreferAbortControllerover a local cancel flag for the verification request.React's documentation recommends either approach for effect cleanup, but
AbortControlleris the preferred pattern because it actually cancels the in-flight request, avoiding unnecessary network work. The current localcancelledflag prevents stale state updates but leaves the request running.♻️ Suggested refactor
- let cancelled = false; + const controller = new AbortController(); (async () => { try { const res = await fetch( `/api/auth/invite?token=${encodeURIComponent(token)}`, - { credentials: "include" }, + { credentials: "include", signal: controller.signal }, ); const data: InviteVerifyResponse = await res.json(); - if (cancelled) return; - if (!res.ok || !data.success || !data.data) { setStatus("error"); setError(data.error || "Invitation link is invalid or has expired."); return; } loginWithToken(data.data.access_token, data.data.user); setStatus("success"); - } catch { - if (!cancelled) { - setStatus("error"); - setError("Failed to verify invitation. Please try again."); - } + } catch (err) { + if (controller.signal.aborted) return; + setStatus("error"); + setError("Failed to verify invitation. Please try again."); } })(); return () => { - cancelled = true; + controller.abort(); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/`(auth)/invite/page.tsx around lines 33 - 65, Replace the local cancelled flag with an AbortController: create a controller in the effect, pass controller.signal into the fetch call that requests `/api/auth/invite?token=${encodeURIComponent(token)}`, and call controller.abort() in the cleanup function; in the catch block ignore/return on an aborted request (check for an AbortError or error.name === "AbortError") so you don't setStatus("error")/setError after abort, and only call loginWithToken(...) and setStatus("success") when the fetch resolves successfully and is not aborted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/api/auth/invite/route.ts`:
- Around line 21-28: The response returned from NextResponse.json (const res)
must include explicit no-cache headers to prevent caching of sensitive auth data
and forwarded cookies; after building res and before returning it (near
NextResponse.json, headers.getSetCookie, and res.headers.append usage), set
Cache-Control to "no-store, no-cache, must-revalidate, max-age=0" and add
complementary headers such as "Pragma: no-cache" and "Expires: 0" on res.headers
(using res.headers.set or equivalent) so the invite verification response is
non-cacheable.
---
Nitpick comments:
In `@app/`(auth)/invite/page.tsx:
- Around line 33-65: Replace the local cancelled flag with an AbortController:
create a controller in the effect, pass controller.signal into the fetch call
that requests `/api/auth/invite?token=${encodeURIComponent(token)}`, and call
controller.abort() in the cleanup function; in the catch block ignore/return on
an aborted request (check for an AbortError or error.name === "AbortError") so
you don't setStatus("error")/setError after abort, and only call
loginWithToken(...) and setStatus("success") when the fetch resolves
successfully and is not aborted.
In `@app/globals.css`:
- Around line 165-172: The `@keyframes` progress block in globals.css is unused;
either delete it or wire it up from the invite UI: remove the `@keyframes`
progress declaration if you prefer inline width updates, or update the invite
progress element in app/(auth)/invite/page.tsx to use the keyframes by applying
an animation (e.g., animation-name: progress plus duration/timing) or a CSS
class that references it so the keyframes actually drive the progress bar
instead of inline width styles.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0e715f56-ff8e-4bdf-aee3-a9eff7bf5ace
📒 Files selected for processing (6)
app/(auth)/invite/page.tsxapp/api/auth/invite/route.tsapp/components/auth/LoginModal.tsxapp/globals.cssapp/lib/context/AuthContext.tsxapp/lib/types/auth.ts
| const res = NextResponse.json(data, { status }); | ||
|
|
||
| const setCookies = headers.getSetCookie?.() ?? []; | ||
| for (const cookie of setCookies) { | ||
| res.headers.append("Set-Cookie", cookie); | ||
| } | ||
|
|
||
| return res; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether auth route handlers set explicit no-store cache headers.
fd -p 'route.ts' app/api/auth | while read -r f; do
echo "== $f =="
rg -n "Cache-Control|Pragma|NextResponse\\.json|Set-Cookie" "$f"
doneRepository: ProjectTech4DevAI/kaapi-frontend
Length of output: 740
🏁 Script executed:
cat -n app/api/auth/invite/route.tsRepository: ProjectTech4DevAI/kaapi-frontend
Length of output: 1247
🏁 Script executed:
# Check if there's middleware that might handle cache headers globally
find . -name "middleware.ts" -o -name "middleware.js" | head -5Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Search for any global cache-control patterns in the codebase
rg -l "Cache-Control|no-store" --type ts --type tsx | head -10Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 103
🏁 Script executed:
# Check other API routes to see if any set headers via NextResponse.json options
rg -n "NextResponse\.json.*headers" --type tsRepository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Look for NextResponse patterns with options to understand the API
rg -B1 -A3 "NextResponse\.json.*\{" app/api --type ts | head -50Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 2853
🏁 Script executed:
# Check if there's a Next.js config or any cache-related setup
cat next.config.js 2>/dev/null || cat next.config.ts 2>/dev/null || echo "No next.config found"Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 317
🏁 Script executed:
# Check the google and logout routes to see their full pattern
cat -n app/api/auth/google/route.tsRepository: ProjectTech4DevAI/kaapi-frontend
Length of output: 1419
🏁 Script executed:
# Search for any response.headers patterns to understand how headers are actually set
rg "response\.headers|res\.headers" app/api -A2 -B2 --type ts | head -80Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 1253
🏁 Script executed:
# Check if NextResponse constructor accepts headers option by looking for similar patterns
rg "NextResponse\.(json|text|redirect)" --type ts -A5 | grep -E "NextResponse|headers" | head -40Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 3002
🏁 Script executed:
# Look for NextResponse type definitions or usage with headers
rg "NextResponse" node_modules --type ts -A5 2>/dev/null | head -100Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Check if there's a tsconfig that might have type definitions
cat tsconfig.json 2>/dev/null | head -30Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 690
🏁 Script executed:
# Search for any example in the codebase where response object headers are set before construction
rg "headers\s*=" app/api --type ts -B3 -A3 | head -80Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Look at Next.js version to understand NextResponse API
cat package.json | grep -A5 -B5 "next"Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 972
🏁 Script executed:
# Check Next.js 16 documentation or search for ResponseInit usage
rg "ResponseInit|init\?" app/api --type ts -B2 -A2 | head -60Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Look for any headers being set in constructor anywhere in the codebase
rg "new NextResponse\|NextResponse\.(json|text)" --type ts -A8 | grep -E "NextResponse|headers" | head -50Repository: ProjectTech4DevAI/kaapi-frontend
Length of output: 58
🏁 Script executed:
# Verify the actual Next.js API: check if response headers can be set in constructor
python3 << 'EOF'
import json
# Next.js NextResponse API for version 16.0.7 analysis
# Based on Next.js documentation, ResponseInit includes:
# { status?: number; statusText?: string; headers?: HeadersInit }
# This means headers can be passed in the options object
# The proposed patch should work syntactically
print("NextResponse.json() signature in Next.js 16.0.7:")
print("- Accepts: (body, init?: ResponseInit)")
print("- ResponseInit includes: { status, headers, statusText }")
print("\nProposed patch syntax appears valid.")
print("\nThe concern raised in review is legitimate:")
print("- GET endpoint returns sensitive auth data")
print("- Returns Set-Cookie headers")
print("- Should be explicitly non-cacheable")
EOFRepository: ProjectTech4DevAI/kaapi-frontend
Length of output: 412
Add explicit no-cache headers to invite verification response.
This GET endpoint returns sensitive auth data and forwards session cookies. Responses should be marked non-cacheable to prevent browsers or proxies from caching the auth token/cookies.
🔧 Proposed patch
- const res = NextResponse.json(data, { status });
+ const res = NextResponse.json(data, {
+ status,
+ headers: {
+ "Cache-Control": "no-store, private, max-age=0",
+ Pragma: "no-cache",
+ },
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const res = NextResponse.json(data, { status }); | |
| const setCookies = headers.getSetCookie?.() ?? []; | |
| for (const cookie of setCookies) { | |
| res.headers.append("Set-Cookie", cookie); | |
| } | |
| return res; | |
| const res = NextResponse.json(data, { | |
| status, | |
| headers: { | |
| "Cache-Control": "no-store, private, max-age=0", | |
| Pragma: "no-cache", | |
| }, | |
| }); | |
| const setCookies = headers.getSetCookie?.() ?? []; | |
| for (const cookie of setCookies) { | |
| res.headers.append("Set-Cookie", cookie); | |
| } | |
| return res; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/auth/invite/route.ts` around lines 21 - 28, The response returned
from NextResponse.json (const res) must include explicit no-cache headers to
prevent caching of sensitive auth data and forwarded cookies; after building res
and before returning it (near NextResponse.json, headers.getSetCookie, and
res.headers.append usage), set Cache-Control to "no-store, no-cache,
must-revalidate, max-age=0" and add complementary headers such as "Pragma:
no-cache" and "Expires: 0" on res.headers (using res.headers.set or equivalent)
so the invite verification response is non-cacheable.
Issue: #112
Summary:
Summary by CodeRabbit
Release Notes