Files
Task_Reporter/openspec/specs/realtime-messaging/spec.md
egg 44822a561a feat: Improve file display, timezone handling, and LOT management
Changes:
- Fix datetime serialization with UTC 'Z' suffix for correct timezone display
- Add PDF upload support with extension fallback for MIME detection
- Fix LOT add/remove by creating new list for SQLAlchemy JSON change detection
- Add file message components (FileMessage, ImageLightbox, UploadPreview)
- Add multi-file upload support with progress tracking
- Link uploaded files to chat messages via message_id
- Include file attachments in AI report generation
- Update specs for file-storage, realtime-messaging, and ai-report-generation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 12:39:15 +08:00

411 lines
17 KiB
Markdown

# realtime-messaging Specification
## Purpose
TBD - created by archiving change add-realtime-messaging. Update Purpose after archive.
## Requirements
### Requirement: WebSocket Connection Management
The system SHALL provide WebSocket endpoints for establishing persistent bidirectional connections between clients and server, with automatic reconnection handling and connection state management.
#### Scenario: Establish WebSocket connection
- **WHEN** an authenticated user connects to `ws://localhost:8000/ws/{room_id}`
- **THEN** the system SHALL validate user's room membership
- **AND** establish a WebSocket connection
- **AND** add the connection to the room's active connections pool
- **AND** broadcast a "user joined" event to other room members
#### Scenario: Handle connection authentication
- **WHEN** a WebSocket connection request is made without valid authentication token
- **THEN** the system SHALL reject the connection with status 401
- **AND** close the WebSocket immediately
#### Scenario: Automatic reconnection
- **WHEN** a WebSocket connection is dropped unexpectedly
- **THEN** the client SHALL attempt to reconnect automatically with exponential backoff
- **AND** resume from the last received message sequence number
- **AND** request any missed messages during disconnection
### Requirement: Real-time Message Broadcasting
The system SHALL broadcast messages to all active room members in real-time, ensuring message ordering and delivery acknowledgment.
#### Scenario: Send text message
- **WHEN** a room member sends a message via WebSocket:
```json
{
"type": "message",
"content": "Equipment temperature rising to 85°C",
"message_type": "text"
}
```
- **THEN** the system SHALL:
- Validate user has write permission (OWNER or EDITOR role)
- Assign a unique message_id and timestamp
- Store the message in database
- Broadcast to all active WebSocket connections in the room
- Return acknowledgment to sender with message_id
#### Scenario: Send system notification
- **WHEN** a system event occurs (user joined, room status changed, etc.)
- **THEN** the system SHALL broadcast a system message:
```json
{
"type": "system",
"event": "user_joined",
"user_id": "john.doe@panjit.com.tw",
"timestamp": "2025-11-17T10:00:00Z"
}
```
- **AND** all connected clients SHALL display the notification
#### Scenario: Handle message ordering
- **WHEN** multiple messages are sent simultaneously
- **THEN** the system SHALL ensure FIFO ordering using message sequence numbers
- **AND** clients SHALL display messages in the correct order
### Requirement: Message Persistence and History
The system SHALL persist all messages to database for audit trail, report generation, and history retrieval.
#### Scenario: Store message in database
- **WHEN** a message is sent through WebSocket
- **THEN** the system SHALL create a database record with:
- message_id (UUID)
- room_id (FK to incident_rooms)
- sender_id (user email)
- content (text or JSON for structured messages)
- message_type (text, image_ref, file_ref, system)
- created_at timestamp
- edited_at (nullable for message edits)
- deleted_at (nullable for soft delete)
- sequence_number (for ordering)
#### Scenario: Retrieve message history
- **WHEN** a user joins a room or reconnects
- **THEN** the system SHALL load recent messages via `GET /api/rooms/{room_id}/messages?limit=50&before={timestamp}`
- **AND** return messages in reverse chronological order
- **AND** include pagination metadata for loading more history
#### Scenario: Search messages
- **WHEN** a user searches for messages containing specific keywords
- **THEN** the system SHALL query the database with full-text search
- **AND** return matching messages with highlighted search terms
- **AND** maintain user's access control (only rooms they're members of)
### Requirement: Message Types and Formatting
The system SHALL support various message types including text, image references, file references, and structured data for production incidents, with inline display of file attachments in the chat view.
#### Scenario: Text message with mentions
- **WHEN** a user sends a message with @mentions
```json
{
"content": "@maintenance_team Please check Line 3 immediately",
"mentions": ["maintenance_team@panjit.com.tw"]
}
```
- **THEN** the system SHALL parse and store mentions
- **AND** potentially trigger notifications to mentioned users
#### Scenario: Image reference message display
- **WHEN** a message with `message_type=image_ref` is rendered in the chat
- **THEN** the client SHALL display:
- A thumbnail of the image (max 300px width)
- The message content/caption below the image
- Sender name and timestamp
- A click-to-expand functionality
- **AND** clicking the thumbnail SHALL open a full-size preview lightbox
#### Scenario: File reference message display
- **WHEN** a message with `message_type=file_ref` is rendered in the chat
- **THEN** the client SHALL display:
- A file type icon (PDF, document, log, etc.)
- The filename
- File size in human-readable format
- A download button/link
- The message content/caption
- Sender name and timestamp
#### Scenario: Structured incident data
- **WHEN** reporting specific incident metrics
```json
{
"type": "message",
"message_type": "incident_data",
"content": {
"temperature": 85,
"pressure": 120,
"production_rate": 450,
"timestamp": "2025-11-17T10:15:00Z"
}
}
```
- **THEN** the system SHALL store structured data as JSON
- **AND** enable querying/filtering by specific fields later
### Requirement: Connection State Management
The system SHALL track online presence and typing indicators for better collaboration experience.
#### Scenario: Track online users
- **WHEN** users connect/disconnect from a room
- **THEN** the system SHALL maintain a list of online users
- **AND** broadcast presence updates to all room members
- **AND** display online status indicators in UI
#### Scenario: Typing indicators
- **WHEN** a user starts typing a message
- **THEN** the client SHALL send a "typing" event via WebSocket
- **AND** the system SHALL broadcast to other room members
- **AND** automatically clear typing status after 3 seconds of inactivity
#### Scenario: Connection health monitoring
- **WHEN** a WebSocket connection is established
- **THEN** the system SHALL send ping frames every 30 seconds
- **AND** expect pong responses within 10 seconds
- **AND** terminate connection if no response received
### Requirement: Message Operations
The system SHALL support message editing and deletion with proper audit trail and permissions.
#### Scenario: Edit own message
- **WHEN** a user edits their own message within 15 minutes
```json
{
"type": "edit_message",
"message_id": "msg-123",
"content": "Updated: Equipment temperature stabilized at 75°C"
}
```
- **THEN** the system SHALL update the message content
- **AND** set edited_at timestamp
- **AND** broadcast the edit to all connected clients
- **AND** preserve original message in audit log
#### Scenario: Delete message
- **WHEN** a user deletes their own message or admin deletes any message
- **THEN** the system SHALL perform soft delete (set deleted_at)
- **AND** broadcast deletion event to all clients
- **AND** clients SHALL show "message deleted" placeholder
- **AND** preserve message in database for audit
#### Scenario: React to message
- **WHEN** a user adds a reaction emoji to a message
```json
{
"type": "add_reaction",
"message_id": "msg-123",
"emoji": "👍"
}
```
- **THEN** the system SHALL store the reaction
- **AND** broadcast to all connected clients
- **AND** aggregate reaction counts for display
### Requirement: Short-lived Database Sessions for WebSocket
The system SHALL process WebSocket messages using short-lived database sessions that are acquired and released for each individual operation, rather than holding a session for the entire WebSocket connection lifetime.
#### Scenario: Message creation with short session
- **WHEN** a user sends a message via WebSocket
- **THEN** the system acquires a database session
- **AND** creates the message with proper sequence number
- **AND** commits the transaction
- **AND** releases the session immediately
- **AND** broadcasts the message to room members
#### Scenario: Concurrent message handling
- **WHEN** multiple users send messages simultaneously
- **THEN** each message operation uses an independent database session
- **AND** sequence numbers are correctly assigned without duplicates
- **AND** no connection pool exhaustion occurs
### Requirement: Message Sequence Number Integrity
The system SHALL guarantee unique, monotonically increasing sequence numbers per room using database-level locking to prevent race conditions during concurrent message creation.
#### Scenario: Concurrent sequence assignment
- **WHEN** two users send messages to the same room at the exact same time
- **THEN** each message receives a unique sequence number
- **AND** the sequence numbers are consecutive without gaps or duplicates
#### Scenario: High concurrency sequence safety
- **WHEN** 50+ users send messages to the same room simultaneously
- **THEN** all messages receive correct unique sequence numbers
- **AND** the operation does not cause deadlocks
### Requirement: Configurable Database Connection Pool
The system SHALL support environment variable configuration for database connection pool parameters to optimize for different deployment scales.
#### Scenario: Custom pool size configuration
- **WHEN** the application starts with `DB_POOL_SIZE=20` environment variable
- **THEN** the connection pool maintains 20 persistent connections
#### Scenario: Pool overflow configuration
- **WHEN** the application starts with `DB_MAX_OVERFLOW=30` environment variable
- **THEN** the connection pool can expand up to 30 additional connections beyond the pool size
#### Scenario: Pool timeout configuration
- **WHEN** all connections are in use and a new request arrives
- **AND** `DB_POOL_TIMEOUT=10` is configured
- **THEN** the request waits up to 10 seconds for an available connection
- **AND** raises an error if no connection becomes available
#### Scenario: Default configuration
- **WHEN** no database pool environment variables are set
- **THEN** the system uses production-ready defaults (pool_size=20, max_overflow=30, timeout=10, recycle=1800)
### Requirement: Message Sender Display Name
The system SHALL include the sender's display name in message responses and broadcasts, enabling the UI to show user-friendly names instead of email addresses.
#### Scenario: Message response includes display name
- **WHEN** a message is retrieved via REST API or WebSocket
- **THEN** the response SHALL include `sender_display_name` field
- **AND** the display name SHALL be obtained by joining with the `tr_users` table
- **AND** if the sender does not exist in `tr_users`, the field SHALL fallback to `sender_id`
#### Scenario: WebSocket broadcast includes display name
- **WHEN** a new message is broadcast via WebSocket
- **THEN** the broadcast SHALL include `sender_display_name` field
- **AND** the value SHALL be the sender's display name from `tr_users` table
#### Scenario: Historical messages include display name
- **WHEN** a client requests message history via `GET /api/rooms/{room_id}/messages`
- **THEN** each message in the response SHALL include `sender_display_name`
- **AND** messages from unknown users SHALL show their `sender_id` as fallback
### Requirement: GMT+8 Timezone Display
The frontend SHALL display all timestamps in GMT+8 (Asia/Taipei) timezone for consistent user experience across all browsers and all parts of the application.
#### Scenario: Message timestamp in GMT+8
- **WHEN** a message is displayed in the chat room
- **THEN** the timestamp SHALL be formatted in GMT+8 timezone
- **AND** use format "HH:mm" for today's messages
- **AND** use format "MM/DD HH:mm" for older messages
#### Scenario: Room list timestamps in GMT+8
- **WHEN** the room list is displayed
- **THEN** the "last updated" time SHALL be formatted in GMT+8 timezone
#### Scenario: File upload timestamp in GMT+8
- **WHEN** a file is displayed in chat or file drawer
- **THEN** the upload timestamp SHALL be formatted in GMT+8 timezone
#### Scenario: Report generation timestamp in GMT+8
- **WHEN** report metadata is displayed
- **THEN** the "generated at" timestamp SHALL be formatted in GMT+8 timezone
### Requirement: @Mention Support
The messaging system SHALL support @mention functionality to tag specific users in messages.
#### Scenario: Trigger mention autocomplete
- **WHEN** user types `@` in the message input
- **THEN** a dropdown menu appears showing room members
- **AND** the list filters as user continues typing
- **AND** user can select a member using keyboard or mouse
#### Scenario: Insert mention into message
- **WHEN** user selects a member from the mention dropdown
- **THEN** the mention is inserted as `@display_name`
- **AND** the mention is stored with the user_id reference
- **AND** the mention is visually highlighted in the message
#### Scenario: Mention notification
- **WHEN** a message containing @mention is sent
- **THEN** the mentioned user receives a highlighted notification
- **AND** the notification indicates they were mentioned
### Requirement: Browser Push Notifications
The system SHALL support browser push notifications for new messages.
#### Scenario: Request notification permission
- **WHEN** user first visits the chat room
- **THEN** the system prompts for notification permission
- **AND** the permission state is stored locally
#### Scenario: Send push notification
- **WHEN** a new message arrives while the tab is not focused
- **AND** user has granted notification permission
- **THEN** a browser push notification is displayed
- **AND** clicking the notification focuses the chat room
### Requirement: Sound and Vibration Alerts
The system SHALL support audio and haptic feedback for new messages.
#### Scenario: Play notification sound
- **WHEN** a new message arrives
- **AND** sound notifications are enabled
- **THEN** a notification sound is played
#### Scenario: Vibrate on mobile
- **WHEN** a new message arrives on a mobile device
- **AND** vibration is enabled
- **AND** the device supports Vibration API
- **THEN** the device vibrates briefly
### Requirement: Mention Data Storage
Messages with @mentions SHALL store the mention metadata for querying.
#### Scenario: Store mention references
- **WHEN** a message with @mentions is created
- **THEN** the `mentions` field stores an array of mentioned user_ids
- **AND** the message content preserves the @display_name format
#### Scenario: Query messages mentioning user
- **WHEN** fetching messages that mention a specific user
- **THEN** messages with that user_id in `mentions` array are returned
### Requirement: Image Preview Lightbox
The frontend SHALL provide a lightbox component for viewing full-size images from chat messages.
#### Scenario: Open image lightbox
- **WHEN** user clicks on an image thumbnail in the chat
- **THEN** a modal overlay SHALL appear
- **AND** the full-size image SHALL be displayed centered
- **AND** a loading indicator SHALL show while image loads
- **AND** the image SHALL be constrained to fit the viewport
#### Scenario: Close image lightbox
- **WHEN** the lightbox is open
- **THEN** user can close it by:
- Clicking the X button
- Pressing the ESC key
- Clicking outside the image
- **AND** focus SHALL return to the chat
#### Scenario: Image lightbox with download
- **WHEN** the lightbox is open
- **THEN** a download button SHALL be visible
- **AND** clicking it SHALL download the original file
### Requirement: File Type Icons
The frontend SHALL display appropriate icons for different file types in chat messages and file drawer.
#### Scenario: PDF file icon
- **WHEN** a PDF file is displayed
- **THEN** a PDF icon (red/document style) SHALL be shown
#### Scenario: Log/text file icon
- **WHEN** a .log or .txt file is displayed
- **THEN** a text file icon SHALL be shown
#### Scenario: Excel file icon
- **WHEN** an Excel file (.xlsx, .xls) is displayed
- **THEN** a spreadsheet icon (green) SHALL be shown
#### Scenario: Generic file icon
- **WHEN** a file with unknown type is displayed
- **THEN** a generic document icon SHALL be shown
### Requirement: Upload Preview
The frontend SHALL show a preview of the file being uploaded before the message is sent.
#### Scenario: Image upload preview
- **WHEN** user selects an image file for upload
- **THEN** a preview thumbnail SHALL be displayed in the input area
- **AND** user can add a caption/description
- **AND** user can cancel the upload before sending
- **AND** a send button confirms the upload
#### Scenario: File upload preview
- **WHEN** user selects a non-image file for upload
- **THEN** file info (name, size, type icon) SHALL be displayed
- **AND** user can add a description
- **AND** user can cancel or confirm