feat(buddy): web buddy flow — Daily room, video layout, join errors (#106)#128
Conversation
- Add buddy_sessions.daily_room_name and daily_room_url; snapshot exposes dailyRoomUrl when active - POST …/start creates a private Daily room before activating; race cleanup deletes orphan room - Teardown Daily room on active→completed reconcile and host abandon; clear DB fields - Active buddy UI: desktop grid timer left / video right; mobile stack timer then video - Mount BuddyVideo with default auto-connect; message when URL missing - Deep-link buddy join failures show dismissible alert and clean URL Made-with: Cursor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughPrivate Daily.co rooms are provisioned for buddy sessions on start, meeting tokens are minted for participants, room name/URL are persisted to the DB, and rooms are torn down and cleared when sessions end or the host abandons them; the UI and snapshot types surface the video URL and token usage. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AppAPI as App API
participant Auth as Auth/Users
participant DB as Database
participant Daily as Daily.co API
Client->>AppAPI: POST /buddy/sessions/[id]/start
AppAPI->>Daily: createRoom(name="buddy-{id}", privacy="private")
alt createRoom OK
Daily-->>AppAPI: { name, url }
AppAPI->>DB: UPDATE buddy_sessions set dailyRoomName,dailyRoomUrl,state="active"
alt DB update OK
DB-->>AppAPI: 1 row
AppAPI-->>Client: 200 active
else DB update failed
AppAPI->>Daily: deleteRoom(name, {ignoreMissing:true})
Daily-->>AppAPI: ok/ignored
AppAPI-->>Client: 500
end
else createRoom DailyApiError
alt name-conflict
AppAPI->>Daily: deleteRoom(conflictName,{ignoreMissing:true})
Daily-->>AppAPI: ok/ignored
AppAPI->>Daily: createRoom(...) retry
end
Daily-->>AppAPI: error -> AppAPI->>Client: 503
end
sequenceDiagram
participant Client
participant AppAPI as App API
participant Auth as Auth/Users
participant DB as Database
participant Daily as Daily.co API
Client->>AppAPI: POST /buddy/sessions/[id]/meeting-token
AppAPI->>Auth: getCurrentUser()
Auth-->>AppAPI: user
AppAPI->>DB: verify participant active
DB-->>AppAPI: membership ok
AppAPI->>AppAPI: reconcileBuddySession(id)
AppAPI->>DB: SELECT dailyRoomName FROM buddy_sessions
DB-->>AppAPI: roomName
AppAPI->>Daily: POST /meeting-tokens {room_name, user_name, user_id, exp}
alt token OK
Daily-->>AppAPI: { token }
AppAPI-->>Client: 200 { token }
else Daily error
AppAPI-->>Client: 503
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📋 Issue PlannerLet us write the prompt for your AI agent so you can ship faster (with fewer bugs). View plan for ticket: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@cursor review |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/app/api/buddy/sessions/[id]/start/route.ts (1)
59-71: Consider handling the duplicate room name edge case.If a previous start attempt created the Daily room but the database update failed, the race condition cleanup attempts to delete the orphan room. However, if that cleanup doesn't fully execute or there's a timing window, a retry would attempt to create a room with the same
buddy-${sessionId}name. Daily's API returns HTTP 400 for duplicate room names within a domain, which would be caught asDailyApiErrorand return a 503 response—masking the underlying issue.For a more robust flow, consider:
- Attempting to fetch/reuse an existing room with that name before creating
- Including a unique suffix (e.g., timestamp) in the room name
The current behavior is acceptable for an MVP since the race cleanup handles orphan rooms, but this edge case is worth hardening in future iterations.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/api/buddy/sessions/`[id]/start/route.ts around lines 59 - 71, The createRoom call using roomName (`const roomName = \`buddy-${sessionId}\`` and `createRoom`) can fail with a duplicate-name DailyApiError; update the flow to first try to locate/reuse an existing room with that name (e.g., call the Daily API list/get-by-name before creating) and only call createRoom if none exists, and as a simpler alternative append a unique suffix (timestamp/UUID) to roomName before calling createRoom so retries won't hit the duplicate-name 400; keep the DailyApiError handling but only treat it as fatal after attempting reuse or using a unique-suffixed name to avoid masking the real-state when a prior room already exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/app/api/buddy/sessions/`[id]/start/route.ts:
- Around line 59-71: The createRoom call using roomName (`const roomName =
\`buddy-${sessionId}\`` and `createRoom`) can fail with a duplicate-name
DailyApiError; update the flow to first try to locate/reuse an existing room
with that name (e.g., call the Daily API list/get-by-name before creating) and
only call createRoom if none exists, and as a simpler alternative append a
unique suffix (timestamp/UUID) to roomName before calling createRoom so retries
won't hit the duplicate-name 400; keep the DailyApiError handling but only treat
it as fatal after attempting reuse or using a unique-suffixed name to avoid
masking the real-state when a prior room already exists.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d398e96b-3059-4fdf-b29b-fd64a9da8e40
📒 Files selected for processing (8)
drizzle/buddy_sessions_daily_room_incremental.sqlsrc/app/api/buddy/sessions/[id]/leave/route.tssrc/app/api/buddy/sessions/[id]/start/route.tssrc/app/app/page.tsxsrc/components/BuddySessionRoom.tsxsrc/db/schema.tssrc/lib/api.tssrc/lib/buddySession.ts
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 186ee4c. Configure here.
| const roomName = `buddy-${sessionId}`; | ||
| let dailyRoom: { name: string; url: string }; | ||
| try { | ||
| dailyRoom = await createRoom({ name: roomName, privacy: "private" }); |
There was a problem hiding this comment.
Private Daily room join fails without meeting token
High Severity
The room is created with privacy: "private", but no Daily meeting token is ever generated or passed to the client. In BuddyVideoInner, daily.join({ url, userName }) is called without a token parameter. Daily's private rooms require a valid meeting token for participants to join — without one the join call will be rejected, making the video feature completely non-functional.
Reviewed by Cursor Bugbot for commit 186ee4c. Configure here.
- Add createMeetingToken + isDailyRoomNameConflict in daily.ts - POST …/meeting-token for active participants; BuddySessionRoom fetches before join - BuddyVideo passes token to daily.join for private rooms - Start: on name conflict delete orphan room once and recreate (CodeRabbit) - Addresses Bugbot: private rooms require meeting tokens Made-with: Cursor


Summary
Implements buddy MVP web flow pieces for #106: Daily room at session start,
BuddyVideowith auto-connect, desktop timer-left / video-right layout, Daily teardown on complete/host abandon, and user-visible deep-link join failures.Closes #106
Test plan
npx drizzle-kit push(or applydrizzle/buddy_sessions_daily_room_incremental.sql) so new columns existDAILY_API_KEYset for start → active path?buddy=shows dismissible alert and cleans URLnpm run buildNotes
dailyRoomUrlwhilestate === "active".BuddySessionRoom.deleteRoom(name, { ignoreMissing: false })fromdaily.tswhen required (runtime teardown usestrue).Made with Cursor
Summary by CodeRabbit
New Features
User Experience
Bug Fixes