Messages & Announcements
Board announcements and staff message routing
Danvas has two distinct communication features that share the "Messages" name in the sidebar: Board (/board) for company-wide announcements, and routed messages reviewed in the Operations Inbox (/inbox). Message creation and detail remain available through /messages/new and /messages/[id]; the legacy /messages list path redirects to the Inbox. They're different products with different audiences and lifecycles.
Canonical source: Message Management feature contract. This page describes the user workflow; the contract owns the detailed state, authorization, and notification behavior.
Board Announcements
The Board is a company-wide feed. Admins and managers post; everyone in scope reads and acknowledges. Announcements support categories, scheduled publication, markdown, media attachments, and read receipts.
Creating an Announcement
- Navigate to Board in the sidebar.
- Click New Announcement (admin/manager only).
- Fill in the dialog:
- Title — up to 200 characters.
- Body — markdown editor (bold, lists, links, code).
- Category — General, Policy, Shift, Incident, or Emergency. Emergency is visually destructive and triggers the highest notification priority.
- Location — pick a single location, or leave as All locations to broadcast across the team.
- Schedule (optional) — pick a future date/time. Scheduled announcements appear in the Scheduled section at the top of the page (visible only to admins/managers) and auto-publish via a Vercel cron route.
- Attachments — up to 4 media URLs (images and short video). The shared uploader auto-converts HEIC photos to JPEG.
- Click Post Announcement (or Post Emergency if the category is Emergency).
The button label changes to Post Emergency for the emergency category so you don't accidentally fire a high-priority notification.
Categories
| Category | Badge | Use case |
|---|---|---|
general | Primary blue | Routine updates, team news |
policy | Primary blue | Policy changes, procedures |
shift | Success green | Schedule changes, shift notes |
incident | Ember orange | Safety incidents, follow-up context |
emergency | Destructive red | Urgent safety, immediate action |
Categories are filterable from the filter bar above the list. Click any category chip to scope the feed.
Reading & Acknowledging
- The ReadTracker component uses an
IntersectionObserver— when an announcement card is 50% visible for 1 second, it marks the announcement as read for your account. The read receipt also captures your response (if any). - Each card has Acknowledge and Ask a question buttons:
- Acknowledge — confirms you've seen it. Optional comment (up to 500 chars).
- Ask a question — posts the question to the announcement thread; admins/managers see it in the read summary.
- Admins and managers see a collapsible read-status list per announcement, with per-user checkmarks and any responses.
Editing & Archival
- Edit — title, body, location, attachments, and category are editable after publication. An
Edited [date]indicator appears below the creator line. Editing does not reset read receipts. - Pin — pinned announcements stay at the top of the feed. Toggle pin from the card menu (admin/manager only).
- Auto-archive — non-pinned announcements automatically archive 14 days after publication. Admins/managers can toggle Show Archived to view the archive.
Notifications
When an announcement publishes, two fan-outs happen (all async, via the notification queue):
- Web Push — sends a browser push to subscribed staff devices.
- Slack — posts to the location's configured Slack channel (or all location channels for global announcements).
Emergency-category announcements use the highest-priority notification channel and bypass quiet hours. The markdown body is what fans out — no truncation, so keep it tight.
Staff Messages
The Messages module is for routed guest messages and manager notes — anything that needs an owner, an audit trail, and a clear handoff. Typical use: a guest calls asking for the manager, a host takes a message in person, a manager-to-manager note that needs acknowledgement.
Creating a Message
- Open the Operations Inbox in the sidebar.
- Choose New Message (the creation route is
/messages/new). - Fill in the form:
- Type — Phone Message, In-Person, or Message for Manager. Determines the default contact mode and the card label downstream.
- Audience — Management (default) routes the message to admins/managers at the location; Individual routes it to a specific staff member.
- Recipient — required when audience is Individual. Lists active team members at the location.
- Contact — attach an existing contact from the directory, capture a one-off guest (name + phone/email/notes), create a new contact, or mark the contact as Unavailable (valid only for
phone_message). - Subject (1–200 chars) and Message (1–5000 chars).
- Urgency —
low,normal,high, orurgent. Drives the badge color and notification priority; it does not suppress the required Slack event. - Media — optional attachments. Same HEIC auto-conversion as everywhere else.
- Click Send Message.
The form autosaves drafts to the device (key draft-message-${locationId}); a recovery banner restores unfinished work on the next visit.
Workflow
Messages have two parallel fields, both of which move through states:
- State (
new→in_progress→archived) — the working state. New messages move toin_progresswhen an owner is assigned or a workflow transition is made. Archiving is final unless explicitly unarchived. - Response Status (
pending→investigating→responded|no_response_needed) — tracks whether the message has been actioned.respondedandno_response_neededboth require notes.
| From state | Allowed workflow transitions | Notes required? |
|---|---|---|
new | pending → investigating | No |
investigating | → responded | Yes |
investigating | → no_response_needed | Yes |
| any | → archived (toggle) | No |
When a management message is assigned an owner, the state auto-advances from new to in_progress.
Ownership & Routing
Anyone with management access at the location can claim a management-audience message. individual-audience messages route to the named recipient. The owner is displayed on the detail card and any workflow transition is recorded in the audit log.
Linked incidents — when a message escalates into a real safety or operational issue, you can convert it into an incident from the message detail page. The link is preserved both ways: the message detail shows the linked incident, and the incident detail shows the source message.
Notifications
When a message is created, the notification policy resolves the named recipient or management audience:
- A best-effort Web Push attempt is made for active subscriptions.
- The Operations Inbox reflects the message and its unread state.
A Slack notification is accepted for the message.created event for every urgency; Web Push is best effort according to the notification policy. Escalating a message into an incident adds the incident notification workflow.
Database Reference
| Table | Used by | Notes |
|---|---|---|
announcements | Board | Title, body, category, location, schedule, creator, edits, pins |
announcement_reads | Board | One row per (announcement, user); tracks read time and response text |
messages | Messages | Subject, body, urgency, priority, audience, state, response status |
message_reads | Messages | One row per (message, user); tracks read time |
message_incident_links | Both | The bridge between a message and any incident created from it |
incident_comments | Both (via Incidents) | Free-form comments on incidents |