Skip to content

Staging#217

Merged
Shashank0701-byte merged 11 commits into
mainfrom
staging
Jun 28, 2026
Merged

Staging#217
Shashank0701-byte merged 11 commits into
mainfrom
staging

Conversation

@Shashank0701-byte

@Shashank0701-byte Shashank0701-byte commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a new SystemCraft landing experience with animated sections, live system visuals, and a refreshed homepage flow.
    • Introduced a shared authentication layout with richer sign-in/sign-up progress states and updated loading screens.
    • Added dashboard command palette/search, workspace telemetry, and more detailed canvas/interview analytics views.
  • Bug Fixes

    • Improved access control for dashboard and practice pages.
    • Strengthened rendered markdown safety on reference architecture pages.
    • Updated Redis connectivity to be more reliable in networked environments.

- complete overhaul to the previous ui
- dedicated faq section
- footer
- features
- navbar polished
- cta polished
- faq console polished
- new login ui
- Authenticating…
Session Verified
Workspace Located
Loading Architecture…
Ready.
…verall wibe of the site

- Black dark sleek
- removed the purple background
- the interview ui
- the report card, the analysis
- the reference archs
Revamp UI for landing page and dashboard with new features
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
system-craft Ready Ready Preview, Comment Jun 28, 2026 4:49am

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Shashank0701-byte, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 15 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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

🚦 How do rate 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 see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e61b814d-c312-4a23-a55d-62efef21e494

📥 Commits

Reviewing files that changed from the base of the PR and between 7cfa44b and 16663ad.

📒 Files selected for processing (13)
  • app/dashboard/layout.tsx
  • app/dashboard/reference-architectures/[id]/page.tsx
  • app/practice/page.tsx
  • components/AuthCard.tsx
  • components/canvas/CanvasPanelsContext.tsx
  • components/canvas/DesignCanvas.tsx
  • components/canvas/PropertiesPanel.tsx
  • components/dashboard/DesignCard.tsx
  • components/landing/SystemCraftLanding.tsx
  • src/hooks/useRequireAuth.ts
  • tests/auth.spec.ts
  • tests/landing.spec.ts
  • tests/navigation.spec.ts
📝 Walkthrough

Walkthrough

This PR performs a comprehensive visual and functional overhaul of SystemCraft. It introduces a new animated landing page (SystemCraftLanding) with Framer Motion, replaces the auth pages with a shared AuthLayout/SystemStatusPanel and a multi-phase authPhase state machine in AuthCard, adds a command-palette to the dashboard header, replaces DesignCard with a deterministic SVG topology preview, rewrites SimulationControls as a live telemetry dashboard, and re-skins every major page surface. Functional changes include Redis IPv4 forcing, a Gemini model bump, connectionCount in the designs API, and useRequireAuth gating on the dashboard layout and practice page.

Changes

SystemCraft Full Redesign

Layer / File(s) Summary
Global tokens, fonts, animations, and infrastructure fixes
app/globals.css, app/layout.tsx, package.json, src/lib/redis.ts, app/api/reference-architectures/analyze/route.ts
CSS theme tokens, new keyframe animations (float, node-pulse, mesh-drift, noise overlay), grid pattern and scrollbar colors updated; Plus Jakarta Sans and JetBrains Mono fonts added; framer-motion dependency added; Redis forced to IPv4; Gemini model constant bumped to gemini-2.5-flash.
New landing page and background environment
app/page.tsx, components/landing/SystemCraftLanding.tsx, components/landing/engine/InfrastructureEnvironment.tsx, components/landing/engine/renderers/*
Home now returns only SystemCraftLanding; new InfrastructureEnvironment composes BlueprintGrid, LightingRenderer, and NoiseRenderer; full landing page implements animated NodeGraph hero with phase sequencing, TimelineSection with scroll-progress tracking, ScenariosSection with timed rotation, FaqSection as console-style accordion, a live-system demo panel, and footer.
AuthLayout, SystemStatusPanel, and simplified login/signup
components/auth/AuthLayout.tsx, components/auth/SystemStatusPanel.tsx, app/login/page.tsx, app/signup/page.tsx
New AuthLayout provides ambient background, left desktop SystemStatusPanel column (animated SVG topology, metrics, session block), and right form slot; login and signup pages reduced to <AuthLayout><AuthCard mode="…" /></AuthLayout>.
AuthCard multi-phase state machine
components/AuthCard.tsx
Adds authPhase state cycling idle → authenticating → verifying → locating → loading_arch → ready → redirect; handleProviderSignIn and handleEmailSubmit drive phase transitions and reset to idle on error; new overlay checklist/progress UI renders during non-idle phases; signup shows "Initializing Workspace" entry screen; all form/OAuth/footer sections restyled.
Dashboard auth gating, KPI data, and connectionCount API
app/dashboard/layout.tsx, app/practice/page.tsx, app/dashboard/page.tsx, app/api/designs/route.ts, app/dashboard/reference-architectures/[id]/page.tsx
DashboardLayout and practice page enforce useRequireAuth; dashboard page fetches /api/user/analytics and /api/health, computes kpis via useMemo; /api/designs GET response includes connectionCount; reference-architecture AI analysis markdown is sanitized via sanitizeHtml(renderMarkdown(content)).
Dashboard shell: Sidebar, Header command palette, Hero, DesignCard, CreateDesignCard
components/dashboard/Sidebar.tsx, components/dashboard/Header.tsx, components/dashboard/Hero.tsx, components/dashboard/DesignCard.tsx, components/dashboard/CreateDesignCard.tsx
Sidebar rebuilt with workspaceItems/systemItems, ProfileSettingsModal, and focus management. Header adds ⌘K command palette with filteredCommands. Hero adds onCreateDesign/isCreating props and "Provision Sandbox" button. DesignCard replaced with deterministic SVG topology preview seeded from id plus connectionCount. CreateDesignCard updated with cluster metadata block.
CanvasPanelsContext activeView and ComponentPalette catalog
components/canvas/CanvasPanelsContext.tsx, components/canvas/ComponentPalette.tsx
CanvasPanelsContext adds activeView (architecture|whiteboard) persisted in sessionStorage; switching to whiteboard auto-closes panels. ComponentPalette refactored into searchable, collapsible catalog with recently-used tracking; drag payload simplified; returns null in whiteboard mode.
DesignCanvas interaction refactor and render overhaul
components/canvas/DesignCanvas.tsx
Replaces rAF auto-fit with ResizeObserver bounding-box zoom/pan; separates canvas-pan from node-mousedown handlers; adds tool hotkeys; changes connection anchor offsets; label edits trigger immediate save bypassing debounce; large render overhaul adds blueprint grid/vignette overlays, animated connections, and updated node visual states.
Canvas side panels: CanvasHeader, PropertiesPanel, SimulationControls, AIFeedbackPanel, Whiteboard
components/canvas/CanvasHeader.tsx, components/canvas/PropertiesPanel.tsx, components/canvas/SimulationControls.tsx, components/canvas/AIFeedbackPanel.tsx, components/canvas/Whiteboard.tsx, components/canvas/WhiteboardClient.tsx
CanvasHeader adds onAIReview/onBack props and monospaced save-status indicators. PropertiesPanel rewritten with collapsible sections; returns null in whiteboard mode. SimulationControls rewritten with useMetricHistory hook, DashboardMetric sparklines, health indicator, and chaos/scaling badges. AIFeedbackPanel and whiteboard toolbar restyled.
Dashboard and canvas page-level re-skins
app/canvas/[id]/page.tsx, app/dashboard/analytics/page.tsx, app/dashboard/reference-architectures/..., app/dashboard/report-card/page.tsx
Canvas loading/error states replaced with dark animated placeholders; analytics page charts restyled with new Recharts theming; reference-architectures list and detail pages reskinned; report-card radar chart, sparklines, and score tiles restyled.
Interview and practice page re-skins with auth gating
app/interview/page.tsx, app/interview/[id]/result/page.tsx, app/practice/page.tsx, app/practice/[id]/page.tsx
Interview hub restyled with updated DIFFICULTY_CONFIG/STATUS_CONFIG and session cards. Interview result page restyles score SVG gradient, AI Insights panel, transcript bubbles, and submitted architecture panel. Practice pages add useRequireAuth gating and restyle template cards and problem overlays.
Copilot frontend design specification documents
Copilot/.frontendskills/*
Adds four markdown guides covering SystemCraft development philosophy, authentication design brief, canvas redesign spec, and background design guidelines.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Shashank0701-byte/System-Craft#80: Both PRs restructure components/AuthCard.tsx's authentication flow — this PR adds the multi-phase authPhase state machine and overlay UI on top of the email/provider sign-in paths PR #80 introduced.
  • Shashank0701-byte/System-Craft#98: Both PRs modify components/canvas/DesignCanvas.tsx and components/canvas/SimulationControls.tsx simulation/telemetry wiring in the same files.
  • Shashank0701-byte/System-Craft#144: Both PRs modify app/dashboard/reference-architectures/[id]/page.tsx annotations and AI analysis panel rendering in the same detail-page component.

Poem

🐇 Hop, hop — the canvas glows,
Blueprint grids and metric rows,
Auth phases tick, the cluster spins,
A topology born from id's twins.
Command palettes open wide,
SystemCraft redesigned inside! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too vague to describe the PR’s main changes and reads like a branch name rather than a summary. Rename it to a concise summary of the primary change, such as the new SystemCraft dashboard/auth/canvas redesign.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 staging

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.

@netlify

netlify Bot commented Jun 28, 2026

Copy link
Copy Markdown

Deploy Preview for system-craft-staging ready!

Name Link
🔨 Latest commit 16663ad
🔍 Latest deploy log https://app.netlify.com/projects/system-craft-staging/deploys/6a40a7a5edf95b0008144c8b
😎 Deploy Preview https://deploy-preview-217--system-craft-staging.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
components/AuthCard.tsx (1)

117-140: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Mirror the email flow's syncFailed lifecycle in the provider path.

This handler never clears stale syncFailed state before starting, and its catch block never marks provider sync failures. That creates two reachable bad states: after one email sync error, a later successful OAuth login gets stuck because the Lines 83-110 sequence bails out while syncFailed is still true; and if /api/user syncing throws after Firebase auth succeeds, the Lines 75-80 redirect guard can still send the user to /dashboard without a synced app user.

🤖 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 `@components/AuthCard.tsx` around lines 117 - 140, The provider sign-in flow in
AuthCard should mirror the email flow’s syncFailed lifecycle: clear any stale
syncFailed state before starting the OAuth sign-in, and set syncFailed to true
if syncUserWithDB fails after Firebase auth succeeds. Update the sign-in handler
around signInFn, syncUserWithDB, and the catch/finally path so the redirect
guard and post-login state checks behave consistently with the email flow.
components/canvas/DesignCanvas.tsx (1)

378-390: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep setSelectedNode synchronized on every selection path.

Only the normal node-selection flow updates the panels context. Undo/redo, delete, impacted-node clicks, and connection selection change local ids without refreshing/clearing setSelectedNode, so the properties panel can show stale node data after the visible selection changed.

Also applies to: 710-722, 1009-1015, 1133-1143

🤖 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 `@components/canvas/DesignCanvas.tsx` around lines 378 - 390, Keep the
properties-panel selection state in sync with all selection changes by updating
or clearing setSelectedNode everywhere a selection is changed, not just in the
normal node-select path. In handleUndo, handleRedo, the delete/impacted-node
handlers, and the connection-selection logic in DesignCanvas, make sure the same
selection transitions also refresh the panels context so stale node details are
not left behind. Use the existing selection handlers and local selection state
in DesignCanvas to locate each path and apply the same setSelectedNode
synchronization consistently.
🟡 Minor comments (15)
Copilot/.frontendskills/Auth.design.md-533-539 (1)

533-539: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix truncated/orphaned content at document end.

Lines 533-539 appear to be incomplete sentences or notes pasted without context ("A subtle 'Initializing Workspace...' animation before the form appears..."). These lack section headers and seem like draft notes that should be integrated into Section 14 (Loading & Interaction States) or removed.

🤖 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 `@Copilot/.frontendskills/Auth.design.md` around lines 533 - 539, The end of
the Auth.design.md document contains orphaned draft notes with no section
context, so either move them into the Loading & Interaction States section or
remove them entirely. Use the existing Section 14 / “Loading & Interaction
States” area and the nearby document structure to integrate the “Initializing
Workspace…”, live status indicator, and post-login sequence notes as proper
bullets or prose instead of leaving standalone fragments. Ensure the final
document ends cleanly with complete, context-rich content rather than truncated
sentences.
app/practice/page.tsx-20-20 (1)

20-20: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Gate the template fetch on auth resolution.

useRequireAuth() now makes unauthenticated visits a redirect-only path, but the mount effect at Lines 25-50 still calls /api/templates before auth settles. That wastes a request on every redirect and will surface noisy errors if the API later requires auth. Start the load only after !authLoading && isAuthenticated.

Also applies to: 52-63

🤖 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 `@app/practice/page.tsx` at line 20, Gate the template loading effect in
page.tsx on auth resolution: the current mount flow still fetches /api/templates
before useRequireAuth() finishes, even though unauthenticated users will
redirect. Update the effect(s) that load templates so they only run once
authLoading is false and isAuthenticated is true, and keep the existing fetch
logic in the same template-loading path so no request is made during
redirect-only visits.
components/dashboard/Sidebar.tsx-177-181 (1)

177-181: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Render the settings modal once outside sidebarContent.

Because sidebarContent is reused for both the desktop aside (Line 188) and the mobile aside (Line 210), putting ProfileSettingsModal inside that subtree mounts two dialog instances whenever the mobile drawer is open. That leaves duplicate modal DOM and duplicate form ids on the page. Hoist the modal next to the two asides and render it once.

🤖 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 `@components/dashboard/Sidebar.tsx` around lines 177 - 181, The
ProfileSettingsModal is currently rendered inside sidebarContent, which causes
it to mount twice when that shared subtree is used by both the desktop and
mobile asides. Move the ProfileSettingsModal render out of sidebarContent in
Sidebar so it sits alongside the two aside blocks and is instantiated only once,
while keeping isProfileModalOpen and setIsProfileModalOpen handling unchanged.
components/dashboard/DesignCard.tsx-265-286 (1)

265-286: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hide or disable the unimplemented menu items.

"Rename" and "Duplicate" currently just close the menu, so they look functional but do nothing. That is a confusing dead-end in a primary card action menu.

🤖 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 `@components/dashboard/DesignCard.tsx` around lines 265 - 286, The “Rename” and
“Duplicate” actions in DesignCard’s menu are currently dead-end buttons that
only close the dropdown, so either hide them or disable them until the handlers
are implemented. Update the menu item rendering in DesignCard so these options
are not presented as active actions unless their onClick logic actually performs
rename/duplicate behavior, and keep the menu’s existing close behavior only for
valid actions.
app/dashboard/page.tsx-311-325 (1)

311-325: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Wire these layout controls or present them as disabled placeholders.

These buttons and the sort <select> currently have no onClick/onChange behavior, so they advertise grid/list and sorting options that never change the view. Either connect them to local state or mark them as coming soon to avoid a dead control surface.

🤖 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 `@app/dashboard/page.tsx` around lines 311 - 325, The layout controls in the
dashboard header are currently decorative only, so either wire the grid/list
buttons and the sort select to real state in dashboard/page.tsx or clearly
disable/label them as coming soon. Update the relevant controls in the layout
controls block to use handlers and state for view mode and sorting, or make them
non-interactive placeholders so they do not imply functionality that is not
implemented.
app/dashboard/analytics/page.tsx-139-145 (1)

139-145: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Point this CTA at the interview flow.

This empty state tells the user to “Start Interview”, but the link still routes to /dashboard. That makes the first-run path misleading; send it to /interview or rename the CTA to match the dashboard destination.

🤖 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 `@app/dashboard/analytics/page.tsx` around lines 139 - 145, The CTA in the
analytics empty state is misleading because the Link labeled “Start Interview”
still points to the dashboard. Update the Link in the analytics page empty-state
section so its href matches the interview flow destination, or if you keep the
current destination, rename the CTA text to match; use the Link element and the
“Start Interview” label as the locating symbols.
components/dashboard/Header.tsx-25-38 (1)

25-38: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Match the keyboard hints to the behavior you actually implement.

The palette footer promises ↑↓ navigation and execution, but this handler only supports Ctrl/Cmd+K and Escape. Either add active-item arrow/Enter handling or remove those hints for now; as-is the palette advertises controls that do nothing.

Also applies to: 280-284

🤖 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 `@components/dashboard/Header.tsx` around lines 25 - 38, The command palette
shortcuts in Header should match the behavior actually implemented: the current
handleKeyDown/useEffect only supports Cmd/Ctrl+K and Escape, so either add real
↑↓ active-item navigation and Enter/⏎ execution in the command palette logic or
remove those footer hints until they work. Update the relevant Header.tsx
keyboard handling and any palette item selection/submit handlers so the
advertised controls in the footer are functional.
components/dashboard/Header.tsx-188-201 (1)

188-201: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t ship a dead “Help & Support” action.

Line 198 renders this as a clickable button, but it has no handler or destination, so users can never complete the action. Wire it to a route/modal or render it as non-interactive until the target exists.

🤖 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 `@components/dashboard/Header.tsx` around lines 188 - 201, The Header
dropdown’s “Help & Support” control is interactive but currently has no behavior
attached. Update the button in Header so it either uses the same open/close
pattern as the Settings action to launch the appropriate modal/route, or render
it as a non-interactive element until that destination exists. Use the existing
dropdown button markup near the Settings button as the reference point and keep
the user flow consistent with the current setIsDropdownOpen handling.
components/canvas/CanvasPanelsContext.tsx-67-75 (1)

67-75: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hydrate activeView before the first render. On reloads that should reopen whiteboard, the provider still starts in architecture, so DesignCanvas mounts the wrong branch once before the effect switches it over. Gate the UI until the saved value is loaded, or restore it during initialization.

🤖 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 `@components/canvas/CanvasPanelsContext.tsx` around lines 67 - 75, The
activeView state in CanvasPanelsContext currently initializes to architecture
and only reads sessionStorage inside useEffect, so DesignCanvas renders the
wrong branch before hydration. Update CanvasPanelsContext so the saved
canvasActiveView is restored during state initialization (or add a loading gate
until it is read) using the activeView/setActiveViewRaw state and the existing
sessionStorage key, ensuring the first render matches the persisted tab.

Source: Linters/SAST tools

components/canvas/DesignCanvas.tsx-300-301 (1)

300-301: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the hard-coded geometry to match the new 160×64 node cards.

The renderer now uses w-[160px] h-[64px], but auto-fit, edge anchors, and drop centering still use the old 144/56/72/28 values. That leaves links anchored inside the card, mis-centers drops, and underestimates the read-only bounding box.

Also applies to: 415-418, 445-446, 469-470, 998-998

🤖 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 `@components/canvas/DesignCanvas.tsx` around lines 300 - 301, The geometry
constants in DesignCanvas are still using the old node-card size, so update the
hard-coded width/height and any derived anchor/centering values to match the new
160×64 cards. Fix the related calculations in the auto-fit logic, edge anchor
math, drop centering, and read-only bounding box paths by adjusting the
constants and expressions around NODE_WIDTH, NODE_HEIGHT, and the other old
72/28-based offsets so they reference the new card dimensions consistently.
app/globals.css-183-185 (1)

183-185: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Gate smooth scrolling behind prefers-reduced-motion.

This forces animated anchor jumps for users who explicitly disabled motion, and the new landing-page section links will hit this path immediately.

Suggested fix
-html {
-  scroll-behavior: smooth;
-}
+@media (prefers-reduced-motion: no-preference) {
+  html {
+    scroll-behavior: smooth;
+  }
+}
🤖 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 `@app/globals.css` around lines 183 - 185, The global html scroll-behavior rule
is forcing smooth scrolling for all users, including those who prefer reduced
motion. Update the html rule in globals.css to apply smooth scrolling only when
the user has not requested reduced motion, using a prefers-reduced-motion media
query around the existing scroll-behavior setting so the landing-page section
links still work without animating for motion-sensitive users.
components/landing/engine/InfrastructureEnvironment.tsx-8-8 (1)

8-8: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hide the ambient background from the accessibility tree.

This subtree is decorative only, but BlueprintGrid contains real SVG text nodes. Without aria-hidden, screen readers can pick up that noise before the actual landing-page content.

Suggested fix
-    <div className="fixed inset-0 w-full h-full bg-[`#020306`] overflow-hidden pointer-events-none select-none z-0">
+    <div
+      aria-hidden="true"
+      className="fixed inset-0 w-full h-full bg-[`#020306`] overflow-hidden pointer-events-none select-none z-0"
+    >
🤖 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 `@components/landing/engine/InfrastructureEnvironment.tsx` at line 8, The
decorative ambient background in InfrastructureEnvironment should be hidden from
assistive tech because BlueprintGrid and its SVG text are non-content noise.
Update the top-level wrapper in InfrastructureEnvironment to include aria-hidden
so the entire background subtree is excluded from the accessibility tree while
keeping the visual effect unchanged.
components/landing/SystemCraftLanding.tsx-944-962 (1)

944-962: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Expose accordion state to assistive tech.

These buttons toggle content visually, but they never announce whether the panel is open. Add aria-expanded and wire each trigger to its panel with aria-controls/id.

Suggested fix
                         <button
+                          type="button"
                           onClick={() => setOpenIndex(isOpen ? null : i)}
+                          aria-expanded={isOpen}
+                          aria-controls={`${activeCategory}-faq-${i}`}
                           className="flex w-full items-center justify-between p-4 text-left text-sm text-cyan-400/80 transition-all duration-[400ms] ease-[cubic-bezier(0.16,1,0.3,1)] hover:bg-cyan-950/10 hover:text-cyan-300"
                         >
...
                             <motion.div
+                              id={`${activeCategory}-faq-${i}`}
                               initial={{ height: 0, opacity: 0 }}
                               animate={{ height: "auto", opacity: 1 }}
                               exit={{ height: 0, opacity: 0 }}
🤖 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 `@components/landing/SystemCraftLanding.tsx` around lines 944 - 962, Update the
FAQ accordion trigger in SystemCraftLanding so assistive tech can detect its
state: the button that toggles `setOpenIndex(isOpen ? null : i)` should expose
`aria-expanded`, and each panel rendered inside `AnimatePresence`/`motion.div`
should have a stable `id` that the button references via `aria-controls`. Keep
the identifiers tied to the FAQ item index or similar unique value so the
trigger and its corresponding panel stay linked even if the list changes.
components/landing/SystemCraftLanding.tsx-768-770 (1)

768-770: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use Tailwind arbitrary easing syntax here

cubic-bezier(0.16,1,0.3,1) is a bare class token, so Tailwind won’t apply it. These transitions fall back to the default timing curve; use ease-[cubic-bezier(0.16,1,0.3,1)] here and in the matching category buttons below.

Suggested fix
- className={`group relative flex items-center px-6 py-4 text-left transition-all duration-[400ms] cubic-bezier(0.16,1,0.3,1) ${
+ className={`group relative flex items-center px-6 py-4 text-left transition-all duration-[400ms] ease-[cubic-bezier(0.16,1,0.3,1)] ${
🤖 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 `@components/landing/SystemCraftLanding.tsx` around lines 768 - 770, The
transition class in SystemCraftLanding’s item and matching category button
styles is using a bare cubic-bezier token that Tailwind will ignore. Update the
className strings around the active item styling and the category button
variants to use Tailwind’s arbitrary easing syntax with
ease-[cubic-bezier(0.16,1,0.3,1)] so the intended timing curve is applied
consistently.
components/landing/SystemCraftLanding.tsx-1071-1100 (1)

1071-1100: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Read reduced-motion from the media query on render
setReduceMotion(matches) runs after the first paint, so reduced-motion users still see the animated state briefly, and the component won’t react if the OS setting changes later. useReducedMotion() or a subscribed media-query hook avoids both.

🤖 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 `@components/landing/SystemCraftLanding.tsx` around lines 1071 - 1100, The
reduced-motion flag in SystemCraftLanding is being set only after mount via the
current useEffect, so the initial render can still animate and later OS
preference changes are missed. Replace the local reduceMotion state + matchMedia
setup in SystemCraftLanding with a subscribed media-query hook such as
useReducedMotion() or an equivalent reactive hook, and keep the
animation/interval effects keyed off that value so the phase sequence and
cluster rotation stop immediately when reduced motion is enabled.

Source: Linters/SAST tools

🧹 Nitpick comments (3)
Copilot/.frontendskills/Updates.md (1)

246-246: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fix hyphenation: "slow-moving gradients".

Change "slow moving gradients" to "slow-moving gradients" for correct compound modifier grammar. This prevents propagation to code comments or derived documentation.

🤖 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 `@Copilot/.frontendskills/Updates.md` at line 246, The phrase in the Updates.md
content should use the correct compound modifier form: change “slow moving
gradients” to “slow-moving gradients.” Update the wording where it appears in
the documentation so any copied or derived text also uses the hyphenated form.
components/auth/AuthLayout.tsx (1)

1-24: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Keep the auth shell server-rendered.

Neither this component nor components/auth/SystemStatusPanel.tsx uses hooks or browser APIs, so this client boundary ships the decorative auth chrome to the browser unnecessarily. Moving the client boundary down to AuthCard preserves behavior with less JS on every auth visit.

♻️ Proposed change
-"use client";

If components/auth/SystemStatusPanel.tsx stays hook-free, drop its client directive too.

🤖 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 `@components/auth/AuthLayout.tsx` around lines 1 - 24, AuthLayout is marked as
a client component even though it and SystemStatusPanel do not use hooks or
browser APIs, which unnecessarily pushes the auth shell to the client. Remove
the client boundary from AuthLayout and keep the shell server-rendered, then
move any needed client-only behavior down to AuthCard so the existing layout and
rendering stay the same with less JS. Also verify SystemStatusPanel remains
hook-free and remove its client directive too if it is still present.
components/dashboard/DesignCard.tsx (1)

91-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove or use the dead mock metric memos.

mockLatency and mockComplexity are never read, so this adds extra memoization work and leaves the file with active lint/typecheck warnings. Either surface them in the card UI or delete them for now.

🤖 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 `@components/dashboard/DesignCard.tsx` around lines 91 - 98, The DesignCard
component has dead mock metric memo values that are computed but never used. In
DesignCard, either wire mockLatency and mockComplexity into the rendered UI so
they are actually displayed, or remove the useMemo blocks entirely if they are
not needed yet. Keep the fix localized to the DesignCard component and ensure no
unused-variable lint/typecheck warnings remain.

Source: Linters/SAST tools

🤖 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 `@app/dashboard/reference-architectures/`[id]/page.tsx:
- Around line 351-365: The markdown rendering path in the reference architecture
page is passing raw model output from renderMarkdown() directly into
sanitizeHtml(), which can still allow unsafe allowed tags/styles through to
dangerouslySetInnerHTML. Update the content pipeline in the page component to
escape or normalize the model text before markdown conversion, or replace the
current renderMarkdown()/sanitizeHtml() flow with a vetted
markdown-plus-sanitizer pipeline so only renderer-generated tags survive. Keep
the fix localized to the markdown body rendering block and preserve the
streaming indicator behavior.

In `@app/practice/`[id]/page.tsx:
- Around line 181-186: The back control in the practice page header is
implemented as a clickable div with router.push, which makes it inaccessible to
keyboard users. Replace the div with a real button or link in the same spot, and
wire the navigation through the existing router.push('/practice') behavior so
the control remains focusable and operable. Keep the visual styling and the
arrow_back icon, but ensure the accessible element is the one handling the
action.

In `@app/practice/page.tsx`:
- Around line 65-69: Add a mobile sidebar trigger for the practice page because
Sidebar is mounted without any way to open its drawer on mobile. Update
app/practice/page.tsx to include a toggle that drives useSidebar().isOpen, or
reuse the same sidebar toggle behavior used in components/dashboard/Header.tsx,
so mobile users can open navigation and settings from this page.

In `@components/AuthCard.tsx`:
- Around line 123-126: The null-check after calling signInFn in AuthCard should
not be treated as a failed login, because signInWithGoogle and signInWithGitHub
can return null when initiating a redirect flow. Update the sign-in handling so
redirect-based providers bypass the failure branch, and only
setSignInError/setAuthPhase('idle') when a real authentication error occurs; use
the existing signInFn, provider, and auth phase logic in AuthCard to keep the
flow in progress during redirects.

In `@components/canvas/DesignCanvas.tsx`:
- Around line 725-759: In DesignCanvas’s keyboard handler inside the useEffect
block, undo/redo shortcuts are still firing even when an input, textarea, or
contenteditable editor owns focus, so they affect the canvas graph while editing
text. Add the same focused-editor guard used for Delete/Backspace and tool
shortcuts before handling the Ctrl/Cmd+Z and Ctrl/Cmd+Y branches, and keep the
logic in handleKeyDown from triggering handleUndo or handleRedo when the
whiteboard text tool or any inline editor is active.
- Around line 544-547: The drag offset calculation in DesignCanvas’s node drag
handler is using viewport coordinates from e.clientX/e.clientY, so it ignores
the canvas element’s position and pan state. Update the drag math in the
relevant drag-start logic (and the matching drag update path referenced by the
same node-drag code) to convert pointer coordinates into canvas space by
subtracting canvasRef.getBoundingClientRect() offsets and accounting for
panOffset before applying zoom. Make the change in the DesignCanvas drag
handlers so setDragOffset and the related position updates use canvas-local
coordinates consistently.

In `@components/canvas/PropertiesPanel.tsx`:
- Around line 130-149: The inspector controls in PropertiesPanel are missing
accessible names and state, so update the node configuration UI to associate
each visible label with its control using matching id/htmlFor on the relevant
select and slider inputs, and expose the read-replica toggle with switch
semantics via role="switch" and aria-checked (or replace it with a native
checkbox). Apply the same accessibility wiring to the other controls in this
panel, especially the node count/storage sliders and the select/toggle elements
in the referenced section, so screen readers announce each control clearly.

In `@components/dashboard/DesignCard.tsx`:
- Around line 146-337: The DesignCard component currently nests the menu trigger
and dropdown actions inside the outer Link, which mixes interactive controls
with navigation. Update DesignCard so the clickable card surface remains inside
the Link, but the menu button and dropdown are rendered outside that linked
region; use the existing menuRef, isMenuOpen, setIsMenuOpen, and
setIsConfirmOpen logic to preserve behavior while separating navigation from
card actions.

---

Outside diff comments:
In `@components/AuthCard.tsx`:
- Around line 117-140: The provider sign-in flow in AuthCard should mirror the
email flow’s syncFailed lifecycle: clear any stale syncFailed state before
starting the OAuth sign-in, and set syncFailed to true if syncUserWithDB fails
after Firebase auth succeeds. Update the sign-in handler around signInFn,
syncUserWithDB, and the catch/finally path so the redirect guard and post-login
state checks behave consistently with the email flow.

In `@components/canvas/DesignCanvas.tsx`:
- Around line 378-390: Keep the properties-panel selection state in sync with
all selection changes by updating or clearing setSelectedNode everywhere a
selection is changed, not just in the normal node-select path. In handleUndo,
handleRedo, the delete/impacted-node handlers, and the connection-selection
logic in DesignCanvas, make sure the same selection transitions also refresh the
panels context so stale node details are not left behind. Use the existing
selection handlers and local selection state in DesignCanvas to locate each path
and apply the same setSelectedNode synchronization consistently.

---

Minor comments:
In `@app/dashboard/analytics/page.tsx`:
- Around line 139-145: The CTA in the analytics empty state is misleading
because the Link labeled “Start Interview” still points to the dashboard. Update
the Link in the analytics page empty-state section so its href matches the
interview flow destination, or if you keep the current destination, rename the
CTA text to match; use the Link element and the “Start Interview” label as the
locating symbols.

In `@app/dashboard/page.tsx`:
- Around line 311-325: The layout controls in the dashboard header are currently
decorative only, so either wire the grid/list buttons and the sort select to
real state in dashboard/page.tsx or clearly disable/label them as coming soon.
Update the relevant controls in the layout controls block to use handlers and
state for view mode and sorting, or make them non-interactive placeholders so
they do not imply functionality that is not implemented.

In `@app/globals.css`:
- Around line 183-185: The global html scroll-behavior rule is forcing smooth
scrolling for all users, including those who prefer reduced motion. Update the
html rule in globals.css to apply smooth scrolling only when the user has not
requested reduced motion, using a prefers-reduced-motion media query around the
existing scroll-behavior setting so the landing-page section links still work
without animating for motion-sensitive users.

In `@app/practice/page.tsx`:
- Line 20: Gate the template loading effect in page.tsx on auth resolution: the
current mount flow still fetches /api/templates before useRequireAuth()
finishes, even though unauthenticated users will redirect. Update the effect(s)
that load templates so they only run once authLoading is false and
isAuthenticated is true, and keep the existing fetch logic in the same
template-loading path so no request is made during redirect-only visits.

In `@components/canvas/CanvasPanelsContext.tsx`:
- Around line 67-75: The activeView state in CanvasPanelsContext currently
initializes to architecture and only reads sessionStorage inside useEffect, so
DesignCanvas renders the wrong branch before hydration. Update
CanvasPanelsContext so the saved canvasActiveView is restored during state
initialization (or add a loading gate until it is read) using the
activeView/setActiveViewRaw state and the existing sessionStorage key, ensuring
the first render matches the persisted tab.

In `@components/canvas/DesignCanvas.tsx`:
- Around line 300-301: The geometry constants in DesignCanvas are still using
the old node-card size, so update the hard-coded width/height and any derived
anchor/centering values to match the new 160×64 cards. Fix the related
calculations in the auto-fit logic, edge anchor math, drop centering, and
read-only bounding box paths by adjusting the constants and expressions around
NODE_WIDTH, NODE_HEIGHT, and the other old 72/28-based offsets so they reference
the new card dimensions consistently.

In `@components/dashboard/DesignCard.tsx`:
- Around line 265-286: The “Rename” and “Duplicate” actions in DesignCard’s menu
are currently dead-end buttons that only close the dropdown, so either hide them
or disable them until the handlers are implemented. Update the menu item
rendering in DesignCard so these options are not presented as active actions
unless their onClick logic actually performs rename/duplicate behavior, and keep
the menu’s existing close behavior only for valid actions.

In `@components/dashboard/Header.tsx`:
- Around line 25-38: The command palette shortcuts in Header should match the
behavior actually implemented: the current handleKeyDown/useEffect only supports
Cmd/Ctrl+K and Escape, so either add real ↑↓ active-item navigation and Enter/⏎
execution in the command palette logic or remove those footer hints until they
work. Update the relevant Header.tsx keyboard handling and any palette item
selection/submit handlers so the advertised controls in the footer are
functional.
- Around line 188-201: The Header dropdown’s “Help & Support” control is
interactive but currently has no behavior attached. Update the button in Header
so it either uses the same open/close pattern as the Settings action to launch
the appropriate modal/route, or render it as a non-interactive element until
that destination exists. Use the existing dropdown button markup near the
Settings button as the reference point and keep the user flow consistent with
the current setIsDropdownOpen handling.

In `@components/dashboard/Sidebar.tsx`:
- Around line 177-181: The ProfileSettingsModal is currently rendered inside
sidebarContent, which causes it to mount twice when that shared subtree is used
by both the desktop and mobile asides. Move the ProfileSettingsModal render out
of sidebarContent in Sidebar so it sits alongside the two aside blocks and is
instantiated only once, while keeping isProfileModalOpen and
setIsProfileModalOpen handling unchanged.

In `@components/landing/engine/InfrastructureEnvironment.tsx`:
- Line 8: The decorative ambient background in InfrastructureEnvironment should
be hidden from assistive tech because BlueprintGrid and its SVG text are
non-content noise. Update the top-level wrapper in InfrastructureEnvironment to
include aria-hidden so the entire background subtree is excluded from the
accessibility tree while keeping the visual effect unchanged.

In `@components/landing/SystemCraftLanding.tsx`:
- Around line 944-962: Update the FAQ accordion trigger in SystemCraftLanding so
assistive tech can detect its state: the button that toggles
`setOpenIndex(isOpen ? null : i)` should expose `aria-expanded`, and each panel
rendered inside `AnimatePresence`/`motion.div` should have a stable `id` that
the button references via `aria-controls`. Keep the identifiers tied to the FAQ
item index or similar unique value so the trigger and its corresponding panel
stay linked even if the list changes.
- Around line 768-770: The transition class in SystemCraftLanding’s item and
matching category button styles is using a bare cubic-bezier token that Tailwind
will ignore. Update the className strings around the active item styling and the
category button variants to use Tailwind’s arbitrary easing syntax with
ease-[cubic-bezier(0.16,1,0.3,1)] so the intended timing curve is applied
consistently.
- Around line 1071-1100: The reduced-motion flag in SystemCraftLanding is being
set only after mount via the current useEffect, so the initial render can still
animate and later OS preference changes are missed. Replace the local
reduceMotion state + matchMedia setup in SystemCraftLanding with a subscribed
media-query hook such as useReducedMotion() or an equivalent reactive hook, and
keep the animation/interval effects keyed off that value so the phase sequence
and cluster rotation stop immediately when reduced motion is enabled.

In `@Copilot/.frontendskills/Auth.design.md`:
- Around line 533-539: The end of the Auth.design.md document contains orphaned
draft notes with no section context, so either move them into the Loading &
Interaction States section or remove them entirely. Use the existing Section 14
/ “Loading & Interaction States” area and the nearby document structure to
integrate the “Initializing Workspace…”, live status indicator, and post-login
sequence notes as proper bullets or prose instead of leaving standalone
fragments. Ensure the final document ends cleanly with complete, context-rich
content rather than truncated sentences.

---

Nitpick comments:
In `@components/auth/AuthLayout.tsx`:
- Around line 1-24: AuthLayout is marked as a client component even though it
and SystemStatusPanel do not use hooks or browser APIs, which unnecessarily
pushes the auth shell to the client. Remove the client boundary from AuthLayout
and keep the shell server-rendered, then move any needed client-only behavior
down to AuthCard so the existing layout and rendering stay the same with less
JS. Also verify SystemStatusPanel remains hook-free and remove its client
directive too if it is still present.

In `@components/dashboard/DesignCard.tsx`:
- Around line 91-98: The DesignCard component has dead mock metric memo values
that are computed but never used. In DesignCard, either wire mockLatency and
mockComplexity into the rendered UI so they are actually displayed, or remove
the useMemo blocks entirely if they are not needed yet. Keep the fix localized
to the DesignCard component and ensure no unused-variable lint/typecheck
warnings remain.

In `@Copilot/.frontendskills/Updates.md`:
- Line 246: The phrase in the Updates.md content should use the correct compound
modifier form: change “slow moving gradients” to “slow-moving gradients.” Update
the wording where it appears in the documentation so any copied or derived text
also uses the hyphenated form.
🪄 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: c458cf64-470c-44f7-9ace-335035150610

📥 Commits

Reviewing files that changed from the base of the PR and between f9acda3 and 7cfa44b.

⛔ Files ignored due to path filters (3)
  • Copilot/.frontendskills/SystemCraft Landing Page Creative Direction.docx is excluded by !**/*.docx
  • Copilot/.frontendskills/SystemCraft Landing Page Creative Direction.pdf is excluded by !**/*.pdf
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (46)
  • Copilot/.frontendskills/Agents.md
  • Copilot/.frontendskills/Auth.design.md
  • Copilot/.frontendskills/Canvas.md
  • Copilot/.frontendskills/Updates.md
  • app/api/designs/route.ts
  • app/api/reference-architectures/analyze/route.ts
  • app/canvas/[id]/page.tsx
  • app/dashboard/analytics/page.tsx
  • app/dashboard/layout.tsx
  • app/dashboard/page.tsx
  • app/dashboard/reference-architectures/[id]/page.tsx
  • app/dashboard/reference-architectures/page.tsx
  • app/dashboard/report-card/page.tsx
  • app/globals.css
  • app/interview/[id]/result/page.tsx
  • app/interview/page.tsx
  • app/layout.tsx
  • app/login/page.tsx
  • app/page.tsx
  • app/practice/[id]/page.tsx
  • app/practice/page.tsx
  • app/signup/page.tsx
  • components/AuthCard.tsx
  • components/auth/AuthLayout.tsx
  • components/auth/SystemStatusPanel.tsx
  • components/canvas/AIFeedbackPanel.tsx
  • components/canvas/CanvasHeader.tsx
  • components/canvas/CanvasPanelsContext.tsx
  • components/canvas/ComponentPalette.tsx
  • components/canvas/DesignCanvas.tsx
  • components/canvas/PropertiesPanel.tsx
  • components/canvas/SimulationControls.tsx
  • components/canvas/Whiteboard.tsx
  • components/canvas/WhiteboardClient.tsx
  • components/dashboard/CreateDesignCard.tsx
  • components/dashboard/DesignCard.tsx
  • components/dashboard/Header.tsx
  • components/dashboard/Hero.tsx
  • components/dashboard/Sidebar.tsx
  • components/landing/SystemCraftLanding.tsx
  • components/landing/engine/InfrastructureEnvironment.tsx
  • components/landing/engine/renderers/BlueprintGrid.tsx
  • components/landing/engine/renderers/LightingRenderer.tsx
  • components/landing/engine/renderers/NoiseRenderer.tsx
  • package.json
  • src/lib/redis.ts

Comment thread app/dashboard/reference-architectures/[id]/page.tsx
Comment on lines +181 to +186
<div
className="flex items-center justify-center size-8 rounded-lg border border-white/[0.05] bg-white/[0.02] text-white/40 hover:text-white hover:bg-white/[0.04] transition-all cursor-pointer"
onClick={() => router.push('/practice')}
>
<span className="material-symbols-outlined text-[16px]">arrow_back</span>
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use a real button or link for the back control.

This is clickable navigation implemented as a div, so it is not focusable or keyboard-operable. That makes the header back action inaccessible.

Suggested fix
-                        <div 
-                           className="flex items-center justify-center size-8 rounded-lg border border-white/[0.05] bg-white/[0.02] text-white/40 hover:text-white hover:bg-white/[0.04] transition-all cursor-pointer" 
-                           onClick={() => router.push('/practice')}
-                        >
+                        <button
+                           type="button"
+                           className="flex items-center justify-center size-8 rounded-lg border border-white/[0.05] bg-white/[0.02] text-white/40 hover:text-white hover:bg-white/[0.04] transition-all cursor-pointer"
+                           onClick={() => router.push('/practice')}
+                           aria-label="Back to practice templates"
+                        >
                             <span className="material-symbols-outlined text-[16px]">arrow_back</span>
-                        </div>
+                        </button>
📝 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.

Suggested change
<div
className="flex items-center justify-center size-8 rounded-lg border border-white/[0.05] bg-white/[0.02] text-white/40 hover:text-white hover:bg-white/[0.04] transition-all cursor-pointer"
onClick={() => router.push('/practice')}
>
<span className="material-symbols-outlined text-[16px]">arrow_back</span>
</div>
<button
type="button"
className="flex items-center justify-center size-8 rounded-lg border border-white/[0.05] bg-white/[0.02] text-white/40 hover:text-white hover:bg-white/[0.04] transition-all cursor-pointer"
onClick={() => router.push('/practice')}
aria-label="Back to practice templates"
>
<span className="material-symbols-outlined text-[16px]">arrow_back</span>
</button>
🤖 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 `@app/practice/`[id]/page.tsx around lines 181 - 186, The back control in the
practice page header is implemented as a clickable div with router.push, which
makes it inaccessible to keyboard users. Replace the div with a real button or
link in the same spot, and wire the navigation through the existing
router.push('/practice') behavior so the control remains focusable and operable.
Keep the visual styling and the arrow_back icon, but ensure the accessible
element is the one handling the action.

Comment thread app/practice/page.tsx Outdated
Comment thread components/AuthCard.tsx Outdated
Comment thread components/canvas/DesignCanvas.tsx Outdated
Comment thread components/canvas/DesignCanvas.tsx
Comment thread components/canvas/PropertiesPanel.tsx
Comment on lines 146 to 337
<Link href={`/canvas/${id}`}>
<div className="group flex flex-col rounded-xl bg-white dark:bg-dashboard-card border border-slate-200 dark:border-transparent hover:border-primary/30 dark:hover:border-primary/50 hover:shadow-xl dark:hover:shadow-primary/5 transition-all overflow-hidden cursor-pointer h-full">
<div className="h-40 w-full bg-slate-100 dark:bg-dashboard-surface relative overflow-hidden">
<div
className="absolute inset-0 bg-cover bg-center opacity-80 group-hover:opacity-100 transition-opacity"
style={{ backgroundImage: `url("${thumbnailUrl}")` }}
/>
<div className="absolute top-3 right-3" ref={menuRef}>
<div className="group flex flex-col rounded-xl bg-[#0c0d16]/30 border border-white/[0.04] hover:border-white/[0.12] hover:bg-[#0c0d16]/50 shadow-[0_4px_20px_rgba(0,0,0,0.4)] hover:shadow-[0_20px_40px_rgba(0,0,0,0.6),inset_0_1px_0_rgba(255,255,255,0.02)] transition-all duration-300 overflow-hidden cursor-pointer h-full select-none relative">

{/* Top highlight */}
<div className="absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/[0.05] group-hover:via-white/[0.1] to-transparent transition-all duration-300" />

{/* Living Topology Preview Canvas */}
<div className="h-34 w-full bg-[#060810]/80 relative overflow-hidden flex items-center justify-center p-2">
<svg
viewBox="0 0 100 70"
className="absolute inset-0 h-full w-full opacity-55 group-hover:opacity-85 transition-opacity duration-300"
aria-hidden="true"
>
<defs>
<linearGradient id={`edgeGrad-${id}`} x1="0%" x2="100%" y1="0%" y2="0%">
<stop offset="0%" stopColor="#22d3ee" stopOpacity="0.2" />
<stop offset="100%" stopColor="#6366f1" stopOpacity="0.08" />
</linearGradient>
</defs>

{/* Connections */}
{edges.map((edge, i) => {
const from = nodes[edge.from];
const to = nodes[edge.to];
if (!from || !to) return null;
return (
<line
key={i}
x1={from.x} y1={from.y}
x2={to.x} y2={to.y}
stroke={`url(#edgeGrad-${id})`}
strokeWidth="0.55"
/>
);
})}

{/* Packets */}
{edges.map((edge, i) => {
const from = nodes[edge.from];
const to = nodes[edge.to];
if (!from || !to) return null;
const dur = 3.5 + i * 1.2;
return (
<circle
key={`p-${i}`}
r="0.5"
fill="#22d3ee"
opacity="0.5"
>
<animateMotion
dur={`${dur}s`}
repeatCount="indefinite"
path={`M${from.x},${from.y} L${to.x},${to.y}`}
/>
</circle>
);
})}

{/* Nodes */}
{nodes.map((node, i) => (
<g key={i}>
{/* Breath pulse */}
<circle
cx={node.x} cy={node.y} r="3.5"
fill="none"
stroke="#22d3ee"
strokeWidth="0.25"
opacity="0.06"
>
<animate
attributeName="r"
values="3.2;4.2;3.2"
dur="6s"
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
values="0.03;0.1;0.03"
dur="6s"
repeatCount="indefinite"
/>
</circle>
<circle
cx={node.x} cy={node.y} r="1.6"
fill="#080a12"
stroke="rgba(34,211,238,0.2)"
strokeWidth="0.4"
/>
</g>
))}
</svg>

{/* Micro Node labels */}
{nodes.map((node, i) => (
<span
key={i}
className="absolute text-[5px] font-mono tracking-wider text-white/20 uppercase pointer-events-none -translate-x-1/2"
style={{ left: `${node.x}%`, top: `${node.y + 4}%` }}
>
{node.label}
</span>
))}

{/* Menu overlay toggles */}
<div className="absolute top-2.5 right-2.5" ref={menuRef}>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setIsMenuOpen(!isMenuOpen);
}}
className="bg-black/40 backdrop-blur-md hover:bg-black/60 text-white p-1.5 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer"
className="bg-[#0c0d16]/80 hover:bg-[#0c0d16] text-white/50 hover:text-white/80 p-1.5 rounded-lg border border-white/[0.05] shadow-md transition-all cursor-pointer"
>
<span className="material-symbols-outlined text-[18px]">more_horiz</span>
<span className="material-symbols-outlined text-[15px]">more_horiz</span>
</button>

{/* Dropdown Menu */}
{isMenuOpen && (
<div className="absolute right-0 top-full mt-1 w-40 bg-white dark:bg-dashboard-card rounded-lg shadow-xl border border-slate-200 dark:border-border-dark overflow-hidden z-50">
<div className="absolute right-0 top-full mt-1.5 w-36 bg-[#0c0d16] rounded-xl shadow-[0_10px_30px_rgba(0,0,0,0.5)] border border-white/[0.06] overflow-hidden z-50 p-1 space-y-0.5 animate-in fade-in slide-in-from-top-1 duration-150">
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
// Could add rename functionality here
setIsMenuOpen(false);
}}
className="w-full px-3 py-2 flex items-center gap-2 text-left text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-surface-highlight-dark transition-colors"
className="w-full px-2.5 py-1.5 flex items-center gap-2 rounded-lg text-left text-xs font-mono uppercase tracking-wider text-white/50 hover:bg-white/[0.02] hover:text-white/80 transition-colors"
>
<span className="material-symbols-outlined text-[18px]">edit</span>
<span className="material-symbols-outlined text-[15px]">edit</span>
<span>Rename</span>
</button>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
// Could add duplicate functionality here
setIsMenuOpen(false);
}}
className="w-full px-3 py-2 flex items-center gap-2 text-left text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-surface-highlight-dark transition-colors"
className="w-full px-2.5 py-1.5 flex items-center gap-2 rounded-lg text-left text-xs font-mono uppercase tracking-wider text-white/50 hover:bg-white/[0.02] hover:text-white/80 transition-colors"
>
<span className="material-symbols-outlined text-[18px]">content_copy</span>
<span className="material-symbols-outlined text-[15px]">content_copy</span>
<span>Duplicate</span>
</button>
<div className="border-t border-slate-200 dark:border-border-dark" />
<div className="border-t border-white/[0.04] my-1" />
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setIsMenuOpen(false);
setIsConfirmOpen(true);
}}
className="w-full px-3 py-2 flex items-center gap-2 text-left text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-500/10 transition-colors"
className="w-full px-2.5 py-1.5 flex items-center gap-2 rounded-lg text-left text-xs font-mono uppercase tracking-wider text-red-400 hover:bg-red-500/[0.06] transition-colors"
>
<span className="material-symbols-outlined text-[18px]">delete</span>
<span className="material-symbols-outlined text-[15px]">delete</span>
<span>Delete</span>
</button>
</div>
)}
</div>
{nodeCount !== undefined && nodeCount > 0 && (
<div className="absolute bottom-3 left-3 bg-black/60 backdrop-blur-sm text-white text-xs px-2 py-1 rounded-md">
{nodeCount} node{nodeCount !== 1 ? 's' : ''}
</div>
)}

{/* Health status led dot */}
<div className="absolute bottom-2.5 left-3 flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-black/45 border border-white/[0.03] text-[7px] font-mono tracking-widest uppercase">
<span className={`inline-block h-1.5 w-1.5 rounded-full ${mockHealth.dot} opacity-70 animate-pulse`} />
<span className="text-white/30">{mockHealth.label}</span>
</div>
</div>

{/* Description / metadata body */}
<div className="p-4 flex flex-col flex-1">
<div className="flex justify-between items-start mb-2">
<h4 className="text-base font-bold text-slate-900 dark:text-white line-clamp-1 group-hover:text-primary transition-colors">{title}</h4>
</div>
<div className="flex items-center gap-2 mb-4">
<span className={`px-2 py-0.5 rounded text-[11px] font-mono font-medium ${statusColor}`}>{status}</span>
<h4 className="text-xs font-bold tracking-tight text-white/85 group-hover:text-cyan-400 transition-colors font-display line-clamp-1">
{title}
</h4>

{/* Simple metadata */}
<div className="mt-2 text-[9px] font-mono tracking-wider uppercase text-white/40 flex items-center gap-1.5">
<span>{nodeCount} Nodes</span>
<span className="text-white/20">·</span>
<span>{connectionCount} Links</span>
</div>
<div className="mt-auto flex items-center justify-between text-xs text-slate-400 dark:text-text-card-footer-dark">
<div className="flex items-center gap-1.5">
<span className="material-symbols-outlined text-[14px]">schedule</span>

{/* Footer status pill & schedule edited timestamp */}
<div className="mt-auto pt-4 flex items-center justify-between">
<span className={`px-2 py-0.5 rounded text-[8px] font-mono tracking-widest uppercase border ${statusColor}`}>
{status}
</span>
<div className="flex items-center gap-1.5 text-[8px] font-mono uppercase tracking-wider text-white/20">
<span className="material-symbols-outlined text-[12px]">schedule</span>
<span>Edited {editedTime}</span>
</div>
{reviewers && (
<div className="flex -space-x-1.5">
<div className="size-5 rounded-full ring-2 ring-white dark:ring-dashboard-card bg-orange-400" title="Reviewer 1"></div>
<div className="size-5 rounded-full ring-2 ring-white dark:ring-dashboard-card bg-blue-400" title="Reviewer 2"></div>
</div>
)}
</div>
</div>

</div>
</Link>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Split the clickable card from the menu actions.

The outer Link wraps the menu trigger and dropdown buttons, which nests interactive controls inside a link. That markup is invalid and tends to break keyboard/focus behavior for the card actions. Keep the preview/body linked, but move the menu controls outside that linked region.

🤖 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 `@components/dashboard/DesignCard.tsx` around lines 146 - 337, The DesignCard
component currently nests the menu trigger and dropdown actions inside the outer
Link, which mixes interactive controls with navigation. Update DesignCard so the
clickable card surface remains inside the Link, but the menu button and dropdown
are rendered outside that linked region; use the existing menuRef, isMenuOpen,
setIsMenuOpen, and setIsConfirmOpen logic to preserve behavior while separating
navigation from card actions.

@Shashank0701-byte Shashank0701-byte merged commit 4bc5b43 into main Jun 28, 2026
11 checks passed
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