nordabiz/docs/superpowers/specs/2026-03-11-messaging-enhancements-design.md
Maciej Pienczyn ea7e021452 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>
2026-03-11 17:04:10 +01:00

6.4 KiB

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:

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