eduverse-backend / Documentation /Flutter_Chat_API_Docs.md
amirhamdi's picture
1 fix(google-drive): add self-healing folder management with duplicate prevention
b4c4de1
|
Raw
History Blame Contribute Delete
11.8 kB

EduVerse API - Chat & Discussions Documentation for Flutter

This document provides a comprehensive, technically detailed guide for integrating the Chat and Discussions features into the EduVerse Flutter application. It covers all roles (student, instructor, teaching_assistant, admin, it_admin), providing endpoint details, expected request shapes, response formats, WebSocket specifications, and Flutter implementation tips.


1. General Info & Headers

Base URL Configuration

  • Local Dev (Android Emulator): http://10.0.2.2:8081
  • Local Dev (iOS Simulator / Web): http://localhost:8081
  • Production: <PRODUCTION_URL>

Headers For all protected endpoints, the JWT accessToken must be passed in the Authorization header:

Authorization: Bearer <your_access_token>

2. Real-Time Messaging (Direct & Groups)

The Messaging module (/api/messages and /messaging WebSocket) provides real-time chat capabilities. It is accessible to all roles.

2.1 WebSocket Connection

Namespace: /messaging Access: All Roles (Requires Token) Type: Socket.IO connection

Connection URI:

ws://localhost:8081/messaging?token=<your_access_token>

Events Emitted by Client (Flutter -> Backend):

  • join_conversation: Join a room. Payload: { "conversationId": 1 }
  • leave_conversation: Leave a room. Payload: { "conversationId": 1 }
  • send_message: Send a real-time message. Payload (WsSendMessageDto):
    {
      "conversationId": 1,
      "text": "Hello!",
      "fileId": null, // Optional file attachment ID
      "replyToId": null // Optional message ID to reply to
    }
    
  • typing: Indicate typing status. Payload: { "conversationId": 1, "isTyping": true }
  • mark_read: Mark conversation as read. Payload: { "conversationId": 1 }
  • delete_message: Socket-based deletion. Payload: { "messageId": 5, "forEveryone": true }
  • edit_message: Socket-based editing. Payload: { "messageId": 5, "text": "Edited hello!" }

Events Listened by Client (Backend -> Flutter):

  • new_message: Incoming message in active room.
  • new_message_notification: Incoming message for unjoined room (global notification).
  • user_typing: Someone is typing. Payload: { "conversationId": 1, "userId": 42, "isTyping": true }
  • message_read: Receipt that messages were read.
  • message_deleted: A message was deleted for everyone.
  • message_edited: A message text was updated.
  • user_status: User came online/offline. Payload: { "userId": 42, "isOnline": true, "lastSeen": "..." }

2.2 Messaging REST Endpoints

2.2.1 Search Users (Start New Chat)

Endpoint: GET /api/messages/users/search Access: All Roles Description: Search for users by name or email to start a conversation. Query params: query (string), limit (int, default 20). Success Response: (Array of Users)

[
  { "userId": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@example.com" }
]

2.2.2 List Conversations

Endpoint: GET /api/messages/conversations Access: All Roles Description: Lists all active conversations for the current user. Result sorted by lastMessageAt. Success Response:

[
  {
    "conversationId": 15,
    "type": "direct", // 'direct' or 'group'
    "name": null, // For groups, this is the group name
    "participants": [42, 10], // Array of User IDs
    "participantUsers": [ { "userId": 42, "fullName": "Student One" } ],
    "directDisplayUser": { "userId": 10, "fullName": "Instructor John" }, // Who you are talking to in direct chat
    "lastMessage": "Sure, no problem!",
    "lastMessageInfo": { "id": 102, "senderId": 10, "isDeleted": false, "sentAt": "2026-08-15T..." },
    "unreadCount": 2
  }
]

2.2.3 Start New Conversation

Endpoint: POST /api/messages/conversations Access: All Roles Body: StartConversationDto

{
  "participantIds": [10],
  "type": "direct", // or 'group'
  "groupName": "Optional Group Name",
  "text": "Hi Instructor! I have a question.",
  "fileId": null 
}

Note: If a direct conversation already exists, the backend automatically routes the message to the existing thread.

2.2.4 Get Conversation Messages

Endpoint: GET /api/messages/conversations/:id Access: All Roles (Must be participant) Query params: page (int), limit (int). Response: Paginated list of messages. Deleted messages return text "This message was deleted" and isDeleted: true.

2.2.5 Send Message (REST fallback)

Endpoint: POST /api/messages/conversations/:id Access: All Roles (Must be participant) Body: SendMessageDto (text, fileId, replyToId).

2.2.6 Edit / Mark Read / Delete

  • Edit Message: PATCH /api/messages/:id (Body: { "text": "new text" }). Only sender can edit.
  • Mark as Read: PATCH /api/messages/:id/read
  • Delete for Me: DELETE /api/messages/:id
  • Delete for Everyone: DELETE /api/messages/:id/everyone (Only sender can invoke).

3. Course Discussions (Forums)

The Discussions module (/api/discussions) provides thread-based, Q&A style forums bound to specific courses.

3.1 Role-Based Access Rules

  • Student: Allowed to read/create/reply ONLY if they have an enrolled status in course_enrollments for a section belonging to the course. Can only update/delete their own threads.
  • Instructor / TA: Full access to courses they teach. They can Pin, Lock, Endorse, and Delete threads/replies.
  • Admin / IT Admin: Global access to all discussions. Full moderation powers.

3.2 Discussion Endpoints

3.2.1 List Discussion Threads

Endpoint: GET /api/discussions Access: Students (if enrolled), Staff/Admins (course specific or global). Query params: courseId (int, required for students), page (int), limit (int). Response: Paginated threads. Pinned threads ALWAYS appear first.

{
  "data": [
    {
      "id": 1,
      "courseId": 5,
      "createdBy": 42,
      "title": "Help with Binary Search Trees",
      "description": "I don't understand the insertion...",
      "isPinned": false,
      "isLocked": false,
      "viewCount": 15,
      "replyCount": 3,
      "createdAt": "..."
    }
  ]
}

3.2.2 Create Thread

Endpoint: POST /api/discussions Access: Students (enrolled), Instructors, TAs, Admins. Body:

{
  "courseId": 5,
  "title": "Midterm Review Session Topics",
  "description": "What should we cover?"
}

3.2.3 Get Thread & Replies

Endpoint: GET /api/discussions/:id Description: Fetch a thread and its paginated replies. Calling this increments the view count. Replies marked as isAnswer appear first. Response Shape:

{
  "thread": { /* Thread object */ },
  "replies": {
    "data": [
      {
        "id": 100,
        "userId": 10,
        "messageText": "Start with the invariant property...",
        "isAnswer": true, // Instructor marked this as correct answer
        "isEndorsed": true, // Instructor endorsed
        "endorsedBy": 10
      }
    ],
    "meta": { /* Pagination */ }
  }
}

3.2.4 Post Reply

Endpoint: POST /api/discussions/:id/reply Body: { "messageText": "Here is my answer...", "parentMessageId": null } Fails (400) if thread isLocked.

3.2.5 Moderation Endpoints (Instructors, TAs, Admins)

These return HTTP 200/204 on success.

  • Update Thread: PUT /api/discussions/:id (Update title/desc. Authors can do this too).
  • Delete Thread: DELETE /api/discussions/:id (Instructors/Admins only).
  • Toggle Pin: PATCH /api/discussions/:id/pin (Pins to top of list).
  • Toggle Lock: PATCH /api/discussions/:id/lock (Prevents new replies).
  • Mark as Answer: PATCH /api/discussions/replies/:replyId/mark-answer (Moves reply to top).
  • Endorse Reply: PATCH /api/discussions/replies/:replyId/endorse (Marks as staff-approved).

4. Role-Specific Action Matrix

This matrix clarifies what UI elements you should render in Flutter based on the user's role.

A. Student Profile

  • Messaging Profile: Can chat directly with any searchable user (other students, TAs, instructors).
  • Discussions Profile:
    • Can only view/create threads for enrolled courses.
    • Cannot see "Pin", "Lock", "Endorse", or "Mark Answer" buttons.
    • Can delete/edit only their own messages.

B. Instructor & TA Profile

  • Messaging Profile: Standard Real-Time chat capabilities.
  • Discussions Profile:
    • Should have moderation UI buttons visible on threads (Pin, Lock, Delete Topic).
    • Should have moderation UI buttons on replies (Endorse, Mark as Answer).
    • TAs have identical discussion moderation privileges inside their assigned sections.

C. Admin & IT_Admin Profile

  • Has omnipotent access. Can view/moderate any discussion thread across the entire application without needing enrollment.

5. Flutter & Dart Implementation Tips

1. WebSocket Integration (socket_io_client)

For Flutter, use the socket_io_client package to connect to NestJS WebSockets. Keep this singleton in a Bloc/Repository.

import 'package:socket_io_client/socket_io_client.dart' as IO;

class ChatSocketService {
  IO.Socket? socket;

  void connect(String token) {
    socket = IO.io('http://10.0.2.2:8081/messaging', IO.OptionBuilder()
        .setTransports(['websocket']) // for Flutter or Web
        .disableAutoConnect()
        .setQuery({'token': token})
        .build());

    socket!.connect();

    // Listeners
    socket!.onConnect((_) => print('Connected to Chat WS'));
    
    socket!.on('new_message', (data) {
      // Map data to MessageModel and dispatch to Bloc
    });
    
    socket!.on('new_message_notification', (data) {
      // Show local notification snackbar
    });
  }

  void sendMessage(int convId, String text) {
    socket!.emit('send_message', {
      'conversationId': convId,
      'text': text,
    });
  }
}

2. Freezed Models Setup

@freezed
class ConversationSummary with _$ConversationSummary {
  const factory ConversationSummary({
    required int conversationId,
    required String type,
    String? name,
    @Default([]) List<int> participants,
    UserSummary? directDisplayUser,
    String? lastMessage,
    required DateTime lastMessageAt,
    @Default(0) int unreadCount,
  }) = _ConversationSummary;

  factory ConversationSummary.fromJson(Map<String, dynamic> json) => _$ConversationSummaryFromJson(json);
}

@freezed
class ChatMessageModel with _$ChatMessageModel {
  const factory ChatMessageModel({
    required int id,
    required int senderId,
    String? text,
    @Default(false) bool isDeleted,
    String? deletedText,
    int? replyToId,
    required DateTime sentAt,
    DateTime? editedAt,
    required String status,
  }) = _ChatMessageModel;

  factory ChatMessageModel.fromJson(Map<String, dynamic> json) => _$ChatMessageModelFromJson(json);
}

3. Moderation Features Visibility

In your Flutter UI for discussions, rely on the user's roles from your AuthBloc to conditionally show UI actions.

bool isModerator = currentUser.roles.any((r) => 
  ['instructor', 'teaching_assistant', 'admin', 'it_admin'].contains(r.roleName)
);

// In your Discussion Thread UI:
if (isModerator) ...[
  IconButton(
    icon: Icon(thread.isPinned ? Icons.push_pin : Icons.push_pin_outlined),
    onPressed: () => context.read<DiscussionBloc>().add(TogglePinEvent(thread.id)),
  ),
  IconButton(
    icon: Icon(thread.isLocked ? Icons.lock : Icons.lock_open),
    onPressed: () => context.read<DiscussionBloc>().add(ToggleLockEvent(thread.id)),
  ),
]