Skip to content
WeDance architecture

How WeDance is built

The system as it exists in the code today. Everything past this page — data model, API, story map — is generated from the code on every build, so it cannot drift.

At a glance

System context

Who uses WeDance and which outside systems it talks to. Solid lines are runtime calls, dotted lines are client-side telemetry.

Rendering diagram…

Diagram source
flowchart LR
  dancer([Dancer]) --> web
  organiser([Organiser / venue / artist]) --> web
  admin([Admin]) --> web
  subgraph wd[WeDance 2026 on Vercel]
    web[Nuxt app<br/>pages + components] -->|tRPC / REST| api[Nitro server<br/>tRPC routers + API routes]
  end
  api --> db[(Neon Postgres<br/>70 tables)]
  api -->|checkout| stripe[Stripe]
  stripe -->|webhook| api
  tt[TicketTailor] -->|order webhook| api
  api -->|email| resend[Resend]
  api -->|places| google[Google Places]
  api -->|uploads| cloudinary[Cloudinary]
  api -->|reports| linear[Linear]
  sync[[sync-v3-events<br/>daily]] -->|read-only| v3[(wedance.vip<br/>v3 Firestore)]
  sync --> db
  web -.->|analytics| posthog[PostHog]
  web -.->|errors + replay| sentry[Sentry]
  api -.-> sentry

Bounded contexts

The domains the data model splits into today. One Nuxt app and one database hold all of them — the boundaries are conventions in the schema and the router files, not separate services.

Stack

Framework
Nuxt 4 (Vue 3, Vite), SSR on Vercel serverless
API
tRPC 11 at /api/trpc (client-side calls) + a few Nitro REST routes for SSR and webhooks
Data
Drizzle ORM on Neon Postgres; SQL migrations in server/database/migrations
Validation
zod on the server (tRPC inputs), valibot in client forms
UI
Tailwind 4 + shadcn-vue (reka-ui) components, the /docs/design system
Auth
Own email + password (FirebaseScrypt hashes carried over from v4) and magic links; opaque session tokens in `sessions`, sent as a Bearer header
Tests
vitest (unit + router), Playwright + playwright-bdd (e2e, design contract/a11y/visual)

External integrations

Each one verified in the code; the file is where to look first.

ServiceWhat forWhere
Neon PostgresThe one production database, via the Neon HTTP driver + Drizzle ORM.server/utils/db.ts
VercelHosting: Nitro `vercel` preset, auto-deploy from main, preview deploys share the prod DB.nuxt.config.ts
Stripe (test mode)Festival ticket checkout sessions; webhook confirms payment, completes referrals.server/trpc/routers/festivalSignup.ts · server/api/stripe/webhook.post.ts
TicketTailorHMAC-signed order webhook marks verified ticket holders for the attendee roster.server/api/webhooks/tickettailor.post.ts
wedance.vip (v3 Firestore)Read-only mirror of upcoming events and their venue/organiser/artist profiles.scripts/sync-v3-events.ts · server/utils/v3EventSync.ts · server/utils/v3ProfileSync.ts
ResendTransactional email: magic links, password reset, ticket confirmations.server/utils/email.ts
Google PlacesCity search and resolution into the canonical `cities` table.server/utils/cities/google.ts
CloudinaryImage uploads (profile photo in settings).server/api/media/image.post.ts
LinearIn-app problem reports and event inquiries become Linear issues.server/trpc/routers/feedback.ts
PostHogProduct analytics (EU), no-op until a key is set.app/plugins/03.posthog.client.ts
SentryError monitoring + session replay, no-op until a DSN is set.sentry.client.config.ts · sentry.server.config.ts

Explore