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>
17 KiB
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:
{ "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:
{ "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
{ "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_refis 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_refis 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
{ "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
{ "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
{ "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=20environment variable - THEN the connection pool maintains 20 persistent connections
Scenario: Pool overflow configuration
- WHEN the application starts with
DB_MAX_OVERFLOW=30environment 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=10is 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_namefield - AND the display name SHALL be obtained by joining with the
tr_userstable - AND if the sender does not exist in
tr_users, the field SHALL fallback tosender_id
Scenario: WebSocket broadcast includes display name
- WHEN a new message is broadcast via WebSocket
- THEN the broadcast SHALL include
sender_display_namefield - AND the value SHALL be the sender's display name from
tr_userstable
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_idas 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
mentionsfield 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
mentionsarray 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