Skip to content

Frontend changes - #77

Merged
VAIBHAVSING merged 9 commits into
VAIBHAVSING:mainfrom
ritesh301:frontend_changes
Dec 3, 2025
Merged

Frontend changes#77
VAIBHAVSING merged 9 commits into
VAIBHAVSING:mainfrom
ritesh301:frontend_changes

Conversation

@ritesh301

@ritesh301 ritesh301 commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

🚀 Pull Request

📋 Description

Brief description of what this PR does.

🎯 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🎨 Code style/formatting
  • ♻️ Code refactoring
  • ⚡ Performance improvements
  • 🧪 Tests

🔗 Related Issue

Fixes #(issue number)

🧪 Testing

  • Tested locally
  • Added/updated tests
  • All tests pass
  • Manual testing completed

📸 Screenshots/Videos

If applicable, add screenshots or videos demonstrating the changes.

📋 Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

🌍 Environment Tested

  • OS: [e.g. macOS, Windows, Linux]
  • Browser: [e.g. Chrome, Firefox, Safari] (if applicable)
  • Node Version: [e.g. 18.x, 20.x]

📝 Additional Notes

Any additional information that reviewers should know.

Summary by CodeRabbit

  • New Features

    • Complete redesigned authentication system with unified NextAuth and JWT support.
    • AI Agents dashboard for managing AI agent connections and MCP configurations.
    • Billing and usage dashboard with cost tracking and resource metrics.
    • Enhanced workspace creation with improved size mapping and cloud region selection.
    • Comprehensive UI component library for consistent app experience.
  • Bug Fixes

    • Fixed authentication failures during workspace operations.
    • Resolved workspace creation payload compatibility with backend.
    • Fixed transaction timeout issues for workspace operations.
  • Documentation

    • Added testing guides (Postman, Quick Start, Comprehensive).
    • Documented API flows and authentication patterns.

✏️ Tip: You can customize this high-level summary in your review settings.

ritesh301 and others added 9 commits November 1, 2025 00:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Updated backend URL to https://dev8-dev.onrender.com
- Fixed transaction timeout issues (5s -> 120s)
- Fixed quota check to exclude deleted workspaces
- Added dynamic VSCode URL integration
- Fixed VSCode URL connection timeout by stripping :8080 port
- Azure Container Apps ingress only supports standard HTTPS (443)
- Removed Browser button from workspace UI
- All 4 workspace APIs tested and working (CREATE, START, STOP, DELETE)
- Region configured to Central India (centralindia)
- Health check now accepts degraded (503) status
@coderabbitai

coderabbitai Bot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR introduces comprehensive documentation for API verification and integration status, unified authentication supporting NextAuth sessions and JWT Bearer tokens, 100+ new UI components wrapping Radix UI primitives and other libraries, extensive API route implementations for workspaces, teams, users, billing, and AI agents, authentication and workspace management pages, and foundational state/utility modules for demo functionality.

Changes

Cohort / File(s) Summary
Documentation
API_VERIFICATION_REPORT.md, INTEGRATION_COMPLETE.md, RENDER_TEST_RESULTS.md, TRANSACTION_TIMEOUT_FIX.md, WORKSPACE_API_FLOW.md, apps/web/AUTHENTICATION_FIX.md, apps/web/QUICK_FIX_TEST.md, apps/web/QUICK_TEST_GUIDE.md, apps/web/TESTING_GUIDE.md, apps/web/WORKSPACE_CREATION_FIX.md, apps/web/POSTMAN_TESTING_GUIDE.md, apps/web/Dev8-Postman-Collection.json
Verification reports, integration status, API flow documentation, authentication and workspace creation guides, testing procedures, Postman collection with 40+ endpoints and environment setup.
Authentication & Core Utilities
apps/web/lib/auth.ts
Unified authentication supporting NextAuth sessions and JWT Bearer tokens via getAuthUser() and requireAuth() functions; enables dual-mode auth for frontend and API clients.
Authentication Routes
apps/web/app/api/auth/change-password/route.ts, apps/web/app/api/auth/logout/route.ts, apps/web/app/api/auth/me/route.ts
Password change, logout, and authenticated user profile endpoints with centralized error handling.
Account Management Routes
apps/web/app/api/account/connections/route.ts, apps/web/app/api/account/delete/route.ts, apps/web/app/api/account/password/route.ts
Connection status aggregation, account deletion, and password validation endpoints.
Workspace API Routes
apps/web/app/api/workspaces/route.ts, apps/web/app/api/workspaces/[id]/route.ts, apps/web/app/api/workspaces/[id]/start/route.ts, apps/web/app/api/workspaces/[id]/stop/route.ts, apps/web/app/api/workspaces/[id]/pause/route.ts, apps/web/app/api/workspaces/[id]/clone/route.ts, apps/web/app/api/workspaces/[id]/details/route.ts, apps/web/app/api/workspaces/[id]/action/route.ts, apps/web/app/api/workspaces/[id]/activity/route.ts, apps/web/app/api/workspaces/[id]/metrics/route.ts, apps/web/app/api/workspaces/[id]/snapshots/route.ts, apps/web/app/api/workspaces/[id]/ssh-keys/route.ts, apps/web/app/api/workspaces/[id]/terminal/route.ts, apps/web/app/api/workspaces/estimate/route.ts, apps/web/app/api/workspaces/options/route.ts
Complete workspace lifecycle management: CRUD, lifecycle actions (start/stop/pause), cloning, activity/metrics/snapshots/SSH keys tracking, terminal access, cost estimation, and options retrieval. Includes Agent API provisioning with fallback behavior.
Team Management Routes
apps/web/app/api/teams/route.ts, apps/web/app/api/teams/[id]/route.ts, apps/web/app/api/teams/[id]/members/route.ts, apps/web/app/api/teams/[id]/members/[memberId]/route.ts, apps/web/app/api/teams/[id]/transfer-ownership/route.ts, apps/web/app/api/teams/[id]/activity/route.ts, apps/web/app/api/teams/[id]/usage/route.ts, apps/web/app/api/teams/[id]/workspaces/route.ts, apps/web/app/api/teams/invitations/[id]/route.ts, apps/web/app/api/teams/invitations/accept/route.ts
Team creation, membership management, role-based access control, ownership transfer, activity/usage tracking, workspace listing, and invitation workflow.
User Management Routes
apps/web/app/api/users/me/route.ts, apps/web/app/api/users/me/usage/route.ts, apps/web/app/api/users/search/route.ts
User profile CRUD, usage statistics aggregation, and search functionality with pagination.
Billing & Reporting Routes
apps/web/app/api/billing/route.ts, apps/web/app/api/billing/invoice/route.ts, apps/web/app/api/reporting/route.ts
Billing dashboard with dynamic cost/usage metrics, invoice generation, and telemetry reporting with synthetic data generation.
AI Agents Routes
apps/web/app/api/ai/agents/route.ts, apps/web/app/api/ai/mcp-config/route.ts
Agent connection management and MCP server configuration with in-memory state.
Miscellaneous Routes
apps/web/app/api/templates/route.ts
Template persistence endpoint (placeholder).
Workspace State & Utilities
apps/web/app/api/_state/workspaces.ts
In-memory workspace state module with randomized metrics, terminal logs, and demo utilities for non-production testing.
Page Components
apps/web/app/(auth)/signin/page.tsx, apps/web/app/(auth)/signup/page.tsx, apps/web/app/ai-agents/page.tsx, apps/web/app/billing-usage/page.tsx
Sign-in/sign-up pages with OAuth integration, AI agents dashboard, and billing usage dashboard with dynamic data fetching and polling.
UI Components — Basic Primitives
apps/web/app/components/ui/button.tsx, apps/web/app/components/ui/input.tsx, apps/web/app/components/ui/label.tsx, apps/web/app/components/ui/badge.tsx, apps/web/app/components/ui/separator.tsx, apps/web/app/components/ui/skeleton.tsx, apps/web/app/components/ui/checkbox.tsx, apps/web/app/components/ui/radio-group.tsx, apps/web/app/components/ui/switch.tsx, apps/web/app/components/ui/progress.tsx, apps/web/app/components/ui/input-otp.tsx, apps/web/app/components/ui/textarea.tsx
Core form and display primitives wrapping Radix UI with consistent styling and accessibility support.
UI Components — Containers & Layouts
apps/web/app/components/ui/card.tsx, apps/web/app/components/ui/accordion.tsx, apps/web/app/components/ui/alert.tsx, apps/web/app/components/ui/alert-dialog.tsx, apps/web/app/components/ui/breadcrumb.tsx, apps/web/app/components/ui/tabs.tsx, apps/web/app/components/ui/table.tsx, apps/web/app/components/ui/pagination.tsx, apps/web/app/components/ui/aspect-ratio.tsx, apps/web/app/components/ui/scroll-area.tsx, apps/web/app/components/ui/resizable.tsx
Container and layout components for cards, accordions, tables, pagination, and responsive panels.
UI Components — Dialogs & Popovers
apps/web/app/components/ui/dialog.tsx, apps/web/app/components/ui/drawer.tsx, apps/web/app/components/ui/popover.tsx, apps/web/app/components/ui/hover-card.tsx, apps/web/app/components/ui/sheet.tsx
Modal, drawer, popover, and sheet components for overlay interactions with portal support and animations.
UI Components — Menus & Navigation
apps/web/app/components/ui/dropdown-menu.tsx, apps/web/app/components/ui/context-menu.tsx, apps/web/app/components/ui/menubar.tsx, apps/web/app/components/ui/navigation-menu.tsx, apps/web/app/components/ui/command.tsx, apps/web/app/components/ui/carousel.tsx
Menu systems (dropdown, context, menubar), command palette, navigation menu, and carousel with keyboard support.
UI Components — Form & Composition
apps/web/app/components/ui/form.tsx, apps/web/app/components/ui/select.tsx
React Hook Form integration with context-based field state management and Radix UI select dropdown.
UI Components — Overlays & Feedback
apps/web/app/components/ui/tooltip.tsx, apps/web/app/components/ui/toast.tsx, apps/web/app/components/ui/toaster.tsx, apps/web/app/components/ui/sonner.tsx
Tooltip, toast notifications, and Sonner toast provider with theme support.
UI Components — Toggle & Slider
apps/web/app/components/ui/toggle.tsx, apps/web/app/components/ui/toggle-group.tsx, apps/web/app/components/ui/slider.tsx
Toggle buttons, toggle groups with variant context, and sliders with multi-thumb support.
UI Components — Chart & Avatar
apps/web/app/components/ui/chart.tsx, apps/web/app/components/ui/avatar.tsx
Themable Recharts wrapper with legend/tooltip support and Avatar with fallback.
UI Components — Sidebar & Collapsible
apps/web/app/components/ui/sidebar.tsx, apps/web/app/components/ui/collapsible.tsx
Comprehensive sidebar with responsive mobile sheet, keyboard shortcuts, cookie persistence, and collapsible sections.
Themes & Providers
apps/web/app/components/theme-provider.tsx, apps/web/app/components/ui/use-mobile.tsx
Theme provider wrapper for next-themes and useIsMobile hook for responsive breakpoint detection.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant Frontend as Frontend<br/>(Next.js)
    participant AuthAPI as Auth<br/>API Routes
    participant WorkspaceAPI as Workspace<br/>API Routes
    participant AgentAPI as Agent API<br/>(Go Backend)
    participant DB as Database

    rect rgb(200, 220, 255)
    Note over Browser,AuthAPI: Authentication Flow
    Browser->>Frontend: Sign In / Sign Up
    Frontend->>AuthAPI: POST /api/auth/* or<br/>NextAuth Session
    AuthAPI->>AuthAPI: getAuthUser() checks<br/>Session then JWT
    AuthAPI->>DB: Validate credentials
    DB-->>AuthAPI: User confirmed
    AuthAPI-->>Frontend: Auth token + Session
    Frontend-->>Browser: Redirect /dashboard
    end

    rect rgb(220, 255, 220)
    Note over Browser,AgentAPI: Workspace Provisioning
    Browser->>Frontend: Create Workspace
    Frontend->>WorkspaceAPI: POST /api/workspaces<br/>with payload<br/>(name, region, size...)
    WorkspaceAPI->>DB: Create Environment<br/>(STOPPED status)
    WorkspaceAPI->>WorkspaceAPI: isAgentIntegrationEnabled()?
    alt Agent Enabled
        WorkspaceAPI->>AgentAPI: POST /provision<br/>with camelCase payload<br/>(cpuCores, memoryGB...)<br/>[300s timeout]
        AgentAPI->>AgentAPI: Health check<br/>[8s, accepts 200/503]
        AgentAPI-->>WorkspaceAPI: Container created<br/>+ URLs (VSCode, SSH)
        WorkspaceAPI->>DB: Update Environment<br/>(RUNNING, URLs, metadata)
    else Agent Disabled/Failed
        WorkspaceAPI->>DB: Keep created record<br/>(agentProvisioned: false)
    end
    WorkspaceAPI-->>Frontend: { ok, environment,<br/>agentProvisioned }
    Frontend-->>Browser: Show workspace dashboard
    end

    rect rgb(255, 230, 200)
    Note over Browser,AgentAPI: Workspace Actions
    Browser->>Frontend: Start/Stop/Pause
    Frontend->>WorkspaceAPI: POST /api/workspaces/[id]/start<br/>(or stop/pause)
    WorkspaceAPI->>DB: Load Environment
    WorkspaceAPI->>WorkspaceAPI: Validate ownership<br/>& state transitions
    alt Action Permitted
        WorkspaceAPI->>AgentAPI: POST /action<br/>{ action: START/STOP/PAUSE }<br/>[90s timeout for actions]
        AgentAPI-->>WorkspaceAPI: Status updated
        WorkspaceAPI->>DB: Update Environment status
    else Validation Failed
        WorkspaceAPI-->>Frontend: 400 Validation Error
    end
    WorkspaceAPI-->>Frontend: { ok, environment, message }
    Frontend-->>Browser: Show updated status
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Key areas requiring focused review:

  • Authentication & Authorization: Dual-mode auth system in lib/auth.ts and usage across 21+ API routes; ensure NextAuth session precedence and JWT fallback logic is correct and secure
  • Workspace Provisioning Logic: apps/web/app/api/workspaces/route.ts includes Agent API integration with graceful fallback; verify payload format (camelCase), timeout handling (300s), and state consistency when provisioning fails
  • Workspace Lifecycle Management: Start/stop/pause/delete routes enforce status validation and role checks; verify state transitions are correct and deletion cascades are complete
  • Team & Permission System: Role-based access control across team endpoints; verify ownership checks, member role updates, and permission enforcement prevent unauthorized access
  • UI Component Surface Area: 60+ new UI components are mostly homogeneous Radix UI wrappers with consistent patterns, but Sidebar and Form components have complex context/state logic requiring verification
  • Agent API Integration: Payload structure, timeout constants (8s health, 300s create, 90s actions), and health check acceptance of 503 status codes; cross-reference with Agent backend contract

Possibly related PRs

Poem

🐰 A hundred components now hop into place,
Routes and auth dance through cyberspace,
From Radix-wrapped buttons to workspace delight,
The API flows gracefully—day turns to night!
Agents provision, users authenticate with might,
Dev8 now shines with its builder's heart light! ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely a template with no actual content filled in; all sections are empty or placeholder text, and no checkboxes are checked. Complete the description template by filling in the actual changes, selecting the type of change, testing status, and other relevant sections. Remove template placeholders and provide specific details about what was implemented.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Frontend changes' is vague and generic, lacking specificity about the actual changes made in this comprehensive PR. Replace with a specific title that summarizes the main change, e.g., 'Add comprehensive UI components, auth system, and API routes' or 'Implement Dev8 workspace management frontend with full API integration'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@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: 70

Comment on lines +20 to +24
const accounts = await prisma.account.findMany({
where: { userId: session.user.id },
select: { provider: true },
});
connected = new Set(accounts.map((a) => a.provider.toLowerCase()));

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.

⚠️ Potential issue | 🔴 Critical

Resolve TS7006 (a implicitly has an any type) in accounts.map

The callback parameter in accounts.map((a) => a.provider.toLowerCase()) is triggering TS7006 under your current compiler settings. Add an explicit type (or cast the accounts array) so the callback parameter is strongly typed, e.g.:

-        const accounts = await prisma.account.findMany({
-          where: { userId: session.user.id },
-          select: { provider: true },
-        });
-        connected = new Set(accounts.map((a) => a.provider.toLowerCase()));
+        const accounts = await prisma.account.findMany({
+          where: { userId: session.user.id },
+          select: { provider: true },
+        });
+        connected = new Set(
+          accounts.map((account: { provider: string }) =>
+            account.provider.toLowerCase(),
+          ),
+        );

This should clear the CI TypeScript error while keeping the behavior unchanged.

📝 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
const accounts = await prisma.account.findMany({
where: { userId: session.user.id },
select: { provider: true },
});
connected = new Set(accounts.map((a) => a.provider.toLowerCase()));
const accounts = await prisma.account.findMany({
where: { userId: session.user.id },
select: { provider: true },
});
connected = new Set(
accounts.map((account: { provider: string }) =>
account.provider.toLowerCase(),
),
);
🧰 Tools
🪛 GitHub Actions: CI

[error] 24-24: TypeScript error TS7006: Parameter 'a' implicitly has an 'any' type.

🤖 Prompt for AI Agents
In apps/web/app/api/account/connections/route.ts around lines 20 to 24, the
callback parameter in accounts.map is implicitly typed (TS7006); fix by giving
the callback an explicit type or by typing the accounts variable: either
annotate the result of prisma.account.findMany as an array with a provider
string (e.g., const accounts: { provider: string }[] = await ...) or change the
map callback to accounts.map((a: { provider: string }) =>
a.provider.toLowerCase()); this will remove the implicit any error without
changing runtime behavior.

Comment on lines +3 to +7
export async function POST() {
// TODO: hook into your real user deletion logic
// For now, just simulate success so the button works end-to-end
return NextResponse.json({ ok: true }, { status: 200 });
}

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.

⚠️ Potential issue | 🔴 Critical

CRITICAL: Missing authentication and error handling.

This endpoint is missing authentication checks, allowing any unauthenticated user to call it. Additionally, there's no error handling for potential failures.

Apply this diff to add authentication and error handling:

+import { NextRequest } from "next/server";
+import { requireAuth } from "@/lib/auth";
+import { handleAPIError } from "@/lib/errors";

-export async function POST() {
+export async function POST(request: NextRequest) {
+  try {
+    await requireAuth(request);
+
     // TODO: hook into your real user deletion logic
     // For now, just simulate success so the button works end-to-end
     return NextResponse.json({ ok: true }, { status: 200 });
+  } catch (error) {
+    return handleAPIError(error);
+  }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/app/api/account/delete/route.ts around lines 3 to 7, the endpoint
currently lacks authentication and error handling; update it to: verify the
caller is authenticated (e.g., validate session/token and fetch the user id) and
return 401 if unauthenticated, then wrap the user-deletion logic in a try/catch
so failures are caught, log the error, and return an appropriate error response
(500 for server errors or a descriptive status/message). Ensure success returns
a 200/204 only after the real deletion completes and never expose internal error
details in client responses.

Comment on lines +3 to +10
export async function POST(req: Request) {
// This is a placeholder implementation; validate and change password in your auth system here
const { next } = await req.json();
if (!next || next.length < 8) {
return NextResponse.json({ ok: false, error: "Password too short" }, { status: 400 });
}
return NextResponse.json({ ok: true });
}

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Missing authentication and misleading parameter name.

This endpoint has several critical issues:

  1. Security vulnerability: No authentication check allows anyone to call this endpoint. Password change routes must use requireAuth (as seen in the complete implementation at apps/web/app/api/auth/change-password/route.ts).

  2. Misleading parameter name: The field next is confusing for a password parameter. It should be named newPassword or similar.

  3. Duplicate endpoint: There's already a complete, secure implementation at /api/auth/change-password/route.ts (lines 12-77) that includes authentication, password strength validation, current password verification, and database updates.

Consider whether this placeholder endpoint is necessary. If it is, apply authentication and proper validation. Otherwise, remove this file and use the existing /api/auth/change-password route.


🏁 Script executed:

#!/bin/bash
# Description: Check if this placeholder endpoint is actually used in the codebase

# Search for references to /api/account/password
rg -n --type ts --type tsx --type js --type jsx '/api/account/password' -g '!route.ts'

# Also check for any fetch/axios calls to this endpoint
rg -n --type ts --type tsx --type js --type jsx 'account/password' -C 3

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Description: Check if /api/account/password endpoint is actually used in the codebase

# Search for references to /api/account/password (without type restrictions)
echo "=== Searching for references to /api/account/password ==="
rg -n '/api/account/password' -g '!route.ts'

# Search for fetch/axios calls to account/password
echo -e "\n=== Searching for account/password references ==="
rg -n 'account/password' -C 2

# Check what files exist in the api/account directory
echo -e "\n=== Contents of apps/web/app/api/account directory ==="
find apps/web/app/api/account -type f -name "*.ts" -o -name "*.tsx" 2>/dev/null | head -20

# Search for any imports or usage of the password route handler
echo -e "\n=== Searching for password route imports ==="
rg -n 'from.*account/password|import.*account/password'

Length of output: 864


🏁 Script executed:

#!/bin/bash
# Description: Get more context on the usage of /api/account/password endpoint

# View the full change-password page to see the request payload
echo "=== Full context of change-password/page.tsx (around line 21) ==="
cat apps/web/app/settings/change-password/page.tsx

# Check if there's any authentication middleware on the route
echo -e "\n=== Check for middleware in apps/web/app/api/account/password/route.ts ==="
cat apps/web/app/api/account/password/route.ts

# Check for any middleware configuration at the api level
echo -e "\n=== Check for middleware.ts or auth configuration ==="
find apps/web -name "middleware.ts" -o -name "middleware.js" | head -10

Length of output: 3147


🏁 Script executed:

#!/bin/bash
# Description: Check middleware to see if authentication is handled

echo "=== Content of apps/web/middleware.ts ==="
cat apps/web/middleware.ts

# Check if there are any route-specific auth handlers
echo -e "\n=== Search for requireAuth usage in api routes ==="
rg -n 'requireAuth' apps/web/app/api/ -A 2

Length of output: 18498


Add authentication check to password endpoint.

This endpoint lacks authentication and will allow any unauthenticated user to call it. Unlike the page accessing it (which may be protected), API routes are explicitly excluded from middleware protection (see matcher config in middleware.ts). All other protected API endpoints use requireAuth() at the start of their handlers.

Additionally, the handler extracts only the next parameter and ignores current (sent from the client), which is incorrect for password change logic.

Required fixes at apps/web/app/api/account/password/route.ts:

  • Import and call requireAuth(req) as the first operation
  • Handle both current and next parameters properly
  • Consider consolidating with the complete implementation at /api/auth/change-password/route.ts if this duplicate endpoint is unnecessary
🤖 Prompt for AI Agents
In apps/web/app/api/account/password/route.ts around lines 3 to 10, the handler
is missing authentication and only reads the new password; update it to import
and immediately call requireAuth(req) as the first operation to enforce the same
protection used by other protected APIs, then parse both current and next from
req.json() and validate them (ensure next meets length/strength rules and
current is provided), verify the current password with your auth layer (or call
the shared change-password service used by /api/auth/change-password/route.ts),
perform the password update only after successful verification, and return clear
JSON responses and appropriate HTTP status codes on success/failure; if this
endpoint is redundant, consolidate by routing calls to or reusing the
implementation at /api/auth/change-password/route.ts instead of duplicating
logic.

Comment on lines +1 to +9
export async function GET() {
const content = `Invoice\nPlan: Pro Developer Plan\nAmount: 4820.00 INR\nDate: ${new Date().toISOString()}\n(This is a placeholder invoice. Replace with PDF generation.)`;
return new Response(content, {
headers: {
"Content-Type": "text/plain",
"Content-Disposition": `attachment; filename=invoice-${new Date().toISOString().slice(0, 7)}.txt`,
},
});
}

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.

⚠️ Potential issue | 🔴 Critical

CRITICAL: Missing authentication for sensitive billing data.

This endpoint exposes invoice data without authentication checks, allowing any user to access billing information.

Apply this diff to add authentication and error handling:

+import { NextRequest } from "next/server";
+import { requireAuth } from "@/lib/auth";
+import { handleAPIError } from "@/lib/errors";
+
-export async function GET() {
+export async function GET(request: NextRequest) {
+  try {
+    await requireAuth(request);
+
     const content = `Invoice\nPlan: Pro Developer Plan\nAmount: 4820.00 INR\nDate: ${new Date().toISOString()}\n(This is a placeholder invoice. Replace with PDF generation.)`;
     return new Response(content, {
       headers: {
         "Content-Type": "text/plain",
         "Content-Disposition": `attachment; filename=invoice-${new Date().toISOString().slice(0, 7)}.txt`,
       },
     });
+  } catch (error) {
+    return handleAPIError(error);
+  }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/app/api/billing/invoice/route.ts around lines 1 to 9, the GET
handler returns invoice data with no authentication or error handling; add an
authentication check that validates the request/session (e.g., verify JWT or
NextAuth session) and return 401/403 if the user is not
authenticated/authorized, wrap the invoice generation and response creation in
try/catch to return a 500 on unexpected errors and log them (without leaking
sensitive details), and ensure the Content-Disposition filename is safely
derived (sanitize or use a fixed pattern) so only authorized users receive the
invoice response.

Comment on lines +47 to +55
plan: "Pro Developer Plan",
accountEmail: "ritesh@cloudidex.com",
payment: "Visa **** 4872",
nextInvoice: new Date(today.getFullYear(), today.getMonth() + 1, 1).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
}),
},

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.

⚠️ Potential issue | 🟠 Major

Avoid hard-coded account identity details in a shared billing endpoint.

accountEmail and payment are hard-coded to a specific-looking user/card, which won’t match the authenticated user and may be undesirable from a PII/compliance perspective if this ever runs outside a local demo. Consider either deriving these fields from the logged-in account or clearly marking and scoping this route as mock/demo-only with generic placeholder values.

🤖 Prompt for AI Agents
In apps/web/app/api/billing/route.ts around lines 47 to 55, the billing response
contains hard-coded PII-like fields (accountEmail and payment); replace these
with either values derived from the authenticated user (pull email and masked
payment info from the current session/account service) or use generic non-PII
placeholders and clearly mark this route as mock/demo-only (e.g., comments and a
guard/env flag) so no real user data is returned in shared or production
environments.

@@ -0,0 +1,1602 @@
# 🚀 Complete Postman Testing Guide for Dev8 Backend APIs

**Date:** October 28, 2025

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.

⚠️ Potential issue | 🟡 Minor

Update the documentation date for accuracy.

The guide shows "October 28, 2025" but the PR was created on November 20, 2025. Please update to reflect the correct date.

-**Date:** October 28, 2025  
+**Date:** November 20, 2025  
📝 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
**Date:** October 28, 2025
**Date:** November 20, 2025
🧰 Tools
🪛 LanguageTool

[style] ~3-~3: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ...ev8 Backend APIs Date: October 28, 2025 Total APIs: 40 Endpoints **Base...

(MISSING_COMMA_AFTER_YEAR)

🤖 Prompt for AI Agents
In apps/web/POSTMAN_TESTING_GUIDE.md around line 3, the document header date is
incorrect (shows "October 28, 2025"); update that date to "November 20, 2025" to
match the PR creation date and any other relevant metadata fields in the file so
the guide reflects the correct publication date.

### Step 1: Start the Server

```bash
cd "c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web"

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.

⚠️ Potential issue | 🟠 Major

Replace hard-coded Windows paths with portable placeholders.

The same hard-coded path issue exists here. Replace with portable placeholders or relative path instructions for cross-platform compatibility.

-cd "c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web"
+# Navigate to the apps/web directory from your project root
+cd apps/web

Also applies to: 102-102

🤖 Prompt for AI Agents
In apps/web/QUICK_TEST_GUIDE.md around lines 12 and 102, the guide includes a
hard-coded Windows absolute path ("c:/Users/.../apps/web"); replace these with a
portable placeholder or a relative path example such as ./apps/web or
<project-root>/apps/web and add a short note showing how to cd into the project
cross-platform (e.g., using quotes only if necessary) so the instruction works
on Windows, macOS, and Linux.

Comment thread apps/web/TESTING_GUIDE.md
@@ -0,0 +1,1930 @@
# 🧪 Complete Application Testing Guide

**Date:** October 28, 2025

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.

⚠️ Potential issue | 🟡 Minor

Verify the date - appears to be in the future.

The date shows "October 28, 2025" which is in the future. This is likely a typo and should be corrected to reflect the actual testing date.

🧰 Tools
🪛 LanguageTool

[style] ~3-~3: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ...on Testing Guide Date: October 28, 2025 Branch: backend-code **Applicat...

(MISSING_COMMA_AFTER_YEAR)

🤖 Prompt for AI Agents
In apps/web/TESTING_GUIDE.md at line 3, the header date is set to "October 28,
2025" which is in the future; update that date to the correct/testing date
(e.g., today's actual date or the intended past date), ensuring the file header
reflects the real testing date and commit the change.

Comment thread apps/web/TESTING_GUIDE.md
### Step 2: Verify Database Schema

```bash
cd "c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web"

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.

⚠️ Potential issue | 🟠 Major

Replace hard-coded Windows paths with portable placeholders.

Multiple commands contain hard-coded Windows-style paths with a specific username (c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web). This makes the documentation non-portable and will fail for other users.

Replace with a portable placeholder:

-cd "c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web"
+cd /path/to/Dev8.dev/apps/web

Or use a relative path instruction:

-cd "c:/Users/RITESH PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web"
+# Navigate to your Dev8.dev/apps/web directory
+cd apps/web

Also applies to: 56-56, 102-102, 572-572, 1573-1573

🤖 Prompt for AI Agents
In apps/web/TESTING_GUIDE.md around lines 44, 56, 102, 572, and 1573 replace the
hard-coded Windows absolute path "c:/Users/RITESH
PRADHAN/OneDrive/Desktop/FINAL_YEAR_PROJECT/Dev8.dev/apps/web" with a portable
placeholder or relative path; update each command to use something like
"<PROJECT_ROOT>/apps/web" or "cd ../apps/web" (or instruct the reader to run
commands from the project root) so the documentation works across different
systems and user accounts.

Comment on lines +37 to +50
### Validation Schema (lib/validations.ts)

The backend validation requires:
```typescript
export const createWorkspaceSchema = z.object({
name: z.string().min(1).max(100),
cloudRegion: z.string().min(1), // Required
cpuCores: z.number().min(1).max(4), // Required
memoryGB: z.number().min(2).max(16), // Required
storageGB: z.number().min(10).max(100), // Required
baseImage: z.string().default('node'), // Required
// ... optional fields
});
```

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.

⚠️ Potential issue | 🟠 Major

Align documented validation limits with size configuration (CPU cores).

The schema snippet documents cpuCores: z.number().min(1).max(4), while the size configuration later defines large as cpu: 8. As written, that payload would fail validation. Either adjust the documented schema (and actual backend, if needed) to allow 8 cores or update the size table/example so all sizes comply with the stated max(4) limit.

Also applies to: 147-156

🤖 Prompt for AI Agents
In apps/web/WORKSPACE_CREATION_FIX.md around lines 37 to 50 (and also apply same
fix to lines 147-156), the documented validation schema limits cpuCores to
max(4) but the sizes table defines a `large` size with cpu: 8 causing an
inconsistency; update the documentation and the backend validation to be
consistent by either lowering the `large` size to ≤4 in the size
configuration/examples or increasing the schema limit to max(8) (and change
actual backend zod schema to match), then run a quick validation test to ensure
payloads for all documented sizes pass.

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

Review continued from previous batch...

Comment on lines +68 to +83
async function toggleAgent(agent: Agent) {
setSavingAgentId(agent.id);
try {
const res = await fetch("/api/ai/agents", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: agent.id, action: agent.status === "connected" ? "disconnect" : "connect" }),
});
const data = await res.json();
setAgents(data.agents);
} catch (e) {
console.error(e);
} finally {
setSavingAgentId(null);
}
}

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.

⚠️ Potential issue | 🟠 Major

Guard against failed agent updates to avoid crashing the agents list.

toggleAgent always does setAgents(data.agents) without checking res.ok or validating the shape. If the API returns an error payload without an agents array, agents becomes undefined, and the subsequent (loadingAgents ? ... : agents).map(...) will throw at runtime.

Harden this flow by checking the response and falling back to the previous state when data.agents is missing:

   async function toggleAgent(agent: Agent) {
     setSavingAgentId(agent.id);
     try {
       const res = await fetch("/api/ai/agents", {
         method: "POST",
         headers: { "Content-Type": "application/json" },
         body: JSON.stringify({ id: agent.id, action: agent.status === "connected" ? "disconnect" : "connect" }),
       });
-      const data = await res.json();
-      setAgents(data.agents);
+      if (!res.ok) {
+        console.error("Failed to update agent", res.status, res.statusText);
+        return;
+      }
+      const data = await res.json();
+      setAgents((prev) =>
+        Array.isArray((data as any).agents) ? (data as any).agents : prev
+      );
     } catch (e) {
       console.error(e);
     } finally {
       setSavingAgentId(null);
     }
   }

Also applies to: 150-181

🤖 Prompt for AI Agents
In apps/web/app/ai-agents/page.tsx around lines 68-83 (and similarly 150-181),
the toggleAgent flow unconditionally calls setAgents(data.agents) which can set
agents to undefined if the API failed or returned a malformed payload; update
the code to first check res.ok, safely parse JSON (guarding against non-JSON
responses), verify that data.agents is an array (e.g.,
Array.isArray(data.agents)), and only call setAgents when that check passes; if
the response is not ok or data.agents is invalid, log the error and leave the
existing agents state unchanged (optionally show an error toast), and ensure
finally still clears setSavingAgentId.

Comment on lines +21 to +27
const validation = changePasswordSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
createErrorResponse(400, ErrorCodes.VALIDATION_ERROR, JSON.stringify(validation.error.issues)),
{ status: 400 }
);
}

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Do not wrap createErrorResponse inside NextResponse.json

createErrorResponse already returns a Response; passing it into NextResponse.json nests a Response as JSON data and will break error responses. Return createErrorResponse directly instead.

Apply this kind of change in all error branches:

-    if (!validation.success) {
-      return NextResponse.json(
-        createErrorResponse(400, ErrorCodes.VALIDATION_ERROR, JSON.stringify(validation.error.issues)),
-        { status: 400 }
-      );
-    }
+    if (!validation.success) {
+      return createErrorResponse(
+        400,
+        ErrorCodes.VALIDATION_ERROR,
+        JSON.stringify(validation.error.issues),
+      );
+    }

@@
-    if (!passwordValidation.valid) {
-      return NextResponse.json(
-        createErrorResponse(400, ErrorCodes.VALIDATION_ERROR, passwordValidation.errors.join(', ')),
-        { status: 400 }
-      );
-    }
+    if (!passwordValidation.valid) {
+      return createErrorResponse(
+        400,
+        ErrorCodes.VALIDATION_ERROR,
+        passwordValidation.errors.join(', '),
+      );
+    }

@@
-    if (!user || !user.password) {
-      return NextResponse.json(
-        createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found'),
-        { status: 404 }
-      );
-    }
+    if (!user || !user.password) {
+      return createErrorResponse(
+        404,
+        ErrorCodes.USER_NOT_FOUND,
+        'User not found',
+      );
+    }

@@
-    const isValid = await verifyPassword(currentPassword, user.password);
-    if (!isValid) {
-      return NextResponse.json(
-        createErrorResponse(401, ErrorCodes.INVALID_CREDENTIALS, 'Current password is incorrect'),
-        { status: 401 }
-      );
-    }
+    const isValid = await verifyPassword(currentPassword, user.password);
+    if (!isValid) {
+      return createErrorResponse(
+        401,
+        ErrorCodes.INVALID_CREDENTIALS,
+        'Current password is incorrect',
+      );
+    }

Also applies to: 33-38, 45-50, 53-59


🏁 Script executed:

#!/bin/bash
# Find createErrorResponse function definition to verify its return type
rg -nP "function createErrorResponse|const createErrorResponse|export.*createErrorResponse" --type=ts --type=tsx -A 10

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Inspect the target file and lines mentioned in the review
cat apps/web/app/api/auth/change-password/route.ts

Length of output: 2273


🏁 Script executed:

#!/bin/bash
# Search for all usages of createErrorResponse wrapped in NextResponse.json
rg -nP "NextResponse\.json\s*\(\s*createErrorResponse" --type=ts --type=tsx -C 3

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Find the errors module (createErrorResponse definition)
fd -e ts -e js "errors\." . | head -20

Length of output: 24


🏁 Script executed:

#!/bin/bash
# Search for createErrorResponse definition without problematic file type
rg -nP "createErrorResponse" lib/errors --type ts -A 5 -B 2

Length of output: 50


🏁 Script executed:

#!/bin/bash
# Alternative: find all files in lib/errors path
find . -path "*/lib/errors*" -type f | head -20

Length of output: 24


🏁 Script executed:

#!/bin/bash
# Search for Response type returns related to createErrorResponse
rg -nP "createErrorResponse.*Response|function createErrorResponse" --type ts -A 8

Length of output: 393


🏁 Script executed:

#!/bin/bash
# Get full createErrorResponse function to confirm complete return statement
cat apps/web/lib/errors.ts | sed -n '25,40p'

Length of output: 227


Return createErrorResponse directly without wrapping it in NextResponse.json

Verification confirms the issue: createErrorResponse at apps/web/lib/errors.ts returns Response.json(..., { status: statusCode }), which is already a Response object. Wrapping it inside NextResponse.json(..., { status: 400 }) nests a Response as JSON data, breaking error responses.

All four error branches in the route require fixes:

  • Line 21-27: validation error
  • Line 33-38: password validation error
  • Line 45-50: user not found (404)
  • Line 53-59: invalid credentials (401)

Apply the suggested changes: return createErrorResponse(...) directly without wrapping it in NextResponse.json.

🤖 Prompt for AI Agents
In apps/web/app/api/auth/change-password/route.ts around lines 21-27, 33-38,
45-50 and 53-59 the route is wrapping createErrorResponse(...) inside
NextResponse.json(...), which nests an existing Response object as JSON; replace
each wrapped return with a direct return of createErrorResponse(...) so the
existing Response produced by createErrorResponse is returned unchanged (i.e.,
remove NextResponse.json(...) and return createErrorResponse(...) directly for
the validation error, password validation error, 404 user-not-found, and 401
invalid-credentials branches).

Comment on lines +10 to +27
export async function POST(request: NextRequest) {
try {
// Verify authentication (optional - just for validation)
await requireAuth(request);

// In a JWT-based system, logout is typically handled client-side
// by removing the token. You could optionally implement a token
// blacklist using Redis here.

return NextResponse.json({
success: true,
message: 'Logged out successfully',
});

} catch (error) {
return handleAPIError(error);
}
}

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.

⚠️ Potential issue | 🟠 Major

Remove authentication requirement from logout endpoint.

Requiring authentication for logout is counterintuitive - if a user's token is invalid or expired, they cannot logout. Since JWT logout is client-side (as noted in the comments), this endpoint should succeed regardless of authentication state.

Apply this diff:

 export async function POST(request: NextRequest) {
   try {
-    // Verify authentication (optional - just for validation)
-    await requireAuth(request);
-
     // In a JWT-based system, logout is typically handled client-side
     // by removing the token. You could optionally implement a token
     // blacklist using Redis here.
📝 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
export async function POST(request: NextRequest) {
try {
// Verify authentication (optional - just for validation)
await requireAuth(request);
// In a JWT-based system, logout is typically handled client-side
// by removing the token. You could optionally implement a token
// blacklist using Redis here.
return NextResponse.json({
success: true,
message: 'Logged out successfully',
});
} catch (error) {
return handleAPIError(error);
}
}
export async function POST(request: NextRequest) {
try {
// In a JWT-based system, logout is typically handled client-side
// by removing the token. You could optionally implement a token
// blacklist using Redis here.
return NextResponse.json({
success: true,
message: 'Logged out successfully',
});
} catch (error) {
return handleAPIError(error);
}
}
🤖 Prompt for AI Agents
In apps/web/app/api/auth/logout/route.ts around lines 10 to 27, the logout
endpoint currently calls requireAuth which blocks requests with missing/expired
tokens; remove that authentication requirement so the endpoint always returns a
successful logout response regardless of auth state. Specifically, delete the
await requireAuth(request) line and any logic that depends on it, keep the
optional comment about token blacklist/cleanup, and ensure the handler returns
NextResponse.json({ success: true, message: 'Logged out successfully' }) inside
try and still calls handleAPIError in catch so the endpoint succeeds even when
no valid token is present.

Comment on lines +30 to +35
if (!user) {
return NextResponse.json(
createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found'),
{ status: 404 }
);
}

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.

⚠️ Potential issue | 🔴 Critical

Fix incorrect response construction.

createErrorResponse already returns a Response.json() object, so wrapping it in NextResponse.json() creates a double-wrapped response.

Apply this diff to fix:

     if (!user) {
-      return NextResponse.json(
-        createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found'),
-        { status: 404 }
-      );
+      return createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found');
     }
📝 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
if (!user) {
return NextResponse.json(
createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found'),
{ status: 404 }
);
}
if (!user) {
return createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User not found');
}
🤖 Prompt for AI Agents
In apps/web/app/api/auth/me/route.ts around lines 30 to 35, the code wraps
createErrorResponse (which already returns a Response.json()) in
NextResponse.json(), causing a double-wrapped response; replace the nested
NextResponse.json(...) call by returning the createErrorResponse(...) result
directly (so return createErrorResponse(404, ErrorCodes.USER_NOT_FOUND, 'User
not found')) and remove the extra status override to let the helper control the
response.

Comment on lines +5 to +10
let seed = Date.now() % 1000;
function rnd() {
// simple deterministic PRNG for jitter
seed = (seed * 9301 + 49297) % 233280;
return seed / 233280;
}

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.

⚠️ Potential issue | 🔴 Critical

Race condition: Global mutable seed causes non-deterministic behavior under concurrent requests.

The global seed variable is mutated by rnd(), causing concurrent requests to interfere with each other's pseudo-random sequences. This defeats the purpose of deterministic generation and produces unpredictable results under load.

Move the seed into request-local scope:

-let seed = Date.now() % 1000;
-function rnd() {
-  // simple deterministic PRNG for jitter
-  seed = (seed * 9301 + 49297) % 233280;
-  return seed / 233280;
-}
+function createRng(initialSeed = Date.now() % 1000) {
+  let seed = initialSeed;
+  return function rnd() {
+    seed = (seed * 9301 + 49297) % 233280;
+    return seed / 233280;
+  };
+}

Then in the GET handler:

 export async function GET(req: Request) {
+  const rnd = createRng();
   const { searchParams } = new URL(req.url);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/app/api/reporting/route.ts around lines 5 to 10, the global mutable
`seed` and `rnd()` cause a race when concurrent requests share state; make the
seed request-local by removing the module-level `seed` and instead create a
per-request seed inside the GET handler, then define `rnd()` as a closure that
captures and updates that local seed (so each request has its own deterministic
PRNG). Replace all uses of the global `rnd()` with the request-local closure so
concurrent handlers do not interfere with each other's sequence.

Comment on lines +29 to +35
const status = searchParams.get('status');
const region = searchParams.get('region');
const limit = parseInt(searchParams.get('limit') || '20');
const offset = parseInt(searchParams.get('offset') || '0');
const sort = searchParams.get('sort') || 'createdAt';
const order = searchParams.get('order') || 'desc';

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.

⚠️ Potential issue | 🟡 Minor

Harden pagination and sorting query params to avoid Prisma runtime errors.

limit, offset, sort, and order are taken directly from searchParams and passed into Prisma:

  • parseInt on invalid strings yields NaN; Math.min(NaN, 100) is NaN, so take/skip can become NaN.
  • Arbitrary sort/order values will be forwarded to orderBy, which Prisma will reject at runtime.

Consider normalizing these values before using them:

const rawLimit = Number.parseInt(searchParams.get("limit") || "20", 10);
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 100) : 20;

const rawOffset = Number.parseInt(searchParams.get("offset") || "0", 10);
const offset = Number.isFinite(rawOffset) && rawOffset >= 0 ? rawOffset : 0;

const allowedSortFields = new Set(["createdAt", "updatedAt", "name", "status"]);
const sort = allowedSortFields.has(searchParams.get("sort") || "")
  ? (searchParams.get("sort") as string)
  : "createdAt";

const order = searchParams.get("order") === "asc" ? "asc" : "desc";

Then use these sanitized values in orderBy, take, and skip to keep the endpoint robust against bad query strings.

Also applies to: 53-70

🤖 Prompt for AI Agents
In apps/web/app/api/workspaces/route.ts around lines 29-35 (and similarly
53-70), the pagination and sorting query params are taken raw and can produce
NaN or invalid values for Prisma; parse limit and offset with a radix, validate
Number.isFinite and enforce defaults (limit default 20, clamp positive limit to
a max e.g. 100; offset default 0 and must be >= 0), validate sort against a
whitelist of allowed fields (e.g. createdAt, updatedAt, name, status) and
fallback to createdAt if invalid, and normalize order to only "asc" or "desc"
with "desc" as default; use these sanitized values for Prisma's take, skip, and
orderBy to avoid runtime errors.

Comment on lines +113 to +121
// Validate request
const validation = createWorkspaceSchema.safeParse(body);
if (!validation.success) {
return NextResponse.json(
createErrorResponse(400, ErrorCodes.VALIDATION_ERROR, JSON.stringify(validation.error.issues)),
{ status: 400 }
);
}

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.

⚠️ Potential issue | 🔴 Critical

Avoid wrapping createErrorResponse in NextResponse.json in POST handler.

As in other routes, createErrorResponse returns a Response. Passing it into NextResponse.json breaks the error body.

Update the POST error paths to return the Response directly:

-    const validation = createWorkspaceSchema.safeParse(body);
-    if (!validation.success) {
-      return NextResponse.json(
-        createErrorResponse(400, ErrorCodes.VALIDATION_ERROR, JSON.stringify(validation.error.issues)),
-        { status: 400 }
-      );
-    }
+    const validation = createWorkspaceSchema.safeParse(body);
+    if (!validation.success) {
+      return createErrorResponse(
+        400,
+        ErrorCodes.VALIDATION_ERROR,
+        JSON.stringify(validation.error.issues),
+      );
+    }
...
-    if (existingCount >= 10) {
-      return NextResponse.json(
-        createErrorResponse(402, ErrorCodes.QUOTA_EXCEEDED, 'Maximum workspace limit reached'),
-        { status: 402 }
-      );
-    }
+    if (existingCount >= 10) {
+      return createErrorResponse(
+        402,
+        ErrorCodes.QUOTA_EXCEEDED,
+        'Maximum workspace limit reached',
+      );
+    }

Also applies to: 124-137

🤖 Prompt for AI Agents
In apps/web/app/api/workspaces/route.ts around lines 113-121 (and similarly for
lines 124-137), the POST handler currently wraps the Response produced by
createErrorResponse inside NextResponse.json which corrupts the error body;
update the error paths to return the Response returned by createErrorResponse
directly (i.e., remove the NextResponse.json(...) wrapper) so the status and
JSON body from createErrorResponse are preserved, and apply the same change to
the other POST error branches mentioned.

Comment on lines +72 to +103
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
([, config]) => config.theme || config.color,
)

if (!colorConfig.length) {
return null
}

return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color
return color ? ` --color-${key}: ${color};` : null
})
.join('\n')}
}
`,
)
.join('\n'),
}}
/>
)
}

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Be explicit about trust boundaries when using dangerouslySetInnerHTML in ChartStyle

ChartStyle builds a <style> block with dangerouslySetInnerHTML from ChartConfig keys and color/theme values. That’s fine for purely static, internal config, but it becomes an XSS/style-injection risk if any of those values (keys, color, or theme[...]) can be influenced by user input.

At minimum, I’d recommend:

  • Documenting that ChartConfig must only contain trusted, non-user-controlled strings, and
  • Optionally constraining colors/keys (e.g. validating keys against /^[a-zA-Z0-9_-]+$/ and colors against a safe pattern) before emitting them into CSS.

If you expect config to be built from user-provided data, introduce a sanitizer layer instead of passing it straight through to CSS.


I'll verify the XSS/style-injection concerns by examining the codebase structure and implementation details.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find ChartConfig type definition
rg -nP 'type\s+ChartConfig|interface\s+ChartConfig' --type=ts --type=tsx

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Find ChartStyle imports and usages
rg -nP 'ChartStyle' --type=ts --type=tsx -C2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check the full context of chart.tsx file
cat apps/web/app/components/ui/chart.tsx | head -150

Length of output: 4058


🏁 Script executed:

#!/bin/bash
# Look for how THEMES is defined
rg -nP 'const\s+THEMES|export\s+const\s+THEMES' --type=ts --type=tsx -A5

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for where ChartConfig might be built or passed
rg -nP 'ChartConfig' --type=ts --type=tsx -B2 -A2 | head -100

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check if there are any validation utilities in the project
fd -e ts -e tsx | xargs grep -l 'sanitize\|validate.*color\|escape' | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any CSS-related validation
rg -nP 'css|style.*valid' --type=ts --type=tsx apps/web/app/components/ui/ -C2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for user input or form submissions that might build chart configs
rg -nP 'user.*color|form.*chart|input.*color' --type=ts --type=tsx -i -C2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check exports from chart.tsx to see public API
rg -nP 'export' apps/web/app/components/ui/chart.tsx -A3

Length of output: 202


🏁 Script executed:

#!/bin/bash
# Look for any existing sanitization in dangerouslySetInnerHTML usages
rg -nP 'dangerouslySetInnerHTML' --type=tsx -B5 -A5

Length of output: 27


I need to search without the problematic --type flag and trace how ChartConfig is used throughout the codebase.


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for ChartContainer usages to see what config is passed
rg -n 'ChartContainer' -C3 | head -150

Length of output: 1116


🏁 Script executed:

#!/bin/bash
# Look for any sanitization or validation of keys/colors
rg -n 'sanitize|escape|validate' apps/web/app/components/ui/chart.tsx

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if id parameter is sanitized before use
rg -n 'uniqueId|chartId' apps/web/app/components/ui/chart.tsx -C2

Length of output: 1099


🏁 Script executed:

#!/bin/bash
# Search for where ChartConfig objects are created/populated
rg -n 'ChartConfig|chart.*:.*{' -C2 | head -200

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Look for any CSS utility libraries or sanitizers in package.json
fd -name 'package.json' -exec grep -l 'sanitize\|escape\|xss' {} \;

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Check if there's a schema or validation for ChartConfig
rg -n 'zod\|yup\|joi\|schema' apps/web/app/components/ui/chart.tsx

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any comments or documentation about ChartConfig safety
rg -n 'ChartConfig' apps/web/app/components/ui/chart.tsx -B3 -A3

Length of output: 968


🏁 Script executed:

#!/bin/bash
# Search for how color/theme values are typically provided
rg -n 'theme.*:|color.*:' apps/web/ --include='*.tsx' --include='*.ts' | head -50

Length of output: 441


🏁 Script executed:

#!/bin/bash
# Check if recharts or any chart library handles injection
fd -name 'package.json' -exec cat {} \; | grep -A10 'recharts\|chart'

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Look broadly at how ChartContainer is being used in examples or tests
fd -name '*.tsx' -o -name '*.ts' | xargs grep -l 'ChartContainer' | head -10

Length of output: 230



---

🏁 Script executed:

```shell
#!/bin/bash
# Find where config objects are actually created/instantiated with data
rg -n 'config.*=' apps/web/ | grep -i chart | head -30

Length of output: 708


🏁 Script executed:

#!/bin/bash
# Look for any usages in pages or components that might show data flow
fd '\.tsx$' -o -f '\.ts$' | xargs grep 'ChartContainer' 2>/dev/null | head -20

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Check if there are tests that show how ChartConfig is supposed to be used
fd -name 'test' -o -name 'spec' | xargs grep -l 'ChartContainer' 2>/dev/null | head -5

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Look at the actual property name/value injection more carefully - check if CSS parsing protects us
cat apps/web/app/components/ui/chart.tsx | sed -n '72,103p'

Length of output: 704


🏁 Script executed:

#!/bin/bash
# Check if there are actual dashboard/page implementations using ChartContainer
rg -n 'ChartContainer' apps/web/app/ -A 5 | head -60

Length of output: 1012


Document trust boundary and add validation for ChartConfig keys and color values in ChartStyle

The code at lines 72-103 does have XSS/style-injection risks. Three unescaped data sources are interpolated directly into CSS:

  • id in the selector: [data-chart=${id}] (line 50 passes it without escaping)
  • Config keys in properties: --color-${key}
  • Color/theme values in declarations: ${color}

If any of these contain special characters (e.g., id="]; malicious-css {, or color="red; background:...", or key="foo]="x"), CSS injection occurs. The id prop is particularly at risk since it's passed from external callers with no sanitization beyond the React.useId() fallback.

Recommendations:

  • Add documentation stating ChartConfig must contain only trusted, application-controlled strings
  • Validate id parameter against /^[a-zA-Z0-9_-]+$/ before use
  • Validate config keys against /^[a-zA-Z0-9_-]+$/
  • Validate color values against a safe color pattern (hex, rgb, named colors)
  • If config can originate from user input, introduce a sanitizer layer instead of passing it directly to CSS
🧰 Tools
🪛 ast-grep (0.40.0)

[warning] 82-82: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)

[error] 83-83: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

Comment on lines +107 to +249
function ChartTooltipContent({
active,
payload,
className,
indicator = 'dot',
hideLabel = false,
hideIndicator = false,
label,
labelFormatter,
labelClassName,
formatter,
color,
nameKey,
labelKey,
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<'div'> & {
hideLabel?: boolean
hideIndicator?: boolean
indicator?: 'line' | 'dot' | 'dashed'
nameKey?: string
labelKey?: string
}) {
const { config } = useChart()

const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null
}

const [item] = payload
const key = `${labelKey || item?.dataKey || item?.name || 'value'}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const value =
!labelKey && typeof label === 'string'
? config[label as keyof typeof config]?.label || label
: itemConfig?.label

if (labelFormatter) {
return (
<div className={cn('font-medium', labelClassName)}>
{labelFormatter(value, payload)}
</div>
)
}

if (!value) {
return null
}

return <div className={cn('font-medium', labelClassName)}>{value}</div>
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
])

if (!active || !payload?.length) {
return null
}

const nestLabel = payload.length === 1 && indicator !== 'dot'

return (
<div
className={cn(
'border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl',
className,
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || 'value'}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color || item.payload.fill || item.color

return (
<div
key={item.dataKey}
className={cn(
'[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5',
indicator === 'dot' && 'items-center',
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
'shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)',
{
'h-2.5 w-2.5': indicator === 'dot',
'w-1': indicator === 'line',
'w-0 border-[1.5px] border-dashed bg-transparent':
indicator === 'dashed',
'my-0.5': nestLabel && indicator === 'dashed',
},
)}
style={
{
'--color-bg': indicatorColor,
'--color-border': indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
'flex flex-1 justify-between leading-none',
nestLabel ? 'items-end' : 'items-center',
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
</div>
</>
)}
</div>
)
})}
</div>
</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.

⚠️ Potential issue | 🟡 Minor

Tooltip suppresses zero values due to item.value && check

In the default rendering branch you use:

{item.value && (
  <span className="text-foreground font-mono font-medium tabular-nums">
    {item.value.toLocaleString()}
  </span>
)}

This hides legitimate 0 values because 0 is falsy. Suggest changing the condition to allow zero:

-                    {item.value && (
+                    {item.value !== undefined && item.value !== null && (
                       <span className="text-foreground font-mono font-medium tabular-nums">
                         {item.value.toLocaleString()}
                       </span>
                     )}

This keeps null/undefined hidden but renders numeric zero correctly.

🤖 Prompt for AI Agents
In apps/web/app/components/ui/chart.tsx around lines 107 to 249, the tooltip
rendering uses a falsy check `item.value && ...` which suppresses legitimate
zero values; update the condition to explicitly check for null/undefined (e.g.,
`item.value !== null && item.value !== undefined`) or test the value type (e.g.,
`typeof item.value === 'number' || item.value !== null`) so numeric 0 is
rendered while still hiding null/undefined.

Comment on lines +72 to +89
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
const [_open, _setOpen] = React.useState(defaultOpen)
const open = openProp ?? _open
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
const openState = typeof value === 'function' ? value(open) : value
if (setOpenProp) {
setOpenProp(openState)
} else {
_setOpen(openState)
}

// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
},
[setOpenProp, open],
)

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.

🛠️ Refactor suggestion | 🟠 Major

Align setOpen with React state setter semantics

setOpen accepts either a boolean or an updater function, but it always calls the updater with the captured open value:

const setOpen = React.useCallback(
  (value: boolean | ((value: boolean) => boolean)) => {
    const openState = typeof value === 'function' ? value(open) : value
    ...
    _setOpen(openState)
  },
  [setOpenProp, open],
)

This behaves like setOpen(!open), not like React’s functional updates, and can misbehave if setOpen(prev => !prev) is used multiple times in a single render cycle. You can fix this by basing the computation on the previous state:

-  const setOpen = React.useCallback(
-    (value: boolean | ((value: boolean) => boolean)) => {
-      const openState = typeof value === 'function' ? value(open) : value
-      if (setOpenProp) {
-        setOpenProp(openState)
-      } else {
-        _setOpen(openState)
-      }
-      document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
-    },
-    [setOpenProp, open],
-  )
+  const setOpen = React.useCallback(
+    (value: boolean | ((value: boolean) => boolean)) => {
+      _setOpen((prev) => {
+        const next = typeof value === 'function' ? value(prev) : value
+        if (setOpenProp) {
+          setOpenProp(next)
+        }
+        document.cookie = `${SIDEBAR_COOKIE_NAME}=${next}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+        return next
+      })
+    },
+    [setOpenProp],
+  )

This preserves external control while matching React’s updater semantics.

@VAIBHAVSING
VAIBHAVSING merged commit 5daac9b into VAIBHAVSING:main Dec 3, 2025
5 of 7 checks passed
@VAIBHAVSING

Copy link
Copy Markdown
Owner

thanks

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.

2 participants