Skip to content

fix: address 8 code-review findings from Cursor audit#9

Open
Cookie-Cat21 wants to merge 3 commits into
mainfrom
fix/code-review-findings
Open

fix: address 8 code-review findings from Cursor audit#9
Cookie-Cat21 wants to merge 3 commits into
mainfrom
fix/code-review-findings

Conversation

@Cookie-Cat21

Copy link
Copy Markdown
Member

Summary

Fixes 8 confirmed bugs surfaced by a code review of Cursor's recent work (PRs #1#6).

  • Wrong wallet account for borrower/SMEwalletAccountId was null-coalescing to "SEY-ACC-002" (Nimal's diaspora account) for borrower and SME personas. Their wallet_account_id is null, so useCurrentUser now returns null for those personas. wallet/page.tsx redirects them to their correct default route and guards all downstream consumers (useWalletRealtime, saveAllocationRules, SendMoneyModal, assistant deeplink).
  • Admin key in client bundleadminHeaders() was reading NEXT_PUBLIC_DEMO_ADMIN_KEY, which Next.js bundles into client JS. Removed the function; added app/api/admin/reset/route.ts (server route) that reads the non-public DEMO_ADMIN_KEY env var and proxies to the backend. Key never reaches the browser.
  • createPaymentSession / getPaymentStatus no timeout — both used raw fetch() with no AbortSignal. Added 15 s and 10 s timeouts respectively.
  • request() silently overwrote caller's signal — the hardcoded signal: AbortSignal.timeout(5000) came after ...options, overwriting any signal a caller passed. Changed to options?.signal ?? AbortSignal.timeout(5000).
  • AuthGuard blank flash — guard was returning null synchronously before the router.replace effect fired, causing a blank screen on every unauthenticated visit. Now returns the same loading spinner used during token validation.
  • PageEnter key={pathname} unmounted all page childrenkey={pathname} on the wrapper in AppShell forced a full subtree remount on every navigation, destroying modal state and re-firing all mount effects. Moved the key to the inner motion.div inside PageEnter (via usePathname()), so only the animated element re-creates.
  • getStoredToken missing try/catchlocalStorage.getItem() can throw SecurityError in sandboxed iframes. Added try/catch to match the sibling getStoredSession.
  • getYDomain([])[NaN, Infinity]Math.min(...[]) returns Infinity; replaced with a safe for...of loop and added an empty-array guard returning [0, 100].

Test plan

  • Log in as diaspora persona → wallet page loads with correct account data
  • Log in as borrower persona → navigating to /wallet redirects to /loans
  • Log in as SME persona → navigating to /wallet redirects to /business
  • Visiting a protected route while logged out shows the loading spinner (not a blank flash) then redirects to /login
  • Navigating between pages animates without destroying SendMoneyModal open state on the wallet page
  • POST /api/admin/reset works (demo reset button) — confirm DEMO_ADMIN_KEY is set in .env.local
  • TypeScript: npx tsc --noEmit passes with no new errors

🤖 Generated with Claude Code

Cookie-Cat21 and others added 3 commits June 19, 2026 18:51
- walletAccountId: return null for borrower/SME instead of falling back
  to the diaspora account 'SEY-ACC-002'; wallet/page.tsx redirects to
  the persona's default route when walletAccountId is null, preventing
  wrong-account reads and saveAllocationRules mutations
- admin reset key: remove NEXT_PUBLIC_DEMO_ADMIN_KEY from client bundle;
  add app/api/admin/reset/route.ts server proxy that reads DEMO_ADMIN_KEY
  server-side only
- createPaymentSession / getPaymentStatus: add AbortSignal.timeout
  (15 s / 10 s) — both previously had no timeout and could hang forever
- request() signal: use options?.signal ?? AbortSignal.timeout(5000) so
  callers can supply their own AbortSignal without it being overwritten
- AuthGuard: show loading spinner instead of null while redirect is
  pending, eliminating the blank-screen flash on unauthenticated visits
- PageEnter: move key={pathname} onto the inner motion.div via
  usePathname(); remove it from AppShell so the wrapper component stays
  mounted across navigations — no more full subtree remounts
- getStoredToken: wrap localStorage.getItem in try/catch, matching
  getStoredSession, so SecurityError in sandboxed iframes doesn't throw
  on every API request
- getYDomain: guard empty-array input ([0,100] fallback) and replace
  Math.min/max spread with a loop to avoid RangeError on large datasets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded GBP/USD/EUR/AUD→LKR fixtures with a live fetch from
open.er-api.com (no API key required). Rates are cached in-process for
1 hour; on failure the service falls back to the previous fixture values
so the demo never breaks. Both the /api/fx router endpoint (async) and
the MCP tool handler (sync) use the shared cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove openai package from requirements.txt
- Delete openai_client.py
- groq_client.py is now self-contained (no OpenAI fallback check)
- claude_client.py proxies directly to groq_client
- stt.py uses Groq Whisper (whisper-large-v3-turbo) for transcription
- config.py: remove openai_api_key and supabase legacy fields
- .env.example: simplified to reflect Groq + Neon-only stack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cursor cursor Bot deleted the fix/code-review-findings branch June 19, 2026 15:05
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontend Ready Ready Preview, Comment Jun 19, 2026 4:22pm

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.

1 participant