All checks were successful
Build release Docker image / Build Docker Images (push) Successful in 7m23s
6.3 KiB
6.3 KiB
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 nameisGroup: Boolean (true if 3+ users, false if 2 users)creator: Relation to usermessages: OneToMany relation to ChatMessageusers: OneToMany relation to user
ChatConversationMember
user: OneToOne relation to userconversation: OneToOne relation to ChatConversationrole: Enum (member, admin, owner)joinedAt: DateTimelastReadAt: DateTime
ChatMessage
sender: OneToOne relation to usercontent: 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
conversationIdis null/undefined:- Call
createConversation()withrecipientIdsand authenticated user - Use returned conversation ID
- Call
- Create ChatMessage with:
sender: authenticated user IDcontent: message content
- Add message to ChatConversation.messages relation
- Return created message with populated relations
- Get authenticated user from
createConversation(ctx)
- Purpose: Create a new conversation with one or more users
- Parameters:
userIds(body): Array of user IDs to add to conversationtitle(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: booleancreator: authenticated user IDtitle: title (optional, for groups)
- Create ChatConversationMember records for each user:
user: user IDconversation: created conversation IDrole: "owner" for creator, "member" for othersjoinedAt: current timestamp
- Return created conversation
- Get authenticated user from
2. Integration Points
- Authentication: Use
ctx.state.user?.id(follows existing pattern inpost.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— AddcreateMessage()and helper logic/Users/julien/projets/dev/harmony/harmony-back/src/api/chat-conversation/controllers/chat-conversation.ts— AddcreateConversation()
4. No Schema Changes Required
- ChatMessage schema is intentionally unidirectional (no back-relation)
- All necessary relations already defined in ChatConversation and ChatConversationMember
Verification Approach
- Type checking: Run Strapi build or
npm run build - Linting: Run project linting command (TBD - will check package.json)
- 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
isGroupflag is set correctly - Verify ChatConversationMember records are created with correct roles
Implementation Decisions (Confirmed)
- User validation: ✅ Validate recipient user IDs exist before creating conversation
- API routing: ✅
createMessagebelongs to chat-message controller - 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
isGroupbased 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