DashboardSupportWelcome

👤 USER DOCS

Getting Started

Daily Operations

Shift Workspace & TasksPre-Shift SetupLine-Up CardsShift ReportsForms

Staff & Locations

Staff SchedulingManaging Locations

Oversight

Manager ReportsAnalyticsPre-Shift & Compliance

Incidents & Feedback

Incident ReportingAnonymous FeedbackMessages & Announcements

AI & Settings

AI ChatgearApp Settings

Administration

Dashboard & OnboardingAdmin

⚙️ DEVELOPER DOCS

Getting Started

Getting StartedDevelopmentDeployment Guide

Architecture

Architecture OverviewData FlowArchitecture Decision Records

Core Domain

Core DomainDatabase ReferenceLocations DomainAuth & RBACScheduling DomainReports DomainIncidents DomainNotifications DomainAudit Log & OptimizationDesign Audit Findings

Frontend

Frontend ArchitectureFormsLoading SkeletonsComponentsPWA & NotificationsimageScreenshots

API Reference

API Reference

Endpoints

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

Contributing

ContributingcodeCode Examples

Security

Security & Compliance
Danvas IconDanvas
Danvas IconDanvas

AI Chat

Ask plain-English questions about your operational data

Danvas AI Chat provides a conversational interface powered by OpenRouter + DeepSeek Chat. The AI has real-time access to your form definitions, submissions, and location data through tool-calling.

Overview

The chat interface lets you query operational data using natural language. Ask questions like "What was submitted today?" or "Show me incident reports from last week" and get instant answers from your database.

Available Tools

The AI agent has access to four tools that query your organizational data:

get_locations

Returns all restaurant locations for your organization.

{
  "type": "function",
  "name": "get_locations",
  "description": "Get all restaurant locations for the organization"

Messages & Announcements

Internal team messaging with board announcements, categories, scheduling, and staff messaging

App Settings

User settings and notification preferences in Danvas

On this page

OverviewAvailable Toolsget_locationsget_formsget_submissionssubmit_formTool ContractsSuccess ResponseError ResponseLocation ScopingRate LimitsChat Interface TypesDirect AI ChatMatrix Room ChatMessage PersistenceConfigurationRelated Files
}

Returns: Array of locations with id, name, address, timezone

get_forms

Returns active forms, optionally filtered by location.

{
  "type": "function",
  "name": "get_forms",
  "parameters": {
    "type": "object",
    "properties": {
      "locationId": {
        "type": "string",
        "description": "Filter forms by location ID (optional)"
      }
    }
  }
}

Returns: Array of forms with id, name, description, fieldCount, isActive

get_submissions

Queries form submissions with optional filters.

{
  "type": "function",
  "name": "get_submissions",
  "parameters": {
    "type": "object",
    "properties": {
      "formId": {
        "type": "string",
        "description": "Filter by form ID (optional)"
      },
      "locationId": {
        "type": "string"












Returns: Array of submissions with id, formId, formName, locationName, submittedBy, submittedAt, data

submit_form

Submits form data on behalf of the authenticated user.

{
  "type": "function",
  "name": "submit_form",
  "parameters": {
    "type": "object",
    "properties": {
      "formId": {
        "type": "string",
        "description": "The form ID to submit to"
      },
      "locationId": {
        "type": "string"









Returns: { success: true, submissionId: string }

Tool Contracts

Every tool follows a consistent contract pattern:

Success Response

Tools return data directly. The AI describes the results in natural language.

{ "id": "123", "name": "Downtown Location" }

Error Response

Errors are returned as data (not thrown), so the AI can explain them to you:

Error CodeMeaningExample Message
NOT_FOUNDEntity doesn't exist"I couldn't find that location/form."
FORBIDDENCross-team access"You don't have access to that data."
INVALID_INPUTValidation failure"That doesn't look right — can you check the details?"
RATE_LIMITEDToo many requests"Let's take a quick break before the next request."

Location Scoping

All data access is automatically scoped to your organization (team). You can only see data for locations you have access to.

Rate Limits

The chat endpoint is rate-limited to 20 requests per minute per user. If you exceed this limit, you'll receive a 429 response and should wait before retrying.

Chat Interface Types

Danvas has two distinct chat experiences:

Direct AI Chat

Uses the Vercel AI SDK useChat hook. Messages are sent to /api/chat with optional threadId for conversation continuity. AI tool calls are executed server-side and results are returned to the conversation.

Matrix Room Chat

Real-time messaging powered by the Matrix protocol. Rooms support channels and direct messages. The Matrix client stores data in IndexedDB and syncs in real-time.

Future: AI bot responding to mentions in Matrix rooms.

Message Persistence

Chat threads are stored in the database with the following schema:

FieldTypeDescription
idUUIDThread identifier
teamIdstringOrganization scope
createdAttimestampCreation time
updatedAttimestampLast activity

Messages within threads store role (user or assistant), content, and AI tool call metadata.

Configuration

The AI model is configured in packages/ai/lib/models.ts:

export const models = {
  chat: openrouter("deepseek/deepseek-chat-v3"),
}

Environment variables required:

  • OPENROUTER_API_KEY — API key for OpenRouter access

Related Files

FilePurpose
apps/app/app/api/chat/route.tsChat API endpoint with tool definitions
apps/app/app/(authenticated)/chat/chat-interface.tsxDirect AI chat UI
apps/app/app/(authenticated)/chat/components/chat-view.tsxMatrix-based room chat
packages/ai/lib/models.tsModel configuration
packages/database/src/schema/chatThreads and chatMessages tables
,
"description": "Filter by location ID (optional)"
},
"startDate": {
"type": "string",
"description": "ISO date string for range start (optional)"
},
"endDate": {
"type": "string",
"description": "ISO date string for range end (optional)"
}
}
}
}
,
"description": "The location ID for the submission"
},
"data": {
"type": "object",
"description": "Key-value pairs matching the form's field definitions"
}
},
"required": ["formId", "locationId", "data"]
}
}