Messaging
Real-time practitioner–client messaging with GIFs, reactions, replies, canned responses, and full-text search.
MealStack includes a full-featured messaging system that lets practitioners and clients communicate directly inside the platform — no more switching to WhatsApp or losing conversation history.
Messaging is available on Starter plans and above. Free plan users can enable messaging but are limited to 50 messages per client per month.
Overview
The messaging system has two sides:
| Side | Where | Key capabilities |
|---|---|---|
| Practitioner | Dashboard → Messages | Conversation inbox, full-text search, canned responses, reactions, replies, edit/delete |
| Client | Portal → Messages | Chat interface, GIF picker, emoji reactions, reply-to, suggested chips, push notifications |
Messages are stored permanently as part of the client record. Unlike WhatsApp, you never lose context — the full conversation is always accessible from the dashboard.
Practitioner experience
Messages inbox
The Messages page (/dashboard/messages) shows all client conversations in a split-panel layout:
- Left panel — Conversation list with client avatars, last message preview, timestamps, and unread badges
- Right panel — Selected conversation with full message thread and reply composer
Filtering conversations
Use the filter chips at the top of the conversation list:
| Filter | What it shows |
|---|---|
| All | Every client conversation, sorted by most recent activity |
| Unread | Only conversations with unread messages from clients |
The unread count badge shows how many clients are waiting for a reply.
Searching messages
The search bar supports two modes:
- Conversation search (2+ characters) — Filters the conversation list by client name
- Full-text message search (3+ characters) — Searches across all message content with highlighted matches, timestamp, and client attribution
Full-text search results show:
- Client name and avatar
- Message snippet with the matching term highlighted
- Timestamp (relative: "2h ago", "Yesterday", "Mon", or date)
- Sender indicator ("You:" prefix for practitioner messages)
Click any search result to jump directly to that client's conversation.
Sending messages
From the conversation panel, practitioners can send:
| Type | How |
|---|---|
| Text | Type in the composer and press Enter or click Send |
| GIF | Click the GIF button, search or browse trending, tap to send |
| Emoji | Click the emoji button for quick reactions (👍 💪 🙏 😊 ❤️ 🎉 ✅ 🔥) |
Messages are delivered in real-time. The client receives a push notification (if enabled) and the message appears instantly in their portal chat.
Canned responses (quick replies)
Save frequently-used messages as canned responses for one-tap sending. Perfect for check-ins, motivational messages, and standard replies.
System defaults
MealStack provides built-in canned responses covering common scenarios:
- Motivation — "Great job! Keep up the amazing work 💪", "Proud of you", "Keep going"
- Reminders — "Don't forget to log your meals today", "Water reminder"
- Check-ins — "How are you feeling today?", "Any challenges this week?"
Creating custom responses
- Open the Messages inbox
- Click the Quick Replies button (top-right of conversation list)
- Click Add New and fill in:
- Shortcut — A keyword for slash-command matching (e.g.,
water,great,checkin) - Title — Display name shown in the picker
- Content — The full message text (supports emoji)
- Category — Group responses by type (motivation, reminder, check-in, custom)
- Shortcut — A keyword for slash-command matching (e.g.,
Using canned responses
In the message composer, type / to open the slash-command picker. As you type after the slash, responses are filtered by shortcut and title. Click any response to insert it, then send.
Alternatively, click the Quick Replies icon next to the composer to browse all responses in a categorized list.
Reactions
Hover over any message to reveal the reaction picker — 6 preset emojis (❤️ 👍 😂 😮 😢 🙏) plus a reply button.
- Click an emoji to add your reaction
- Click the same emoji again to remove it
- Reactions appear as small pills below the message bubble
- Both practitioner and client reactions are visible to each other
The reaction style is single-reaction per user per emoji (iMessage-style) — you can react with multiple different emojis, but only one of each type.
Reply-to (quoted replies)
Click the reply button (↩) on any message to quote it in your next message. The quoted preview appears above the composer showing:
- Who sent the original message
- First 80 characters of the content
The recipient sees the quoted block inside your message bubble with a left border accent, making threaded context clear even in long conversations.
Edit and delete messages
Editing
Practitioners can edit their own messages within 15 minutes of sending. After editing:
- The message content updates in-place
- An "edited" label appears next to the timestamp
- The original content is not preserved for the client
Deleting
Practitioners can delete their own messages within 15 minutes of sending. After deletion:
- The message bubble is replaced with "This message was deleted" in italic
- The message is soft-deleted (preserved in the database for audit purposes)
- Reactions and replies referencing the deleted message remain but show the placeholder
Edit and delete windows are enforced server-side. Once 15 minutes have passed, the option disappears from the UI and the API rejects the request.
Rate limiting
To prevent abuse, messaging is rate-limited:
| Limit | Value |
|---|---|
| Messages per minute (practitioner) | 30 |
| Messages per minute (client) | 10 |
| GIFs per minute | 5 |
| Message length | 2,000 characters |
Rate limit errors show a brief toast notification. The limit resets after 60 seconds.
Client experience
Opening the chat
Clients access messaging from:
- The Messages tab in the portal bottom navigation
- The unread messages banner on the portal home screen
- Push notification taps (deep-links to the chat)
Chat interface
The portal chat uses a premium WhatsApp/Telegram-style design:
- Header — Practitioner name, avatar, and real-time availability status (derived from business hours + timezone)
- Messages area — Grouped bubbles with date separators, food-themed background pattern
- Input bar — Emoji button, GIF button, auto-expanding text area, circular send button
Availability status
The header shows the practitioner's current availability based on configured business hours:
| Status | When |
|---|---|
| 🟢 "Typically replies quickly" | During configured business hours |
| ⚪ "Available from 9 AM" | Before business hours open |
| ⚪ "Replies by tomorrow" | After business hours close |
| ⚪ "Replies on Monday" | On a closed day (e.g., Sunday) |
Suggested chips
When the chat is empty (first conversation), clients see tappable quick-start suggestions:
- 👋 Say hello — Auto-fills "Hi! 👋"
- 🔄 Request a change — Auto-fills "I'd like to request a change to my meal plan."
- ❓ Ask a question — Focuses the input (empty)
GIF picker
Tap the GIF button to open an inline picker (Instagram-style, slides up from bottom):
- Trending GIFs load automatically
- Quick search chips — pre-set categories (Agree, Applause, Dance, Good job, High five, Thumbs up, etc.)
- Search — Type to find specific GIFs with debounced search
- Tap to send — Selecting a GIF sends it immediately as a full-width bubble
GIFs are served through a server-side GIPHY proxy (/api/giphy) to keep the API key secure. Attribution ("Powered by GIPHY") is shown per GIPHY ToS.
Emoji reactions
Clients can react to any message:
- Desktop — Hover over a message to reveal the reaction picker
- Mobile — Long-press (500ms) a message to show the picker
- Quick react — Double-tap any message to instantly react with ❤️
The picker shows 6 emojis: ❤️ 👍 😂 😮 😢 🙏
Active reactions (ones the client has already used) are highlighted with a ring. Tapping an active reaction removes it.
Reply-to
From the reaction picker, tap the reply button (↩) to quote a message. A preview bar appears above the input showing:
- Left accent bar in primary color
- "Replying to [name]" label
- Truncated content preview
- X button to cancel
The reply appears in the sent bubble as a quoted block at the top.
Edit and delete (client side)
Clients can edit or delete their own messages within 5 minutes of sending (shorter window than practitioners to prevent abuse).
- Edited messages show an "edited" label
- Deleted messages show "This message was deleted" placeholder
Read receipts
Client messages show delivery status:
| Icon | Meaning |
|---|---|
| ✓ (gray) | Message sent successfully |
| ✓✓ (blue) | Message read by practitioner |
| Spinner | Message is being sent |
| ⚠ "Failed · Tap to retry" | Send failed — tap to retry |
Push notifications
When the practitioner sends a message, the client receives:
- Push notification (if portal is installed as PWA and notifications enabled)
- In-app sound + haptic feedback (if the portal is open but on a different page)
- Toast notification (if the portal is open)
Notifications are visibility-aware — they don't fire when the client is already viewing the messages page.
Optimistic sending
Messages appear instantly in the chat (optimistic UI) before server confirmation:
- Sending state shows a spinner and slightly reduced opacity
- On success, the optimistic message is replaced by the server-confirmed version
- On failure, the message turns red with "Failed · Tap to retry" — tapping re-sends
Rich message types
Swap requests
When a client requests a food swap through the portal's meal plan view, a structured message is auto-sent:
🔄 Swap request: I'd like to replace "Apple Cinnamon Oatmeal" in my breakfast. Reason: Not available locallyThis renders as a rich card in the chat with:
- Swap icon + "SWAP REQUEST" header
- Food name highlighted
- Meal type context
- Optional reason in italics
System messages
Automated system messages appear centered with muted styling:
- "Portal access enabled"
- "New meal plan shared"
- "Goal completed 🎉"
How-to guides
How to set up canned responses
Open the Messages page
Navigate to Dashboard → Messages from the sidebar.
Click Quick Replies
In the top-right corner of the conversation list, click the Quick Replies button.
Create a new response
Click Add New and fill in the shortcut, title, content, and category.
Use in conversations
Type / in the message composer, then start typing the shortcut. Select from the filtered list.
How to search message history
Open Messages
Navigate to Dashboard → Messages.
Type your search
In the search bar, type 3 or more characters. The view switches from conversation list to message search results.
Browse results
Results show the client name, message snippet with highlighted match, and timestamp.
Jump to conversation
Click any result to open that client's conversation panel.
How to configure message notifications (practitioner)
Message notification preferences are managed per-practice in Settings → Client Portal → Push Notification Preferences. Ensure "Message notifications" is toggled on.
How to configure message notifications (client)
Clients manage their notification preferences from the portal user menu → Notification Settings. They can toggle message alerts on/off and set quiet hours.
How to use GIFs (portal)
Tap the GIF button
In the message composer, tap the GIF label next to the emoji button.
Browse or search
The picker opens with trending GIFs. Use the search bar or tap a category chip to find specific GIFs.
Tap to send
Tap any GIF to send it immediately. The picker closes and the GIF appears in the chat as a full-width image bubble.
How to react to a message
Reveal the picker
Desktop: Hover over any message bubble. Mobile: Long-press (hold for ~0.5 seconds).
Select an emoji
Tap one of the 6 emojis (❤️ 👍 😂 😮 😢 🙏). The reaction appears as a pill below the message.
Remove a reaction
Tap your active reaction pill below the message, or open the picker and tap the highlighted emoji again.
Quick react shortcut: Double-tap any message to instantly react with ❤️ — no need to open the picker.
Security & privacy
- All messages are encrypted in transit (TLS)
- GIF searches are proxied through the server — client devices never contact GIPHY directly
- Rate limiting prevents spam and abuse
- Message data is scoped to the organization — no cross-org access
- Soft-deleted messages are retained for audit but hidden from the UI
- HIPAA-friendly: data stays on the platform, not on third-party messaging services
Feature toggle
Messaging can be enabled or disabled per-client from the client's Portal tab → Feature Toggles → Messaging. When disabled, the client sees a locked screen prompting them to contact their dietitian.
The messaging feature toggle is on by default for new clients when portal access is enabled.