Danvas
Danvas
DashboardSupportWelcome

👤 USER DOCS

User Guides

Getting Started

Getting StartedDashboard & OnboardingApp Settings

Tutorials

Tutorial: Setting Up Shift Tasks & ClosersTutorial: Managing Incidents in the InboxTutorial: Tracking Compliance & Sync StatusTutorial: Operational Workflows with the AI AssistantTutorial: Building & Deploying Custom Checklists

Daily Operations (Staff)

Shift Workspace & TasksService Day SetupDaily Line-UpStaff Service Day ReportsForms

Communication & Chat

Messages & AnnouncementsUnified Operations InboxAI Assistant

Manager & Admin Guides

Daily Line-Up SetupStaff SchedulingManaging LocationsNPS and Guest FeedbackCouponsContacts and Guest HistoryManager CloseoutsDaily Line-Up & ComplianceAnalyticsIncident ReportingWhistleblower Concerns & FeedbackAdmin Tools

⚙️ DEVELOPER DOCS

Getting Started

Getting StartedDevelopmentDeployment Guide

Architecture

Architecture OverviewExplanation: AI Integration & Tenant SecurityExplanation: Dynamic Forms Engine DesignExplanation: Compliance Ledger DesignExplanation: Live Sync & Data FreshnessData FlowArchitecture Decision Records

Core Domain

Core DomainDatabase ReferenceLocations DomainAuth & RBACScheduling DomainReports DomainIncidents DomainUnified Operations InboxLive Sync Data FreshnessToast Sync PipelineNotifications DomainCoupons and Guest NPSAudit Log & Compliance ArchitectureDesign Audit FindingsAI Chat IntegrationAnalytics & Tips Integration

Frontend

Frontend ArchitectureFormsLoading SkeletonsComponentsPWA & Offline ShellScreenshots

API Reference

API Reference

Endpoints

POS Sales APIOptimization Data APISchedule Shifts APIEmployee Export APIReports APIIncidents APIAI Chat APIPush Notifications APIWebhooks APICron API

Contributing

ContributingCode Examples

Security

Security & Compliance

Release Notes

What's New

Notifications Domain

Technical architecture of Slack and Web Push integrations

Overview

The notifications domain manages multi-channel alerts and team communication. It leverages @repo/slack for operational summaries and @repo/notifications for browser-level Web Push.

Slack Integration (@repo/slack & apps/slack-bot)

Slack notifications use a consolidated microservice architecture:

  1. Thin Client (@repo/slack): Resolves channel routing configuration from slack_configs but does not perform any Block Kit rendering or direct Slack Web API calls.
  2. Slack Bot (apps/slack-bot): A stateless render-and-dispatch service that validates incoming payloads, renders Block Kit templates, and dispatches messages to Slack via chat.postMessage using the managed workspace bot token and @slack/web-api. Installation-token decryption is historical and is not the current credential authority.

Low-Latency Dispatch Path

For critical alerts (such as incidents or announcements), notifications are written to the notification_queue table and immediately drained using Next.js after() via the triggerNotificationQueueDrain() helper, bypassing cron latency to deliver alerts in under 2 seconds.

Dynamic Routing

Routing config is resolved locally by notification-router.ts in @repo/slack based on:

  1. teamId (Required)
  2. formType (e.g., shift_report, incident, preshift)
  3. locationId (Optional location-specific override)

Once resolved, the client sends a POST request to ${SLACK_BOT_URL}/api/notifications/dispatch containing the target channelId and the raw domain payload.

Template System

All Block Kit templates live in apps/slack-bot/lib/templates/ and include:

  • Shift reports — summary with location, ratings, and hero mention
  • Manager reports — daily operational summary
  • Incidents — severity-tagged alerts with status and escalation tracking
  • Pre-shift briefings — staff goals with roles and POS targets
  • Labor variance alerts — multi-location threshold breaches
  • Schedule summaries — weekly roster overview
  • Anonymous feedback — category-tagged feedback with truncation
  • Coupon/Survey alerts — privacy-safe lifecycle and sentiment notifications; contactable recovery remains gated

All templates enforce Slack's 2900-character section limit and 50-block message limit via truncate() helpers.

Reliability Patterns

  • Retry Logic: Failed dispatch requests are retried using exponential backoff.
  • Queue Fallback: If apps/slack-bot is unavailable or after() fails, a background cron job at /api/notifications processes pending items in the notification_queue.
  • Response Receipts: Bot messages include a Danvas context footer with timestamp for traceability.

Coupon and survey delivery

Guest events are accepted transactionally with the reservation, feedback, or survey mutation, using stable event identities. After commit, the existing notification queue and Slack delivery ledger own retries. A provider failure never reverses a redeemed reservation or an applied survey response.

The canonical worker reloads the durable event and authoritative records before deciding whether delivery is eligible, a lifecycle no-op, or a recovery disposition. Legacy rating hints cannot authorize an alert without its durable feedback/response identity. Routing uses the actual restaurant rather than the campaign's first assignment. Event metadata excludes raw names, email, phone, comments, public/private tokens, cookies, and staff proof.

The approved NPS mode is anonymous-only: sentiment events do not create Contact records or contactable Operations Inbox recovery. Coupon feedback remains a separate 1–5 metric. See Guest NPS and the guest feature contract.

Web Push Notifications (@repo/notifications)

Browser-native notifications used for high-urgency alerts.

  • Subscriptions: Stored in the push_subscriptions table.
  • VAPID Keys: Used for secure delivery to Google/Apple/Mozilla push services.
  • Service Worker: Handled by the Next.js PWA configuration (serwist).

Email Notifications (@repo/email)

Transactional emails delivered via Resend.

  • Templates: Built with React Email for consistent styling and type safety.
  • Provider: @repo/email wraps the Resend SDK with standardized logging and error handling.

PII Safety in Observability

All observability surfaces that could carry customer contact details (emails, phone numbers) are wired through a single redaction primitive at @repo/security/pii:

  • Sentry — scrubSentryEvent runs in beforeSend for the client, server, and edge runtimes. It redacts message, exception values, breadcrumbs, and extra before the event leaves the process.
  • PostHog — captureSecureEvent in @repo/telemetry/server scrubs event properties through scrubPII before the server-side PostHog SDK transmits them. Prefer this helper over calling analytics.capture directly so call sites can't accidentally leak PII.
  • AI chat — The /api/assistant/chat route calls redactPII on user-supplied text before it is forwarded to the model or persisted.

If you need a new pattern matched (e.g. an employee ID format), add it to packages/security/pii.ts — do not re-implement redaction locally.

Related

Database Schema

Reports Domain

Security & Compliance

API Reference

Toast Sync Pipeline

Technical architecture of the Toast POS sync pipeline, sales metrics, and schedule variance

Coupons and Guest NPS

Assignment routing, durable coupon lifecycle, Contact identity, and anonymous NPS

On this page

OverviewSlack Integration (@repo/slack & apps/slack-bot)Low-Latency Dispatch PathDynamic RoutingTemplate SystemReliability PatternsCoupon and survey deliveryWeb Push Notifications (@repo/notifications)Email Notifications (@repo/email)PII Safety in ObservabilityRelated