System Overview
Tap is a three-tier application with a React frontend, Express backend, and Supabase PostgreSQL database. It integrates with Claude AI for intelligent conversation management, Resend for email delivery, and Slack/Microsoft Teams for multi-channel campaign distribution.
How the Services Connect
The frontend communicates exclusively with the backend API. The backend orchestrates all external services -- it calls Claude AI for conversation intelligence, Supabase for data storage and authentication, Resend for email delivery, and Slack/Teams APIs for multi-channel campaign distribution. No external service is called directly from the frontend (except Supabase Auth for login).
Color key: Purple = Frontend/Vercel, Orange = Backend/Render, Green = Database/Supabase, Pink = AI/Anthropic, Blue = Communications (Email/Slack/Teams)
Data Flow: What Happens When a Message is Sent
This diagram shows the path of a single participant message through the system.
The participant submits a message in the chat interface. The frontend sends it to the backend API. The backend stores the message in Supabase, then sends the full conversation history to Claude AI. Claude decides whether to ask a follow-up question or end the conversation. The backend stores Claude's response and returns it to the frontend, where it appears in the chat.
Key Architecture Patterns
| Pattern | How It's Used |
|---|---|
| MVC-ish | Routes -> Controllers -> Services (backend) |
| Token-based access | Participants use unique tokens, no authentication required |
| JWT auth | Campaign creators authenticate via Supabase JWT |
| Row-Level Security | Supabase RLS policies isolate multi-tenant data |
| Cron jobs | Hourly reminder checks via node-cron |
| Background jobs | Invitation sending (Slack/Teams) and stuck job recovery run asynchronously |
| Admin client | Backend uses Supabase service role key to bypass RLS when needed |
| Multi-channel delivery | Campaigns can target email, Slack, or Teams via delivery_channel |
| Version tracking | Backend exposes version, git commit, and build time via version.js |