0.12.18 : add create message, conversation
All checks were successful
Build release Docker image / Build Docker Images (push) Successful in 7m23s
All checks were successful
Build release Docker image / Build Docker Images (push) Successful in 7m23s
This commit is contained in:
173
spec.md
Normal file
173
spec.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user