feat: add Identity current-user experience - #3
Conversation
📝 WalkthroughWalkthroughPR thêm luồng current-user từ xác thực Clerk đến BridgeWorks API và giao diện tổng quan tài khoản. PR cũng thêm điều hướng dùng chung, cập nhật landing page, theme, tài liệu README và bước kiểm tra ChangesCurrent-user account experience
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
tests/example.spec.ts (1)
77-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKiểm tra tràn ngang trên
<main>.
src/app/page.tsxLine 27 đặtoverflow-x-hiddentrên<main>. Một phần tử con quá rộng có thể bị cắt, nhưngdocument.documentElement.scrollWidthvẫn bằngclientWidth. Đo kích thước của<main>để bài kiểm thử phát hiện nội dung bị cắt.Đề xuất thay đổi
- const dimensions = await page.evaluate(() => ({ - scrollWidth: document.documentElement.scrollWidth, - clientWidth: document.documentElement.clientWidth, + const dimensions = await page.locator("main").evaluate((main) => ({ + scrollWidth: main.scrollWidth, + clientWidth: main.clientWidth, }));🤖 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 `@tests/example.spec.ts` around lines 77 - 82, Update the overflow test in the example spec to measure the <main> element instead of document.documentElement, using the existing page.evaluate block and the main element as the source of scrollWidth/clientWidth so hidden horizontal overflow under the main container is detected even when the root document width stays unchanged..github/workflows/playwright.yml (1)
60-61: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winKhông chạy lặp cùng một bộ kiểm tra.
pnpm checkđã chạy lint, typecheck, unit tests, application build và Storybook build. Workflow đã chạy các lệnh này tại Line 42-55. Line 60-61 vì vậy chạy lại năm tác vụ nặng và có thể làm vượttimeout-minutes: 35.Hãy dùng
pnpm checkthay cho các bước riêng lẻ, hoặc bỏ bước aggregate. Giữ riêngpnpm test:storybookvàpnpm test:e2e.🤖 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 @.github/workflows/playwright.yml around lines 60 - 61, The workflow is duplicating the frontend validation suite by running the same lint/typecheck/unit/build/Storybook checks again through the aggregate step. Update the Playwright workflow so the section around run `pnpm check` does not repeat the checks already covered earlier; either keep only `pnpm check` for the aggregate validation or remove that aggregate step entirely, while preserving the separate `pnpm test:storybook` and `pnpm test:e2e` steps.src/features/current-user/current-user-overview.tsx (1)
17-19: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winĐặt
timeZonerõ ràng cho định dạng ngày.
Intl.DateTimeFormatkhông cótimeZone. Component này render trên server, nên ngày được tính theo múi giờ của tiến trình server. Nếu người dùng ở múi giờ khác, "Joined BridgeWorks" và "Identity last updated" (dòng 169-181) có thể lệch một ngày.Thuộc tính
dateTimecủa thẻ<time>đã giữ giá trị ISO gốc, nên chỉ cần cố định múi giờ hiển thị.♻️ Đề xuất cố định múi giờ
const dateFormatter = new Intl.DateTimeFormat("en", { dateStyle: "medium", + timeZone: "UTC", });🤖 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/features/current-user/current-user-overview.tsx` around lines 17 - 19, Update the dateFormatter in the current-user overview component to specify the intended fixed display time zone via Intl.DateTimeFormat options. Keep the existing medium date formatting and the ISO value used by the time elements unchanged.src/features/current-user/current-user-loading.tsx (1)
3-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueBỏ
aria-labeltrùng với text sr-only.Phần tử
role="status"cóaria-labelvà đồng thời chứa<span className="sr-only">với cùng một chuỗi (dòng 25).aria-labelthay thế nội dung khi trình đọc màn hình tính tên phần tử. Giữ một nguồn văn bản duy nhất là đủ.♻️ Đề xuất giữ một nguồn văn bản
<div role="status" - aria-label="Loading your BridgeWorks account" className="space-y-8 sm:space-y-10" >🤖 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/features/current-user/current-user-loading.tsx` around lines 3 - 7, Remove the aria-label attribute from the role="status" container in the current-user loading component, keeping the existing sr-only span as the single accessible text source. Preserve the status role and all other loading markup unchanged.src/features/current-user/current-user-contract.ts (1)
8-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueChuyển các schema Zod sang API mới và giữ
z.object().strict().Dự án dùng Zod 4 nên dùng
z.email()thayz.string().email()vàz.iso.datetime({ offset: true })thayz.string().datetime({ offset: true }). Không dùngz.strictObject(...)vì.strict()không bị deprecated trong Zod 4; giữz.object(...).strict()ở đây là đủ.🤖 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/features/current-user/current-user-contract.ts` around lines 8 - 32, Update the Zod schemas in currentUserSchema and errorEnvelopeSchema to use the Zod 4 API: replace the string-based email and datetime validators with z.email() and z.iso.datetime({ offset: true }) in the existing z.object(...).strict() definitions. Keep the current z.object(...).strict() pattern unchanged, and do not switch to z.strictObject(...) since the review explicitly wants the strictness preserved via .strict().
🤖 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/app/`(protected)/app/page.tsx:
- Around line 17-22: Update the route guard around the experience status check
to call experience.redirectToSignIn with APP_ROUTE only for "signed-out". For
"unauthorized", allow rendering to continue so the existing unauthorized panel
in current-user-overview.tsx can prompt the user to sign in again without
creating a redirect loop.
In `@src/lib/bridgeworks-api-config.ts`:
- Around line 53-67: Update classifyBridgeWorksApiConfiguration() to require
https: for BridgeWorks API base URLs, while allowing http: only for explicitly
supported local development cases. In requestCurrentIdentityUser(), ensure the
Clerk Bearer token is never sent over an unprotected http: URL, or route such
requests through the configured secure proxy.
---
Nitpick comments:
In @.github/workflows/playwright.yml:
- Around line 60-61: The workflow is duplicating the frontend validation suite
by running the same lint/typecheck/unit/build/Storybook checks again through the
aggregate step. Update the Playwright workflow so the section around run `pnpm
check` does not repeat the checks already covered earlier; either keep only
`pnpm check` for the aggregate validation or remove that aggregate step
entirely, while preserving the separate `pnpm test:storybook` and `pnpm
test:e2e` steps.
In `@src/features/current-user/current-user-contract.ts`:
- Around line 8-32: Update the Zod schemas in currentUserSchema and
errorEnvelopeSchema to use the Zod 4 API: replace the string-based email and
datetime validators with z.email() and z.iso.datetime({ offset: true }) in the
existing z.object(...).strict() definitions. Keep the current
z.object(...).strict() pattern unchanged, and do not switch to
z.strictObject(...) since the review explicitly wants the strictness preserved
via .strict().
In `@src/features/current-user/current-user-loading.tsx`:
- Around line 3-7: Remove the aria-label attribute from the role="status"
container in the current-user loading component, keeping the existing sr-only
span as the single accessible text source. Preserve the status role and all
other loading markup unchanged.
In `@src/features/current-user/current-user-overview.tsx`:
- Around line 17-19: Update the dateFormatter in the current-user overview
component to specify the intended fixed display time zone via
Intl.DateTimeFormat options. Keep the existing medium date formatting and the
ISO value used by the time elements unchanged.
In `@tests/example.spec.ts`:
- Around line 77-82: Update the overflow test in the example spec to measure the
<main> element instead of document.documentElement, using the existing
page.evaluate block and the main element as the source of
scrollWidth/clientWidth so hidden horizontal overflow under the main container
is detected even when the root document width stays unchanged.
🪄 Autofix
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: CHILL
Plan: Pro Plus
Run ID: 6089c027-4d8f-4938-be16-19b89696452f
📒 Files selected for processing (28)
.github/workflows/playwright.ymlREADME.mdsrc/app/(protected)/app/error.tsxsrc/app/(protected)/app/loading.tsxsrc/app/(protected)/app/page.tsxsrc/app/globals.csssrc/app/layout.tsxsrc/app/page.tsxsrc/components/layout/app-navigation-link.tsxsrc/components/layout/app-navigation.tssrc/components/layout/app-shell.stories.tsxsrc/components/layout/app-shell.test.tsxsrc/components/layout/app-shell.tsxsrc/components/layout/mobile-app-navigation.tsxsrc/features/current-user/current-user-contract.test.tssrc/features/current-user/current-user-contract.tssrc/features/current-user/current-user-loading.tsxsrc/features/current-user/current-user-overview.stories.tsxsrc/features/current-user/current-user-overview.test.tsxsrc/features/current-user/current-user-overview.tsxsrc/features/current-user/current-user.service.server.tssrc/lib/bridgeworks-api-config.server.tssrc/lib/bridgeworks-api-config.test.tssrc/lib/bridgeworks-api-config.tssrc/lib/bridgeworks-api-core.test.tssrc/lib/bridgeworks-api-core.tssrc/lib/bridgeworks-api.server.tstests/example.spec.ts
📜 Review details
🔇 Additional comments (26)
src/app/page.tsx (1)
1-23: LGTM!Also applies to: 27-38, 40-85, 87-107
src/app/layout.tsx (1)
32-32: LGTM!Also applies to: 66-85
src/app/globals.css (1)
30-38: LGTM!Also applies to: 61-101, 104-144
tests/example.spec.ts (1)
4-25: LGTM!README.md (2)
3-28: LGTM!Also applies to: 39-109, 110-146, 147-156, 161-194, 196-211
37-37: 🔒 Security & PrivacySecurity Misconfiguration (CWE-319): Cleartext Transmission of Sensitive Information
Giới hạn HTTP cho môi trường local.
README.mdmô tả mọi originhttp://hoặchttps://là hợp lệ. Request current-user gửiAuthorization: Bearer <Clerk session token>tại Line 65 và Line 116. Nếu môi trường triển khai dùng HTTP ngoài loopback, token đi qua kết nối không mã hóa.server-only,credentials: "omit"vàCache-Control: no-storekhông bảo vệ hop mạng.Chỉ cho phép HTTP với loopback trong phát triển, hoặc từ chối HTTP ở môi trường triển khai. Xác minh thêm redirect không chuyển
Authorizationtới HTTP hoặc host không được ủy quyền.#!/usr/bin/env bash set -euo pipefail rg -n -C 8 \ 'NEXT_PUBLIC_API_BASE_URL|http:|https:|redirect|Authorization|fetch\(' \ src/lib/bridgeworks-api-config.ts \ src/lib/bridgeworks-api-config.server.ts \ src/lib/bridgeworks-api-core.ts \ src/lib/bridgeworks-api.server.tssrc/lib/bridgeworks-api-config.server.ts (1)
1-12: LGTM!src/features/current-user/current-user-overview.test.tsx (1)
1-89: LGTM!src/features/current-user/current-user-overview.stories.tsx (1)
1-137: LGTM!src/app/(protected)/app/error.tsx (1)
17-32: LGTM!src/components/layout/app-navigation.ts (1)
1-25: LGTM!src/components/layout/app-navigation-link.tsx (1)
1-36: LGTM!src/components/layout/app-shell.tsx (1)
3-4: LGTM!Also applies to: 17-21, 24-30, 46-50
src/components/layout/mobile-app-navigation.tsx (1)
3-10: LGTM!Also applies to: 22-22, 31-31, 55-58, 76-99
src/components/layout/app-shell.test.tsx (1)
3-23: LGTM!Also applies to: 37-39, 56-58
src/components/layout/app-shell.stories.tsx (1)
5-37: LGTM!Also applies to: 54-56
src/lib/bridgeworks-api-config.test.ts (1)
5-52: LGTM!src/lib/bridgeworks-api-core.ts (2)
37-81: LGTM!
100-111: 🔒 Security & Privacy | ⚡ Quick winSensitive Data Exposure (CWE-319): Cleartext Transmission of Sensitive Information
Reachability: Internal
Reachability path
● Entry src/app/layout.tsx:26 metadata │ ▼ ● Hop src/app/(protected)/app/page.tsx:9 metadata │ ▼ ● Hop src/features/current-user/current-user-overview.tsx:107 ReadyOverview │ ▼ ● Hop src/features/current-user/current-user-contract.ts:89 mapCurrentUserResponse │ ▼ ● Sink src/lib/bridgeworks-api-core.tsRàng buộc HTTPS cho request mang token phiên.
requestBridgeWorksApigắnAuthorization: Bearer ${token}vào mọi request.baseUrlđến từclassifyBridgeWorksApiConfiguration, hàm này chấp nhận cảhttp:vàhttps:(xemsrc/lib/bridgeworks-api-config.ts:34-80). Nếu môi trường triển khai đặtNEXT_PUBLIC_API_BASE_URLlà một originhttp://không phải loopback, token phiên Clerk đi qua kênh không mã hoá.
redirect: "manual"vàcredentials: "omit"chặn rò rỉ qua redirect và cookie, nhưng không bảo đảm bảo mật truyền tải.Đề xuất: chỉ cho phép
http:với host loopback, hoặc chặn gắn credential khi protocol không phảihttps:.🔒 Đề xuất chặn credential trên kênh không mã hoá
try { - const response = await fetcher(new URL(path, `${baseUrl}/`), { + const url = new URL(path, `${baseUrl}/`); + if ( + url.protocol !== "https:" && + url.hostname !== "127.0.0.1" && + url.hostname !== "localhost" && + url.hostname !== "::1" + ) { + return { kind: "network-error", requestId }; + } + const response = await fetcher(url, { method: "GET",Chạy script sau để xác nhận cấu hình base URL trong repo và tài liệu triển khai:
#!/bin/bash # Mục tiêu: kiểm tra mọi nơi khai báo NEXT_PUBLIC_API_BASE_URL và ràng buộc protocol. rg -n -C4 'NEXT_PUBLIC_API_BASE_URL' fd -H -t f -g '.env*' --exec rg -n 'API_BASE_URL' {} \; rg -n -C6 'hasSupportedProtocol|protocol ===' --glob '*.ts'src/lib/bridgeworks-api-core.test.ts (1)
8-131: LGTM!src/lib/bridgeworks-api.server.ts (1)
19-40: LGTM!src/features/current-user/current-user-contract.ts (1)
63-153: LGTM!src/features/current-user/current-user-contract.test.ts (1)
42-201: LGTM!src/features/current-user/current-user.service.server.ts (1)
37-109: LGTM!src/app/(protected)/app/loading.tsx (1)
1-5: LGTM!src/features/current-user/current-user-overview.tsx (1)
203-302: LGTM!
| if ( | ||
| experience.status === "signed-out" || | ||
| experience.status === "unauthorized" | ||
| ) { | ||
| return experience.redirectToSignIn({ returnBackUrl: APP_ROUTE }); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Trạng thái unauthorized có thể tạo vòng lặp chuyển hướng.
Trạng thái signed-out và unauthorized được xử lý chung. Hai trạng thái này khác nhau:
signed-out: Clerk không có phiên. Chuyển hướng tới sign-in là đúng.unauthorized: Clerk vẫn có phiên hợp lệ, nhưng backend Identity trả 401 hoặcgetToken()trảnull(xemsrc/features/current-user/current-user.service.server.tsdòng 68-79 và 94-99).
Nếu Clerk vẫn xem người dùng đã đăng nhập, trang sign-in chuyển hướng ngược về returnBackUrl: APP_ROUTE. Trang này gọi lại backend, nhận unauthorized lần nữa và chuyển hướng tiếp. Kết quả là vòng lặp chuyển hướng, không phải khôi phục phiên.
Hệ quả downstream: nhánh case "unauthorized" trong src/features/current-user/current-user-overview.tsx (dòng 239-256) đã có panel "Sign in again", nhưng nhánh này không bao giờ đạt tới từ route này.
Đề xuất: chỉ chuyển hướng cho signed-out, và render panel unauthorized để người dùng chủ động đăng nhập lại.
🐛 Đề xuất tách hai trạng thái
- if (
- experience.status === "signed-out" ||
- experience.status === "unauthorized"
- ) {
+ if (experience.status === "signed-out") {
return experience.redirectToSignIn({ returnBackUrl: APP_ROUTE });
}Chạy script sau để xác nhận hành vi middleware và route sign-in khi phiên Clerk còn hiệu lực:
#!/bin/bash
# Mục tiêu: kiểm tra middleware, route sign-in và cách redirectToSignIn được dùng.
fd -t f 'middleware.*' --exec cat -n {} \;
rg -n -C6 'redirectToSignIn|SIGN_IN_ROUTE|afterSignInUrl|forceRedirectUrl'
fd -t d 'sign-in' --exec tree {} \;🤖 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/app/`(protected)/app/page.tsx around lines 17 - 22, Update the route
guard around the experience status check to call experience.redirectToSignIn
with APP_ROUTE only for "signed-out". For "unauthorized", allow rendering to
continue so the existing unauthorized panel in current-user-overview.tsx can
prompt the user to sign in again without creating a redirect loop.
| try { | ||
| const url = new URL(normalized); | ||
| const hasSupportedProtocol = url.protocol === "http:" || url.protocol === "https:"; | ||
| const hasOriginOnlyPath = url.pathname === "/"; | ||
|
|
||
| if ( | ||
| !hasSupportedProtocol || | ||
| !url.hostname || | ||
| url.username || | ||
| url.password || | ||
| url.search || | ||
| url.hash || | ||
| !hasOriginOnlyPath | ||
| ) { | ||
| throw new Error("invalid BridgeWorks API base URL"); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg 'bridgeworks-api|me |AUTHORIZATION|Authorization|NEXT_PUBLIC_API_BASE_URL|CLERK|clerk' || true
echo
echo "== config files outline/contents =="
for f in $(git ls-files | rg 'src/lib/bridgeworks-api(-config\.server|\.server|-config)\.ts|src/lib/bridgeworks-api-config\.test\.ts$'); do
echo "--- $f ---"
wc -l "$f"
sed -n '1,220p' "$f" | cat -n
doneRepository: DoMinhHHung/BridgeWorksApps
Length of output: 6826
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "--- src/lib/bridgeworks-api-core.ts ---"
wc -l src/lib/bridgeworks-api-core.ts
sed -n '1,240p' src/lib/bridgeworks-api-core.ts | cat -n
echo
echo "--- call sites across repo ---"
rg -n "requestCurrentIdentityUser|requestBridgeWorksApi|/api/v1/me|Authorization|bearer|Bearer|setHeaders|followRedirect|redirect" src || trueRepository: DoMinhHHung/BridgeWorksApps
Length of output: 7879
Security Misconfiguration (CWE-319): Cleartext Transmission of Sensitive Information
Reachability: Internal
Reachability path
● Entry
src/lib/bridgeworks-api-config.server.ts:8
getBridgeWorksApiConfiguration
│
▼
● Sink
src/lib/bridgeworks-api-config.ts
Không gửi Clerk token qua cấu hình http:.
classifyBridgeWorksApiConfiguration() coi http: là hợp lệ; requestCurrentIdentityUser() sau đó gọi /api/v1/me với Authorization: Bearer ... vào URL http: đó. Đặt giới hạn cấu hình thành https: khi có thể; nếu cần local http:, đảm bảo token không được gửi hoặc được bảo vệ qua proxy.
🤖 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/lib/bridgeworks-api-config.ts` around lines 53 - 67, Update
classifyBridgeWorksApiConfiguration() to require https: for BridgeWorks API base
URLs, while allowing http: only for explicitly supported local development
cases. In requestCurrentIdentityUser(), ensure the Clerk Bearer token is never
sent over an unprotected http: URL, or route such requests through the
configured secure proxy.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f2e1479c5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ( | ||
| experience.status === "signed-out" || | ||
| experience.status === "unauthorized" | ||
| ) { | ||
| return experience.redirectToSignIn({ returnBackUrl: APP_ROUTE }); |
There was a problem hiding this comment.
Avoid looping backend-unauthorized sessions
When Identity returns 401 while Clerk still considers the browser signed in, this branch sends the user to the sign-in route, but SignInPage immediately redirects any signed-in Clerk session back to /app (src/app/(auth)/sign-in/[[...sign-in]]/page.tsx:42-44). That makes backend-unauthorized recovery a redirect loop instead of an actionable unauthorized state; keep these sessions on an explicit recovery/sign-out flow or clear the Clerk session before sending them to sign-in.
Useful? React with 👍 / 👎.
Objective
Replace the protected
/appengineering placeholder with the first real authenticated BridgeWorks vertical slice. The page obtains the current Clerk session token only on the server, calls Identity through APISIXGET /api/v1/me, validates the response, and renders product-facing account and lifecycle states.Backend contract
Verified from backend
main(DoMinhHHung/bridgeworks, commit81bb80f3252826f85c2f4fce7d58554d0d66a47c):GET /api/v1/methrough APISIX;Authorization: Bearer <Clerk session token>;X-Request-Id;idUUIDv7, publicid_usermatching^bw[0-9]{12}$, nullableprimary_email, exact statusactive, RFC 3339created_atandupdated_at;{code,message,request_id,details};401 unauthorized→ Clerk sign-in recovery;403 account_disabled→ disabled;403 account_deleted→ deleted;409 identity_not_ready→ not ready, preservingRetry-After(currently2);503 service_unavailable→ service unavailable;Cache-Control: no-storeand varies onAuthorization;The current Identity route has no verified stable 429 error code. Structurally valid HTTP 429 responses are mapped by status without inventing an Identity code.
Architecture
src/lib/bridgeworks-api-config.ts: pure base-origin validation for missing, placeholder, malformed, and configured states;src/lib/bridgeworks-api-config.server.ts:server-onlyenvironment boundary;src/lib/bridgeworks-api-core.ts: bounded timeout, bounded body,cache: "no-store",credentials: "omit", no redirects, Bearer header, and request-ID forwarding;src/lib/bridgeworks-api.server.ts: centralizedserver-onlyAPISIX client;src/features/current-user/current-user-contract.ts: strict Zod success/error decoding and stable status/code mapping;src/features/current-user/current-user.service.server.ts: Clerkauth().getToken()flow, request context, typed result union, safe structured diagnostics;src/features/current-user/current-user-overview.tsx: product UI mapping with no raw fetch logic.No page or Client Component receives the Clerk token. The internal Identity UUID is validated but not rendered. Backend request IDs and Retry-After guidance are preserved. Invalid JSON, empty/oversized bodies, unsupported statuses, and malformed schemas stop at safe non-data states.
UI changes
Create an accountand secondarySign inCTAs target real auth routes;/appshows public ID, nullable primary email, active state, joined date, and last Identity update;/appas return URL;aria-currentfrom the pathname;Security
Accessibility and responsive behavior
/,/sign-in,/sign-up, and fail-closed/appin all three configured browsers.Testing
Final GitHub Actions run
30994624563, job92268616260, completed successfully on final head8f2e1479c56f860117011d65cc7eb1bd0be65ded.Exact validation:
pnpm install --frozen-lockfile— passed;pnpm lint— passed;pnpm typecheck— passed;pnpm test— passed: 7 files, 69 tests;pnpm build— passed;/appremains dynamically server-rendered and no Client Component imported aserver-onlymodule;pnpm build-storybook— passed;pnpm test:storybook— passed: 6 files, 25 tests;pnpm check— passed, rerunning lint, typecheck, 69 unit tests, application build, and Storybook build;pnpm test:e2e— passed: 24 tests total, 8 each in Chromium, Firefox, and WebKit.Unit coverage includes API URL validation, strict success parsing, malformed success/error payloads, every verified backend lifecycle code, request-ID preservation, Retry-After seconds/date parsing, unsupported status, network failure, timeout, invalid JSON, empty response, oversized response, and no token/raw diagnostic exposure. Storybook contains ready, null email, not-ready, disabled, deleted, rate-limited, service-unavailable, unexpected, loading, mobile, and desktop presentations. Playwright covers product copy, auth CTAs, secretless auth-unavailable states, fail-closed
/app, axe, and overflow at 375/768/1024/1440 in Chromium, Firefox, and WebKit.The run emitted non-failing existing tooling warnings for the Vite native config-loader migration, Storybook chunk size, and GitHub Actions Node runtime migration. No package/tooling migration was added outside this vertical slice.
Manual authenticated smoke
Pending — not executed. The automated environment has no dedicated Clerk test instance, valid development credentials, or reachable local APISIX/Identity stack. README contains the full 15-step authenticated Identity checklist. No authenticated Clerk E2E pass is claimed.
Scope exclusions
Status
mainat3086aec3fa31439e9fba74f7123c71e4c97aee83;8f2e1479c56f860117011d65cc7eb1bd0be65ded;Summary by CodeRabbit
Tính năng mới
Cải tiến giao diện
Tài liệu & Kiểm thử