fix(dashboard): resolve P0/P1 issues from full visual audit#201
fix(dashboard): resolve P0/P1 issues from full visual audit#201ajitpratap0 wants to merge 1 commit intomainfrom
Conversation
Fix 6 issues identified during a comprehensive CDP-based visual audit
of the trading dashboard (Lighthouse, performance traces, network
analysis, responsive testing, and route-by-route screenshots).
P0 fixes (critical — blocked usage):
- Fix SystemStatusIndicator crash: guard Object.entries(services ?? {})
when API returns undefined services field (StatusDot.tsx:121)
- Add X-API-Key header to dashboard API client for authenticated
endpoints (/trades, /performance/*, /risk/*) via NEXT_PUBLIC_API_KEY
P1 fixes (high — degraded experience):
- Fix candlestick 404: route fetch through apiClient with /api/v1/
prefix instead of raw fetch to non-existent /market/ path
- Fix CLS (0.10 borderline): add min-h-[120px] to StatCard loading
skeletons and rendered cards to prevent layout shift
- Fix LCP (1,002ms render delay): extract static page header into
Server Component, push 'use client' boundary to DashboardContent
- Implement light mode: add next-themes with ThemeProvider, define
light CSS variables, persist theme choice via localStorage
Bonus: fix pre-existing CandlestickData type error blocking prod build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Label error. Requires at least 1 of: bug, enhancement, documentation, dependencies, performance, security, breaking-change. Found: |
|
PR Review placeholder - testing auth |
|
PR Review - fix(dashboard) P0/P1 visual audit fixes Good structured approach. The audit-driven methodology is clear and the fixes are well-scoped. SECURITY: NEXT_PUBLIC_API_KEY is bundled into client JavaScript Any NEXT_PUBLIC_* variable is inlined into the browser bundle at build time and visible to anyone who opens DevTools. An API key exposed this way is effectively public - it can be scraped and used to hit /admin/resolve-outcomes and trading endpoints directly. For a trading system, consider: (1) a thin Next.js API route that holds the key server-side and proxies requests, or (2) a short-lived JWT issued at login. At minimum, add a warning comment to .env.example noting browser bundle exposure and track the proper fix. Type assertion masks a real type mismatch (performance/page.tsx:33) The cast 'as CandlestickData[]' silences the compiler without fixing the underlying mismatch. Since getMarketCandlestick now returns ApiResponse<CandlestickData[]>, candlestickData?.data already has the right type. Remove the cast and prefer ?? over ||: Suspense boundary will not stream (app/page.tsx) DashboardContent is a use client component (it uses hooks). Client components cannot be streamed by Next.js App Router as async Server Components. The Suspense fallback shows during client hydration - still a real LCP win since the static header SSRs - but it is not streaming. The comment 'streams in after hydration' should be updated to avoid confusing future contributors. API key logic is duplicated in two places (lib/api.ts) Both ApiClient.request() and standalone buildHeaders() independently read process.env.NEXT_PUBLIC_API_KEY. If the header name or env var changes, two spots need updating. Consolidate by calling buildHeaders() inside ApiClient.request() as well. triggerOutcomeResolution lost its Content-Type header After this PR it uses buildHeaders() which only adds X-API-Key. If the backend expects Content-Type: application/json on POST requests this could fail silently. Pass Content-Type: application/json to buildHeaders() for that call. Minor notes:
What works well:
Summary: The P0 null crash and 401 fixes are correct and needed. Two things worth addressing before merge: (1) security caveat on NEXT_PUBLIC_API_KEY and (2) the type assertion in performance/page.tsx. The rest are low-risk improvements. |
Summary
Comprehensive fix for all P0 and P1 issues identified during a full visual audit of the CryptoFunk trading dashboard. The audit used 5 parallel CDP agents covering Lighthouse scores, performance traces, network analysis, responsive design, and route-by-route screenshots.
Before: Homepage crashed on load, 6 API endpoints returned 401, candlestick chart threw 404, no light mode, borderline CLS score, and slow LCP due to monolithic client component.
After: All 7 routes render successfully, API auth is configurable, light/dark/system theme toggle persists, LCP improved via Server Component extraction, CLS stabilized via skeleton dimension matching.
Changes
P0 — Critical (blocked usage)
components/ui/StatusDot.tsxservices ?? {}guard beforeObject.entries()— prevents crash when API returns undefined serviceslib/api.ts,.env.exampleX-API-Keyheader torequest()method and standalone fetch functions, sourced fromNEXT_PUBLIC_API_KEYenv varP1 — High (degraded experience)
hooks/usePerformance.ts,lib/api.tsfetch()withapiClient.getMarketCandlestick()using correct/api/v1/prefix and auth headers. Mock fallback preserved.components/ui/StatCard.tsxmin-h-[120px]to skeleton and rendered card containers, sparkline skeleton placeholder, subtitle skeletonapp/page.tsx, newcomponents/dashboard/DashboardContent.tsx'use client'page into Server Component (static header = LCP element) + Client Component (data-dependent content via Suspense)app/globals.css,app/layout.tsx,app/providers.tsx,app/settings/page.tsx,package.jsonnext-themes, addedThemeProviderwithdefaultTheme="dark", defined light CSS variables, replaced manual theme toggle withuseTheme()hook (persists via localStorage)Bonus
app/performance/page.tsx,lib/api.tsgetMarketCandlestick()return asApiResponse<CandlestickData[]>, addedCandlestickDataimport — unblocked production buildsAudit Evidence
The full audit ran 5 parallel CDP agents and produced:
lighthouse_auditperformance_start_tracelist_network_requestsnavigate_page+take_screenshotresize_page+emulateScreenshots saved in
audit-screenshots/(not committed).Test Plan
npx tsc --noEmit— 0 errorsnpm run build— all 7 routes compileNEXT_PUBLIC_API_KEYin.env.localand verify authenticated endpoints return 200Breaking Changes
None. Dark mode remains the default theme. All existing functionality preserved.
Remaining (P2/P3 — follow-up)
/riskpage (time formatting)🤖 Generated with Claude Code