docs: add messaging enhancements design spec

Six incremental improvements: flash confirmation, form hint, recipient
preview, read receipts, branded email, file attachments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-11 17:04:10 +01:00
parent 0f8a2d7863
commit ea7e021452

View File

@ -0,0 +1,146 @@
# Messaging System Enhancements — Design Spec
**Date:** 2026-03-11
**Status:** Approved
**Scope:** 6 incremental improvements to `/wiadomosci` messaging system
## Context
NordaBiz messaging system has solid foundations: `PrivateMessage` model with threading (`parent_id`), `UserNotification` creation on send, email notifications via Microsoft Graph API, user blocking, and bell-icon notification dropdown. Missing: post-send confirmation, recipient preview, read receipts visibility, branded email template, file attachments.
## Feature 1: Post-Send Flash Message
**Goal:** Inform sender that message was delivered and recipient will be notified.
**Implementation:**
- In `messages_send()` route (`blueprints/messages/routes.py`), add `flash()` after successful send
- Message text: `"Wiadomość wysłana! Odbiorca zostanie powiadomiony emailem."` (category: `success`)
- If recipient has `notify_email_messages=False`: `"Wiadomość wysłana!"` (without email mention)
- Redirect to sent box remains unchanged
**Files:** `blueprints/messages/routes.py`
## Feature 2: Contextual Hint on Compose Form
**Goal:** Before sending, inform user what happens after they click "Wyślij".
**Implementation:**
- Add hint text below the submit button in `compose.html`
- Text: `"📧 Odbiorca zostanie powiadomiony o nowej wiadomości emailem"`
- Styled as muted/secondary text, small font, consistent with form design
- Static text — no backend changes needed
**Files:** `templates/messages/compose.html`
## Feature 3: Recipient Profile Preview
**Goal:** After selecting recipient in autocomplete, show mini business card.
**Implementation:**
- Extend the `users` JSON injected into `compose.html` with: `company_name`, `company_slug`, `position` (job title)
- Route `messages_new()` already queries all active verified users — add LEFT JOIN to `UserCompanyPermissions` + `Company` to get company info
- In compose.html JS, when recipient is selected via `selectRecipient()`, populate a preview card below the selected-recipient chip:
- Avatar initials (already exist in autocomplete items)
- Company name (linked to company profile if available)
- Position/role text
- Preview card hidden when no recipient selected, shown with fade-in on selection
**Files:** `blueprints/messages/routes.py` (extend user query), `templates/messages/compose.html` (preview card UI + JS)
## Feature 4: Read Receipts in Sent Box
**Goal:** Sender can see which sent messages have been read.
**Implementation:**
- In `messages_sent()` route, the query already returns `PrivateMessage` objects with `is_read` and `read_at` fields
- In `sent.html` template, add visual indicator per message:
- Unread: single gray checkmark icon or "Wysłana" badge
- Read: double blue checkmark or "Przeczytana" badge with `read_at` timestamp on hover (title attribute)
- CSS-only styling, no JS needed
- No new DB queries — data already available on the model
**Files:** `templates/messages/sent.html`
## Feature 5: Branded Email Notification
**Goal:** Message notification email should use the same branded template as password reset and welcome emails.
**Implementation:**
- Current inline HTML in `messages_send()` (lines ~203-212) replaced with call to a new helper function
- New function `_build_message_notification_email(sender_name, subject, content_preview, message_url)` in `email_service.py`
- Uses existing `_email_v3_wrap()` template for consistent branding
- Content: sender name, subject, first 200 chars of message body, "Przeczytaj wiadomość" CTA button
- Preserves existing logic: only sends if `recipient.notify_email_messages != False`
**Files:** `email_service.py` (new template function), `blueprints/messages/routes.py` (use new function instead of inline HTML)
## Feature 6: File Attachments
**Goal:** Allow attaching files (images + business documents) to messages.
### Database Model
New model `MessageAttachment`:
```python
class MessageAttachment(Base):
__tablename__ = 'message_attachments'
id = Column(Integer, primary_key=True)
message_id = Column(Integer, ForeignKey('private_messages.id', ondelete='CASCADE'), nullable=False)
filename = Column(String(255), nullable=False) # original filename
stored_filename = Column(String(255), nullable=False) # UUID-based on disk
file_size = Column(Integer, nullable=False) # bytes
mime_type = Column(String(100), nullable=False)
created_at = Column(DateTime, default=datetime.now)
```
Relationship on `PrivateMessage`: `attachments = relationship('MessageAttachment', backref='message', cascade='all, delete-orphan')`
### File Storage
- Path: `static/uploads/messages/{year}/{month:02d}/{uuid}.{ext}`
- Reuse `FileUploadService` pattern but extend allowed types:
- Images: JPG, PNG, GIF (max 5MB each)
- Documents: PDF, DOCX, XLSX (max 10MB each)
- Magic bytes validation for all types
- Max 3 files per message, max 15MB total
- No EXIF stripping for documents (only images)
### Upload Flow
- `compose.html`: file input with drag & drop zone (reuse forum pattern)
- Files uploaded with the message form submission (multipart/form-data) — no pre-upload AJAX
- `messages_send()` processes files after message creation
- `messages_reply()` also supports attachments
### Display
- `view.html`: attachments listed below message content
- Images: inline thumbnail preview (max 300px wide) with click to full size
- Documents: file icon + filename + size, click to download
- `sent.html` / `inbox.html`: paperclip icon indicator if message has attachments
### Migration
SQL migration: `database/migrations/XXX_message_attachments.sql`
- CREATE TABLE + indexes + GRANT permissions to `nordabiz_app`
**Files:** `database.py`, `blueprints/messages/routes.py`, `templates/messages/compose.html`, `templates/messages/view.html`, `templates/messages/sent.html`, `templates/messages/inbox.html`, `database/migrations/XXX_message_attachments.sql`
## Implementation Order
1. Flash message (smallest, immediate UX win)
2. Contextual hint (CSS only, no backend)
3. Read receipts in sent box (template change, data exists)
4. Recipient profile preview (query extension + JS)
5. Branded email template (email_service refactor)
6. File attachments (largest — new model, migration, upload logic, UI)
Each feature is an independent commit, deployable and testable separately.
## Out of Scope
- Real-time WebSocket notifications (current 60s polling is sufficient)
- Message search
- Group messages / broadcast
- Message deletion by sender
- Typing indicators