Add Direct Messaging Feature
Implement a real, persistent one‑to‑one chat system in the existing app
The route
7 steps to Done
- 01
Design Message & Conversation Data Model
Create database structures to store chats and individual messages
Preview prompt + verify gate ▾ Hide ▴
Write Prisma schema definitions for two new models: Conversation (id UUID primary key, participantAId UUID, participantBId UUID, createdAt timestamp, updatedAt timestamp) and Message (id UUID primary key, conversationId UUID foreign key, senderId UUID foreign key, content String, sentAt timestamp, read Boolean default false). Add necessary indexes for fast lookup (e.g., participant pair, conversationId). Provide the exact lines to insert into schema.prisma and a migration command (prisma migrate dev). Ensure the models reference the existing User model correctly and compile without errors.
- ✓ Do the new models appear in schema.prisma?
- ✓ Does `prisma migrate dev` complete without errors?
- ✓ Are the tables present in the database with correct columns and indexes?
- 02
Create API Endpoints for Messaging
Expose HTTP routes to send a message and fetch a conversation's messages
Preview prompt + verify gate ▾ Hide ▴
Implement two Express routes: 1. POST /api/messages – body: {conversationId, content}. Validate that `req.userId` matches the conversation participants, create a Message record with senderId = req.userId, sentAt = now, read = false, and update the Conversation's updatedAt. Return the created Message JSON. 2. GET /api/conversations/:id/messages – query params: optional `limit` and `offset`. Validate that `req.userId` is a participant, fetch messages ordered by sentAt ascending, apply pagination, and return an array of Message objects. Include proper TypeScript types, error handling (400 for bad input, 403 for unauthorized, 500 for server errors), and export the router for inclusion in the main app. Do not include placeholder logic; all validation must be real.
- ✓ Can you POST a new message and receive a 201 response with the message JSON?
- ✓ Does GET /api/conversations/:id/messages return a paginated list of real messages?
- ✓ Do unauthorized users receive a 403 error?
- 03
Persist Messages and Update Read Status
Ensure messages are saved and can be marked as read
Preview prompt + verify gate ▾ Hide ▴
Create a PATCH /api/messages/:id/read route that: - Verifies `req.userId` is either the sender or receiver of the message. - Updates the specific Message record setting `read = true` and `readAt = now` (add readAt column if not present, include migration instructions). - Returns the updated Message. - Handles errors: 403 if not participant, 404 if message not found. Provide any additional Prisma migration needed for the new `readAt` field, and update the Message model accordingly.
- ✓ Does the PATCH call return the updated message with read=true?
- ✓ Is the readAt timestamp stored in the database?
- ✓ Do unauthorized attempts return 403?
- 04
Build Chat UI Component
Create a visible chat window that lists messages and allows sending new ones
Preview prompt + verify gate ▾ Hide ▴
Implement a React component `ChatBox` that accepts a `conversationId` prop. Inside, fetch messages from GET /api/conversations/:id/messages on mount (useEffect) and display them in a scrollable list showing sender name, content, timestamp, and read indicator. Provide an input field and Send button; on click, POST to /api/messages with the content, then append the new message to the list without reloading. Use the `useAuth()` hook for `userId`. Style with Tailwind to look like a simple chat bubble UI. No placeholder text; messages must render actual data from the API.
- ✓ Does the component display existing messages from the server?
- ✓ Can a user type and send a new message that appears instantly?
- ✓ Are messages styled as chat bubbles with sender distinction?
- 05
Integrate Chat UI into App Navigation
Make the chat reachable from a user's profile or contacts list
Preview prompt + verify gate ▾ Hide ▴
1. In the router configuration, add a new route `<Route path="/chat/:conversationId" element={<ChatPage/>} />`. 2. Create `ChatPage.tsx` that extracts `conversationId` from `useParams()`, renders the `ChatBox` with that ID. 3. On `UserProfile` (or contacts list), add a button that calls an API to either fetch an existing Conversation between the logged‑in user and the profile user or creates one if none exists, then navigates to `/chat/{conversationId}` using `useNavigate`. 4. Ensure the API call uses the new POST /api/conversations endpoint (you may need to create it if not existing) that returns a conversation ID. 5. Verify navigation works and the ChatBox loads the correct messages.
- ✓ Does the 'Message' button open a URL like /chat/<uuid>?
- ✓ Is a Conversation created if none existed?
- ✓ Does the ChatPage render ChatBox with messages for that conversation?
- 06
Add Real‑Time Updates (Polling)
Refresh the chat view when new messages arrive without manual reload
Preview prompt + verify gate ▾ Hide ▴
Modify `ChatBox` to start a `setInterval` on mount that calls the GET messages endpoint every 5 seconds, updating the message list state if there are new messages (compare last message timestamp). Clean up the interval on unmount. Ensure duplicate messages are not added. Include a loading indicator while fetching. No placeholder timers; the interval must be real.
- ✓ Does the message list update when the other user sends a message?
- ✓ Is there no memory leak (interval cleared on unmount)?
- ✓ Are duplicate messages avoided after successive polls?
- 07
End‑to‑End Verification
Confirm the full chat flow works between two real users
Preview prompt + verify gate ▾ Hide ▴
Perform the following manual test steps: 1. Log in as User A, go to User B's profile, click 'Message', start a conversation. 2. Send a message "Hello". Verify it appears in the UI and is stored in the DB (query with Prisma). 3. In a second browser, log in as User B, open the same conversation (via the chat URL). Verify the message appears automatically (polling). 4. Send a reply "Hi" from User B. Confirm it appears for User A. 5. Close and reopen the chat page; ensure the full message history persists. 6. Mark the first message as read (trigger the read endpoint) and verify the read flag updates in the DB. Document the observed results. No code generation needed; just confirm the system behaves as expected.
- ✓ Can User A send a message that User B receives without reload?
- ✓ Is the full conversation stored in the database after reload?
- ✓ Does the read flag update correctly when marked read?
- ✓ Does polling keep both sides in sync?