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

Forms

Build and submit dynamic forms per location

Danvas forms provide a flexible system for building custom data collection workflows per location. Forms are defined with a JSON schema and rendered dynamically at runtime.

Overview

Admins build forms using a visual form builder. Each form has a name, description, and array of field definitions. Staff then fill out forms on any device — submissions trigger Slack notifications and update compliance tracking.

Field Types

Danvas supports 8 field types:

TypeDescriptionValidation
textSingle-line text inputMax 500 chars
textareaMulti-line text inputMax 5000 chars
numberNumeric inputRange validation available
emailEmail addressEmail format check
selectSingle dropdownOptions defined in form
multiselectMultiple choice checkboxesAt least 1 required
dateDate pickerISO date format
checkboxBoolean toggleReturns true/false

Form Schema

Forms are stored as JSONB with this structure:

Frontend Architecture

Technical design of the Next.js App Router and design system

Loading Skeletons

Architecture pattern for loading states and skeleton components

On this page

OverviewField TypesForm SchemaDynamic RenderingDraft AutosaveMedia UploadsCSV ExportSubmission FlowSlack NotificationsSeeded Form ExamplesConfigurationEnvironment VariablesForm Builder PermissionsRelated Files
interface FormField {
  id: string;
  type: FieldType;
  label: string;
  placeholder?: string;
  required: boolean;
  options?: FormFieldOption[];  // For select/multiselect
  validation?: {
    min?: number;
    max?: number;
    pattern?: string;











Dynamic Rendering

Forms are rendered dynamically using:

  • React Hook Form — Form state management
  • Zod — Schema validation generated from field definitions
  • Server Actions — Form submission handling

The renderer maps each field type to its appropriate input component, applies validation rules, and handles submission to the server.

Draft Autosave

Forms support automatic draft saving to prevent data loss:

  • Drafts are saved to localStorage as users type (throttled to once per 30 seconds)
  • If the page is accidentally closed, the draft is restored on next visit
  • Drafts are keyed by form ID + user ID for multi-form support
  • Clearing a submitted form removes the draft

Media Uploads

Forms with image fields use Vercel Blob for storage:

  1. User selects an image file (JPEG, PNG, or HEIC from iOS)
  2. Client-side HEIC-to-JPEG conversion is applied automatically
  3. File is uploaded directly to Vercel Blob via signed URL
  4. The returned URL is stored in the form submission data
  5. Images are displayed inline in submission views and Slack notifications

CSV Export

Form submissions can be exported as CSV from the admin submissions view, making it easy to analyze collected data in spreadsheet tools.

Submission Flow

  1. User fills out form fields in the browser
  2. Client-side validation via Zod schema (generated from form JSON)
  3. Server action submitForm() receives validated data
  4. Data stored in form_submissions table with timestamp
  5. Slack notification sent to configured channels (if locationId provided)
  6. Compliance row updated if form is a shift/manager report

Slack Notifications

When a form is submitted, a Slack message is sent using Block Kit formatting:

// packages/slack/templates/dynamic-form.ts
function buildDynamicFormBlocks(form: Form, submission: FormSubmission) {
  return [
    { type: "header", text: { type: "plain_text", text: form.name } },
    { type: "section", fields: [...


Configure webhook URLs in environment:

SLACK_WEBHOOK_REPORTS=https://hooks.slack.com/services/...

Seeded Form Examples

The database seed includes these demo forms:

FormPurposeFields
Opening ChecklistPre-shift verificationtextarea, select (ratings), checkbox, number (temp)
Incident ReportSafety/event reportingtext, date, select (severity), textarea
Shift LogEnd-of-shift notesVarious text and number fields

Configuration

Environment Variables

VariablePurpose
DATABASE_URLNeon PostgreSQL connection
SLACK_WEBHOOK_*Webhook URLs for notifications

Form Builder Permissions

Only admins can create/edit forms. Form submission is available to all authenticated users.

Related Files

FilePurpose
apps/app/app/(authenticated)/admin/forms/form-builder.tsxAdmin form builder UI
apps/app/app/(authenticated)/admin/forms/actions.tsForm CRUD server actions
apps/app/app/(authenticated)/forms/[formId]/form-submission-client.tsxDynamic form renderer
apps/app/app/(authenticated)/forms/actions.tsSubmit form server action
packages/database/src/form-types.tsCore type definitions
packages/database/src/schema/forms and form_submissions tables
packages/slack/templates/dynamic-form.tsSlack message builder
};
}
interface Form {
id: string;
name: string;
description: string;
fields: FormField[];
isActive: boolean;
createdAt: Date;
updatedAt: Date;
}
] },
{ type: "context", elements: [...] }
];
}