Back to Projects

MeetWise

Next.jsTypeScriptReacttRPCDrizzle ORMPostgreSQLStream Video SDKStream Chat SDKOpenAIInngestBetter AuthPolarTailwind CSSTanStack QueryRadix UIZod
IMAGE — Dashboard home page with sidebar navigation showing Agents and Meetings sections
IMAGE — Agent list page with search bar and paginated agent cards
IMAGE — Agent creation form with name input, instructions textarea, and DiceBear robot avatar preview
IMAGE — Agent detail page showing meeting count and edit/delete actions
IMAGE — Meeting list page with status filters (Upcoming, Active, Completed, Processing, Cancelled)
IMAGE — New meeting form with name input and agent selector dropdown
IMAGE — Video call screen (Stream Video UI) with user and AI agent as participants
IMAGE — Active meeting showing live transcription and closed captions
IMAGE — Completed meeting detail page with AI-generated summary
IMAGE — Meeting transcript view with speaker avatars (user initials + robot avatar for agent)
IMAGE — Post-meeting Q&A chat powered by Stream Chat with AI responses
IMAGE — Upgrade/Premium page showing subscription plans via Polar
IMAGE — Sign-in page with email/password and Google OAuth options (Better Auth)
VIDEO
VIDEO
VIDEO
VIDEO
VIDEO
VIDEO
VIDEO
VIDEO
VIDEO
Dashboard Home1 / 22

Overview

An AI-powered meeting platform where users create custom AI agents with unique instructions, start video calls with those agents as real-time participants, and receive auto-generated transcripts and summaries after each meeting. Built with Next.js 15, React 19, tRPC, Stream Video & Chat SDKs, OpenAI Realtime API, Inngest background jobs, and Drizzle ORM with PostgreSQL.

Key Features

AI & Agents
  • Create custom AI agents with unique names and system instructions — each agent gets a DiceBear robot avatar auto-generated from its name
  • Start video meetings with AI agents that join as real-time participants using OpenAI Realtime API via Stream Video SDK
  • Automatic transcription and recording enabled on every call with 1080p quality and closed captions
  • Post-meeting AI processing via Inngest background job — fetches JSONL transcript, resolves speaker identities, and generates GPT-4o summary
  • View full meeting transcript with speaker identification — user avatars (initials) and agent avatars (robot) displayed inline
  • Post-meeting Q&A via Stream Chat — ask questions about the meeting and get AI-powered answers with context from the transcript
  • Meeting status lifecycle management: upcoming → active → processing → completed/cancelled with real-time status tracking
  • Premium subscription system via Polar with free tier usage limits on number of agents and meetings
  • Paginated agent and meeting lists with search filtering using case-insensitive ilike queries via Drizzle ORM
  • Authentication with Better Auth supporting email/password credentials, Google OAuth, and GitHub OAuth with session management
  • Stream Video call creation with auto-configured transcription (auto-on) and recording (auto-on, 1080p) settings
Video & Communication
  • Meeting duration calculation using PostgreSQL EXTRACT(EPOCH) for precise time tracking
Data & Infrastructure
  • Type-safe API layer using tRPC with protected and premium-gated procedures for authorization
Auth & Payments
  • Dashboard layout with collapsible sidebar navigation, responsive design, and light/dark mode toggle

Architecture Overview

How the system is structured from frontend to external services.

01

Frontend

Next.js 15 (App Router)React 19Tailwind CSSRadix UI / ShadcnTanStack React Query

Server Components for layout and data fetching, Client Components for interactive meeting UI, agent forms, and chat. TanStack React Query manages server state with tRPC integration. Responsive dashboard with collapsible sidebar and light/dark mode via next-themes.

02

Backend & API

tRPCDrizzle ORMBetter AuthZod

Type-safe RPC layer with tRPC — protected procedures enforce authentication, premium procedures gate resource creation behind Polar subscription checks. Drizzle ORM provides type-safe SQL queries with PostgreSQL. Better Auth handles credentials + Google OAuth with session-based auth.

03

Database

PostgreSQLDrizzle ORM

Six tables: users, sessions, accounts, verifications, agents, and meetings. Meeting status tracked via a PostgreSQL enum (upcoming, active, completed, processing, cancelled). Cascade deletes ensure cleanup when users or agents are removed. Duration computed via EXTRACT(EPOCH) on timestamp columns.

04

External Services

Stream Video SDKStream Chat SDKOpenAI Realtime APIInngestPolar

Stream Video handles WebRTC video calls with auto-transcription and 1080p recording. OpenAI Realtime API powers AI agent participation in live calls. Inngest runs background jobs for post-meeting transcript processing and GPT-4o summarization. Stream Chat enables post-meeting Q&A. Polar manages subscription billing with free tier limits.

Data Model

Core entities and how they relate to each other.

User

Has many Sessions, Accounts (cascade delete). Has many Agents and Meetings (cascade delete)

Central user account — supports email/password credentials and Google OAuth via Better Auth

id (text, PK)nameemail (unique)emailVerified (boolean)imagecreatedAtupdatedAt

Session

Belongs to User (cascade delete on user removal)

Active user sessions with unique tokens, expiry, and device tracking (IP address, user agent)

id (text, PK)token (unique)expiresAtipAddressuserAgentuserIdcreatedAtupdatedAt

Account

Belongs to User (cascade delete on user removal)

OAuth provider links — stores provider IDs, access/refresh/ID tokens, and token expiry for each connected provider

id (text, PK)accountIdproviderIdaccessTokenrefreshTokenidTokenaccessTokenExpiresAtscopepassworduserIdcreatedAtupdatedAt

Verification

Standalone — referenced by Better Auth internally

Email verification tokens with identifier and expiry — used by Better Auth for email confirmation flows

id (text, PK)identifiervalueexpiresAtcreatedAtupdatedAt

Agent

Belongs to User (cascade delete). Has many Meetings (cascade delete). Meeting count computed via db.$count subquery

Custom AI agent created by a user — stores name and system instructions that define the agent's personality during calls

id (nanoid, PK)nameinstructions (text)userIdcreatedAtupdatedAt

Meeting

Belongs to User (cascade delete) and Agent (cascade delete). Duration computed as EXTRACT(EPOCH FROM ended_at - started_at)

Video meeting record — tracks lifecycle status, links to agent, stores transcript URL, recording URL, and AI-generated summary after processing

id (nanoid, PK)namestatus (enum: upcoming|active|completed|processing|cancelled)startedAtendedAttranscriptUrlrecordingUrlsummaryuserIdagentId

Key Flows

Step-by-step walkthrough of the main user and system flows.

Meeting Creation & Video Call

  1. 1User creates a meeting by selecting a name and choosing an AI agent
  2. 2tRPC premium procedure checks Polar subscription (or free tier limits) before allowing creation
  3. 3Backend creates a Stream Video call with auto-transcription (language: en, mode: auto-on) and recording (1080p, auto-on)
  4. 4Agent is upserted as a Stream Video user with a DiceBear robot avatar
  5. 5User clicks 'Start Meeting' — frontend generates a Stream Video token via tRPC and joins the call
  6. 6AI agent connects to the call using OpenAI Realtime API, participating as a live conversational partner
  7. 7During the call, Stream Video handles transcription, closed captions, and 1080p recording automatically

Post-Meeting Processing (Inngest)

  1. 1When the meeting ends, a webhook triggers an Inngest event with the meeting ID and transcript URL
  2. 2Inngest function 'meetings/processing' starts — meeting status set to 'processing'
  3. 3Step 1: Fetches the raw JSONL transcript from Stream Video's CDN
  4. 4Step 2: Parses JSONL into structured transcript items with speaker IDs and timestamps
  5. 5Step 3: Resolves speaker identities by querying users and agents tables, maps names and avatars
  6. 6Step 4: GPT-4o summarizer agent (Inngest Agent Kit) generates a structured meeting summary
  7. 7Step 5: Summary is saved to the meetings table and status is updated to 'completed'

Post-Meeting Q&A (Stream Chat)

  1. 1User opens a completed meeting and navigates to the Q&A section
  2. 2Frontend generates a Stream Chat token via tRPC and connects to a chat channel for the meeting
  3. 3User types a question about the meeting (e.g., 'What were the key action items?')
  4. 4AI retrieves the meeting transcript and summary as context
  5. 5GPT-4o generates an answer based on the actual meeting content
  6. 6Response is streamed back through Stream Chat and displayed in the conversation UI

Challenges I Solved

01

AI Agent as a Real-Time Call Participant

The Problem

AI agents need to join video calls as live participants, listen to user speech, and respond conversationally in real time — not just generate text responses asynchronously.

How I Solved It

Integrated OpenAI Realtime API with Stream Video SDK. The agent is upserted as a Stream Video user with a DiceBear avatar, joins the call, and uses the OpenAI Realtime API for bidirectional audio streaming. The agent's system instructions (defined by the user) control its conversational behavior.

02

Background Transcript Processing with Speaker Resolution

The Problem

Raw transcripts from Stream Video contain speaker_id references, not human-readable names. Processing must happen asynchronously after the call ends without blocking the user.

How I Solved It

Inngest handles the entire pipeline as a multi-step background function: fetch JSONL transcript, parse it, query both users and agents tables to resolve speaker IDs to names and avatars, then feed the enriched transcript to GPT-4o for summarization. Each step is independently retryable.

03

Premium Gating with Polar Subscriptions

The Problem

Free tier users should be limited on how many agents and meetings they can create, while premium users get unlimited access. This needs to be enforced at the API level, not just the UI.

How I Solved It

Created a custom premiumProcedure in tRPC that checks the user's Polar subscription state. For free users, it counts existing resources (agents or meetings) via Drizzle and blocks creation when limits are exceeded. If the user is a paying subscriber, the check is skipped entirely.

04

Type-Safe End-to-End with tRPC + Drizzle

The Problem

Traditional REST APIs require manual type definitions for request/response shapes, leading to type mismatches between frontend and backend as the app evolves.

How I Solved It

tRPC provides full type inference from server procedures to client hooks — input schemas are validated with Zod, and return types flow automatically to TanStack React Query. Drizzle ORM adds type safety at the database layer with schema-derived types, so the entire stack from DB to UI is type-checked.

Summary

MeetWise demonstrates expertise in AI-integrated real-time applications, combining OpenAI Realtime API for live agent participation, Stream Video/Chat SDKs for WebRTC conferencing and messaging, and Inngest for reliable background processing. The project showcases a modern full-stack architecture with tRPC for type-safe APIs, Drizzle ORM for type-safe database operations, Better Auth for flexible authentication, and Polar for subscription management — all built on Next.js 15 with React 19.