Architecture Overview
High-level architecture of the Danvas platform
Overview
Danvas is built as a Turborepo monorepo with deployable Next.js applications and over 20 shared packages. Each business capability is encapsulated in a reusable @repo/* package, and applications compose these packages to build their user interfaces and APIs. Public marketing is hosted outside this monorepo (ADR-0081).
System Architecture
graph TD
App[Main Application apps/app] --> UI[UI Design System]
App --> Auth[Authentication & Security]
App --> DB[Database & Storage]
App --> Notifications[Communication & Notifications]
App --> AI[AI & Analytics]
App --> Idem[Webhook Idempotency]
API[API Backend apps/api] --> DB
API --> Auth
API --> Notifications
API --> Idem
Guest[Guest Portal apps/guest] --> GuestDomain[Coupons and Guest NPS]
GuestDomain --> DB
GuestDomain --> Identity[Contact Identity]
App --> GuestDomain
App --> Identity
API --> GuestDomain
GuestDomain --> NotificationsApplications
| Application | Port | Purpose |
|---|---|---|
Main App (apps/app) | 4000 | Primary operator application — all authenticated workplace features |
Guest Portal (apps/guest) | 3300 | Guest/customer-facing coupon and survey flows |
API Backend (apps/api) | 4002 | API server — scheduled cron jobs, webhooks, integrations |
Documentation (apps/docs) | 4004 | Technical platform documentation site |
Slack Bot (apps/slack-bot) | 4005 | Slack dispatch and interactive alert handlers |
Analytics MCP (apps/analytics-mcp) | 4006 | Machine-facing analytics MCP server |
Storybook (apps/storybook) | 6006 | Isolated component stories development |
Key Packages
| Package | Purpose |
|---|---|
@repo/coupons | Authorized campaign/issuance commands, fulfillment reporting, and coupon timelines |
@repo/guest | Public assignment resolution, coupon reservations, survey submission, and guest events |
@repo/contact-identity | Shared customer resolution, canonical Contact locks, merges, and effective consent |
@repo/database | Drizzle ORM + Neon PostgreSQL — schema, migrations, connection pool |
@repo/auth | Clerk authentication — user provisioning, role-based access control, session management |
@repo/ai | Vercel AI SDK and Vercel AI Gateway — reviewed model routes, chat interface, and inference utilities |
@repo/design-system | UI component library — shadcn/ui primitives, data tables, scheduling UI, Tailwind v4 |
@repo/slack | Slack webhook delivery — DB-backed routing, Block Kit templates, retry logic |
@repo/telemetry | Product telemetry — PostHog, Vercel Analytics, Google Analytics |
@repo/restaurant-analytics | POS/business analytics — labor variance, tip marts, upgrade aggregates |
@repo/optimization | Scheduling optimization — labor metrics, goals, fill rates, efficiency points |
@repo/daypart-readiness | Daypart command console — operational readiness, close reads, briefing checks |
@repo/security | Nosecone security headers, AES-256-GCM encryption, bot detection |
@repo/rate-limit | Sliding window rate limiter — Upstash Redis with in-memory fallback |
@repo/notifications | Shared durable notification queue/workers and Web Push |
@repo/email | Resend transactional email — React Email templates |
@repo/seo | Metadata helpers, sitemap, JSON-LD structured data |
@repo/storage | Vercel Blob — file uploads with HEIC-to-JPEG conversion |
@repo/observability | Sentry error tracking + BetterStack logging |
@repo/idempotency | Durable command outcomes and webhook deduplication |
Data Flow
Authenticated Session
- User signs in via Clerk at
(unauthenticated)/sign-in @repo/auth/serverprovisions the user in the database (or links them to a pending invite)- The authenticated layout wraps all pages with
SidebarProvider+NotificationsProvider - Server Actions and API routes use
getActionContext()for authorization guards (with local RBAC and location scoping per ADR-0018) - Tenant-owned reads and writes enforce the authorized
teamIdand, where applicable,locationId; global, reference, audit, migration, and system-owned tables follow their explicit contracts
Background Jobs
The API app (apps/api) runs operational jobs via Vercel Cron. The deployed entrypoints
and schedules are owned by apps/api/vercel.json; this page intentionally avoids duplicating volatile timing details. Current families include compliance and report reminders, announcement publishing, 7shifts synchronization, coupon expiry, and keep-alive health checks. Certified analytics mart materialization is owned by Dagster, not these API cron handlers.
Coupons, NPS, and customer identity
The operator App owns authorized campaign authoring, immutable publication, issuance recovery, and reports. The Guest portal owns assignment-scoped coupon and survey interactions. Both use shared packages and the database transaction boundary; a public route does not inherit authority from an admin page.
Contact resolution/merge locks precede aggregate association writes. Campaign edit revisions prevent stale publication, and the durable issuance-command fence prevents a lost response from creating another private link. Accepted reservations retain their offer version and absolute server expiry. Reports distinguish guest attestation from verified staff/POS fulfillment; Danvas does not modify Toast checks. Anonymous NPS creates no Contact or contactable recovery case.
Domain events commit with accepted mutations. The shared notification worker reloads authoritative records and delivers through existing queue/Slack ledgers. Provider delivery and cron scheduling do not own coupon capacity or survey completion. See Coupons and Guest NPS for routing, privacy, recovery, and the separate rollout/pilot gates.
Restaurant Analytics Data Flow
Operational analytics (tips, labor, sales, upgrades) are Neon-native. Source and fact tables land in Neon; Dagster owns certified analytics mart materialization, while apps/api cron jobs handle operational orchestration and notifications. Intelligence → Analytics pages read the resulting tables via server actions.
graph LR
subgraph Danvas["Danvas"]
APP[apps/app<br/>Intelligence → Analytics]
API[apps/api<br/>operational crons]
DAG[Dagster<br/>certified materializations]
end
subgraph Neon["Neon PostgreSQL"]
FCT[public fact tables]
MART[analytics marts]
end
subgraph POS["Toast / 7shifts"]
TOAST[POS + labor sync]
end
TOAST --> FCT
DAG --> MART
FCT --> APP
MART --> APP
FCT --> APIKey jobs: Dagster daily_certified_metrics_job owns daily/hourly tip and Upgrade
partitions; completed_week_metrics_job owns completed-week outputs. Historical
replay is an approval-bound Dagster partition repair.
The @repo/telemetry package is product telemetry (PostHog, Vercel Analytics) and is not the tip dashboard read path. See Analytics & Tips Integration.
Tech Stack Summary
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Monorepo | Turborepo v2 + Bun |
| Database | Neon PostgreSQL + Drizzle ORM |
| Auth | Clerk authentication + local team/location authorization |
| AI | Vercel AI Gateway → reviewed model routes |
| UI | shadcn/ui + Tailwind v4 |
| State | TanStack Query + Zustand + nuqs |
| Resend + React Email | |
| Storage | Vercel Blob |
| Analytics | PostHog + Vercel Analytics + Google Analytics |
| Monitoring | Sentry + BetterStack |
| Push | Web Push API + Slack |
| Deploy | Vercel |