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:
parent
0f8a2d7863
commit
ea7e021452
@ -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
|
||||
Loading…
Reference in New Issue
Block a user