# Technical Specification: Chat Messaging Feature ## Task Complexity: **Medium** ### Rationale - Involves creating relationships between 3 entities (ChatMessage, ChatConversation, ChatConversationMember) - Handles two conversation types with different logic (direct vs group) - Requires user authentication and transactional data creation - Some edge cases (creating conversation before message, handling members, etc.) --- ## Technical Context - **Language**: TypeScript - **Framework**: Strapi 4 - **Database**: Relational DB (presumed based on Strapi structure) - **Existing patterns**: Core controller pattern with custom methods (see `post.ts`) --- ## Current State ### Completed - Schema definitions for `ChatMessage`, `ChatConversation`, `ChatConversationMember` - Service layer structure in place (core service factories) - Basic controller scaffolding ### Missing - Custom controller methods for creating messages and conversations - Business logic for handling conversation creation workflow --- ## Data Model Overview ### ChatConversation - `title`: Optional conversation name - `isGroup`: Boolean (true if 3+ users, false if 2 users) - `creator`: Relation to user - `messages`: OneToMany relation to ChatMessage - `users`: OneToMany relation to user ### ChatConversationMember - `user`: OneToOne relation to user - `conversation`: OneToOne relation to ChatConversation - `role`: Enum (member, admin, owner) - `joinedAt`: DateTime - `lastReadAt`: DateTime ### ChatMessage - `sender`: OneToOne relation to user - `content`: String (required) - `isEdited`: Boolean (default: false) - `deletedAt`: DateTime - **Note**: No back-relation to ChatConversation (by design) --- ## Implementation Approach ### 1. Controller Methods #### `createMessage(ctx)` - **Purpose**: Create a message in a conversation - **Parameters**: - `conversationId` (query/body): ID of target conversation (null if creating new conversation) - `content` (body): Message content (required) - `recipientIds` (body, optional): User IDs for new conversation - **Logic**: - Get authenticated user from `ctx.state.user.id` - If `conversationId` is null/undefined: - Call `createConversation()` with `recipientIds` and authenticated user - Use returned conversation ID - Create ChatMessage with: - `sender`: authenticated user ID - `content`: message content - Add message to ChatConversation.messages relation - Return created message with populated relations #### `createConversation(ctx)` - **Purpose**: Create a new conversation with one or more users - **Parameters**: - `userIds` (body): Array of user IDs to add to conversation - `title` (body, optional): Conversation title (for groups) - **Logic**: - Get authenticated user from `ctx.state.user.id` - Merge authenticated user into conversation members - Remove duplicates from user list - Determine if group: `isGroup = totalUsers > 2` - Create ChatConversation: - `isGroup`: boolean - `creator`: authenticated user ID - `title`: title (optional, for groups) - Create ChatConversationMember records for each user: - `user`: user ID - `conversation`: created conversation ID - `role`: "owner" for creator, "member" for others - `joinedAt`: current timestamp - Return created conversation ### 2. Integration Points - **Authentication**: Use `ctx.state.user?.id` (follows existing pattern in `post.ts`) - **Database queries**: Use `strapi.db.query()` pattern (established in codebase) - **Error handling**: Follow Strapi context methods (`ctx.badRequest()`, `ctx.unauthorized()`) ### 3. Files to Modify - `/Users/julien/projets/dev/harmony/harmony-back/src/api/chat-message/controllers/chat-message.ts` — Add `createMessage()` and helper logic - `/Users/julien/projets/dev/harmony/harmony-back/src/api/chat-conversation/controllers/chat-conversation.ts` — Add `createConversation()` ### 4. No Schema Changes Required - ChatMessage schema is intentionally unidirectional (no back-relation) - All necessary relations already defined in ChatConversation and ChatConversationMember --- ## Verification Approach 1. **Type checking**: Run Strapi build or `npm run build` 2. **Linting**: Run project linting command (TBD - will check package.json) 3. **Manual testing**: - Create message in existing conversation - Create message with null conversationId (should create conversation first) - Create conversation with 2 users (direct message) - Create conversation with 3+ users (group chat) - Verify `isGroup` flag is set correctly - Verify ChatConversationMember records are created with correct roles --- ## Implementation Decisions (Confirmed) 1. **User validation**: ✅ Validate recipient user IDs exist before creating conversation 2. **API routing**: ✅ `createMessage` belongs to chat-message controller 3. **Permission checks**: ✅ Verify user is member of conversation before sending message --- ## Detailed Implementation Plan ### Task 1: Implement `createConversation` in chat-conversation controller - Validate all recipient user IDs exist in database - Add authenticated user to members list - Determine `isGroup` based on total user count (>2 = group) - Create ChatConversation record with creator and title - Create ChatConversationMember records for all users with appropriate roles - Return created conversation with populated members ### Task 2: Implement `createMessage` in chat-message controller - Validate authenticated user exists - If conversationId is null: call service method to create conversation with recipientIds - If conversationId is provided: - Verify conversation exists - Verify user is member of conversation (permission check) - Validate message content (required, non-empty) - Create ChatMessage with sender and content - Add message to conversation.messages relation - Return created message with populated sender relation ### Task 3: Add helper service methods in chat-conversation service - `createConversationWithMembers()`: Centralized logic for creating conversation + members - Used by both direct createConversation controller and createMessage ### Task 4: Add helper service methods in chat-message service - `createMessageInConversation()`: Centralized logic for creating and linking message ### Task 5: Verification - Build and type-check the project - Run linting - Verify error handling for edge cases