Prod fixes#68
Conversation
- Move /accessible and /search routes before /:id wildcard in repos.ts to prevent Express matching them as :id parameter (fixes 404) - Add clear comment marking wildcard routes section - Memoize presenceUser object in App.tsx to prevent new object on each render - Refactor usePresence hook to use refs instead of direct state in callbacks to prevent reconnection loops (fixes constant online/offline flapping) - Add connected providers checkmarks to onboarding page 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…invites The teamsRouter has routes like /workspaces/:workspaceId/members and /invites but was mounted at /api/teams, making them inaccessible at the expected paths. Changed mount from /api/teams to /api so routes work correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed billing routes from checking req.session.user (doesn't exist) to req.session.userId with DB lookup - Added stripeCustomerId column to users table - Added migration 0008_stripe_customer_id for the new column - Updated all billing routes: subscription, checkout, portal, change, cancel, resume, invoices, upcoming 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidate settings to use only SettingsPage (which has Billing tab) instead of having two separate settings panels. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes critical production issues affecting routing, WebSocket stability, and database schema updates for billing integration.
Key Changes:
- Fixed Express route matching issues causing 404 errors for specific API endpoints
- Resolved WebSocket reconnection loops by memoizing user objects and using refs in hooks
- Updated database schema to support Stripe customer IDs for billing
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/cloud/api/repos.ts | Relocated /accessible and /search routes before wildcard /:id route to fix 404 errors |
| src/cloud/server.ts | Changed teams router mount point from /api/teams to /api to match route definitions |
| src/dashboard/react-components/hooks/usePresence.ts | Refactored to use refs instead of direct state dependencies to prevent reconnection loops |
| src/dashboard/react-components/App.tsx | Memoized presence user object to prevent unnecessary re-renders and WebSocket reconnections |
| src/dashboard/app/app/page.tsx | Added connected provider checkmarks on onboarding page |
| src/cloud/db/schema.ts | Added stripeCustomerId column to users table |
| src/cloud/db/migrations/* | Migration files for adding Stripe customer ID and dropping SSH fields |
| src/cloud/api/billing.ts | Updated billing endpoints to use database-stored user data instead of session |
| .trajectories/* | Trajectory tracking files for completed work |
Comments suppressed due to low confidence (1)
src/cloud/db/migrations/0008_stripe_customer_id.sql:1
- The migration drops SSH-related columns from workspaces table, but the migration name only references 'stripe_customer_id'. Consider either splitting this into separate migrations or updating the migration name to reflect all changes (e.g., '0008_add_stripe_customer_id_drop_ssh').
ALTER TABLE "users" ADD COLUMN "stripe_customer_id" varchar(255);--> statement-breakpoint
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null); | ||
| const isConnectingRef = useRef(false); // Prevent race conditions | ||
| const currentUserRef = useRef(currentUser); | ||
| currentUserRef.current = currentUser; // Keep ref in sync with prop |
There was a problem hiding this comment.
The ref initialization and update are separated, which could lead to subtle bugs. Consider moving the ref declaration closer to where it's used (around line 276) or adding a comment explaining why it's declared early but also updated later in the hook.
| currentUserRef.current = currentUser; // Keep ref in sync with prop | |
| // Keep a mutable reference to the latest `currentUser` so that callbacks | |
| // defined later in this hook (e.g. the WebSocket connect handler) can read | |
| // the up-to-date value without needing to be recreated on every render. | |
| currentUserRef.current = currentUser; |
| {/* Special expanded section for Codex with CLI auth flow */} | ||
| {provider.id === 'codex' ? ( | ||
| <div className="p-4 bg-bg-tertiary rounded-xl border border-border-subtle space-y-4"> | ||
| <div className={`p-4 bg-bg-tertiary rounded-xl border space-y-4 ${connectedProviders.includes(provider.id) || connectedProviders.includes('openai') ? 'border-green-500/50' : 'border-border-subtle'}`}> |
There was a problem hiding this comment.
The condition connectedProviders.includes('openai') appears twice in this file (lines 551, 558-559, 570, 575, and 604) specifically for the 'codex' provider. This hardcoded relationship between codex and openai should be extracted into a helper function or constant to improve maintainability and make the relationship explicit.
Summary
Production fixes for routing issues and WebSocket stability.
1. Fix
/api/repos/accessibleand/api/repos/searchreturning 404Problem: Express was matching
/accessibleand/searchas the:idparameter in the/:idwildcard route, returning 404.Solution: Moved specific routes (
/accessible,/search) before the/:idwildcard inrepos.ts. Added clear comment marking the wildcard routes section.Files:
src/cloud/api/repos.ts2. Fix user presence constantly flipping online/offline
Problem: Users were rapidly cycling between online/offline status every second.
Root cause: In
App.tsx, thecurrentUserobject passed tousePresencewas recreated on every render, causing callbacks to be recreated and effects to re-run (disconnect/reconnect).Solution:
presenceUserobject inApp.tsxusinguseMemousePresencehook to use refs instead of direct state in callbacksFiles:
src/dashboard/react-components/App.tsx,src/dashboard/react-components/hooks/usePresence.ts3. Fix
/api/workspaces/:id/membersand/api/invitesreturning 404Problem:
teamsRouterwas mounted at/api/teams, but its routes define full paths like/workspaces/:workspaceId/members.Solution: Changed mount path from
/api/teamsto/api.Files:
src/cloud/server.ts4. Connected providers checkmarks on onboarding page
Shows checkmarks next to already-authenticated providers.
Files:
src/dashboard/app/app/page.tsxTest plan
/api/repos/accessiblereturns repository list/api/repos/search?q=testreturns search results/api/workspaces/:id/membersreturns member list/api/invitesreturns pending invitations🤖 Generated with Claude Code