Skip to content
Flows
App Builder Generated Intermediate · 90-120 minutes

Add Direct Messaging Feature

Implement a real, persistent one‑to‑one chat system in the existing app

Start Route · 7 steps

The route

7 steps to Done

  1. 01

    Design Message & Conversation Data Model

    Create database structures to store chats and individual messages

    Preview prompt + verify gate ▾

    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?
  2. 02

    Create API Endpoints for Messaging

    Expose HTTP routes to send a message and fetch a conversation's messages

    Preview prompt + verify gate ▾

    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?
  3. 03

    Persist Messages and Update Read Status

    Ensure messages are saved and can be marked as read

    Preview prompt + verify gate ▾

    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?
  4. 04

    Build Chat UI Component

    Create a visible chat window that lists messages and allows sending new ones

    Preview prompt + verify gate ▾

    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?
  5. 05

    Integrate Chat UI into App Navigation

    Make the chat reachable from a user's profile or contacts list

    Preview prompt + verify gate ▾

    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?
  6. 06

    Add Real‑Time Updates (Polling)

    Refresh the chat view when new messages arrive without manual reload

    Preview prompt + verify gate ▾

    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?
  7. 07

    End‑to‑End Verification

    Confirm the full chat flow works between two real users

    Preview prompt + verify gate ▾

    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?