"Where Networks Fail, PulseMeet Lives"
PulseMeet is a production-ready, low-network resilient video conferencing and AI meeting intelligence platform designed, architected, engineered, and deployed by A. Sri Sai Charan. Built with Next.js 16 (App Router), React 19, LiveKit WebRTC, Supabase Auth & Database, and Google Gemini 2.5 Flash AI, PulseMeet is engineered specifically to ensure continuous meeting survival during poor internet conditions β dynamically adapting from video streams to low-bandwidth adaptive video and automatic audio-priority mode, capturing real-time closed captions, buffering network outage gaps, and generating automated post-meeting AI reports (summaries, action items, meeting insights, and PDF export).
π Production Deployment: https://pulsemeet.vercel.app
Log in with Google OAuth to create meeting rooms, join active video calls, view live closed captions, and generate AI meeting reports.
- π₯ Real-time WebRTC video conferencing powered by LiveKit
- π€ AI-powered meeting summaries, action items, and insights using Google Gemini
- π¬ Live subtitles with browser-based speech recognition
- π Designed for resilient meeting experiences under unstable network conditions
- π Secure Google OAuth authentication with Supabase
- π Automatic transcript generation and PDF meeting reports
- π± Fully responsive modern UI built with Next.js and Tailwind CSS
Most modern video conferencing platforms perform well on fast broadband connections, but quickly degrade or disconnect when internet stability fluctuates. In low-bandwidth or spotty mobile network environments, users frequently experience lost audio/video context, missed commitments, and total call dropouts.
PulseMeet was built to address these core challenges:
- Uninterrupted Communication: Prioritizes audio continuity over heavy video streams when bandwidth deteriorates, guaranteeing meetings stay alive on 2G/3G connections.
- Context Recovery: Automatically tracks network disconnect intervals and generates an AI Recovery Summary detailing missed discussion points as soon as a participant reconnects.
- Automated Post-Meeting Intelligence: Synthesizes raw speech transcripts into executive summaries, owner-assigned action items, and structured insights using Google Gemini AI, backed by zero-downtime local fallback processing engines.
| Dimension | Details |
|---|---|
| Languages | TypeScript, React, Next.js, SQL |
| Architecture | Next.js App Router, LiveKit WebRTC, Supabase, Google Gemini AI |
| Development | Production Ready, Responsive Design, Secure Authentication, AI Meeting Intelligence |
| Repository | https://github.com/cherry-git999/PulseMeet |
- π Live Demo
- β Highlights
- π― Project Motivation
- π Repository Overview
- β¨ Core Features
- π System Architecture
- β‘ Performance & Optimization
- π Low-Network Experience & Resilience
- π Security & Data Protection
- π Database Schema & Entity Relationship
- π API Route Reference
- π§© Component Architecture
- π Technology Stack
- π Installation & Setup
- π Environment Variables
- π Folder Structure
- π End-to-End User Flow
- π§ Troubleshooting
- πΊ Product Roadmap
- π€ Contributing
- π License
- π Acknowledgements
- π¨βπ» Author
PulseMeet combines real-time WebRTC communications with client-side speech recognition and server-side generative AI to deliver a complete meeting lifecycle management solution. Designed, built, and tested as a portfolio-grade full-stack engineering project by A. Sri Sai Charan, PulseMeet demonstrates modern WebRTC architecture and AI integration.
Unlike conventional conferencing apps that freeze or drop calls during network instability, PulseMeet's primary engineering objective is low-network survival:
- Adaptive Quality Control: Dynamically scales down WebRTC bitrates based on connection telemetry.
- Audio Priority Fallback: When connection reaches critical thresholds (2G / slow 3G), video publication is automatically paused to guarantee uninterrupted audio continuity.
- AI Outage Recovery: Outages during meetings are automatically tracked and summarized upon reconnection via the
RecoverySummaryModalso participants never lose context.
- Google OAuth 2.0 via Supabase Auth: Secure single-click authentication using standard OAuth redirection flows.
- Automatic Profile Provisioning: Extracts Google user metadata (
full_name,email,avatar_url) and stores it in a dedicatedprofilestable. - Profile Completion & Editing: Page (
/complete-profile) enabling users to customize display names and avatar fallbacks (viaui-avatars.com).
- LiveKit WebRTC Infrastructure: Ultra-low-latency video/audio streaming utilizing LiveKit server tokens and SDK client connection management.
- Dynamic Token Server: Secure backend endpoint (
/api/livekit-token) issuing short-lived JWTs scoped to specific room channels. - Dynamic Video Grid Layout: Responsive grid renderer adapting seamlessly to 1 to multi-participant streams with speaker highlighting.
- Media Controls: Independent microphone toggle, camera toggle, screen sharing, raise hand status indicator, and live closed-caption overlay.
- Local Media Preview: Instant pre-join camera and mic hardware verification.
- Adaptive WebRTC Streams: Dynamic stream adaptation (
dynacast,adaptiveStream) balancing quality based on subscriber viewport.
- Browser-Native Web Speech API: Continuous zero-latency speech recognition (
webkitSpeechRecognition) integrated directly into the meeting room loop. - Live Captions Banner: Subtitle overlay bar displaying real-time transcribed dialogue on screen during active meetings.
- Transcript Buffer & Deduplication: Real-time entry management (
TranscriptManager) tracking timestamps, epoch times, speaker labels, speech fragments, and system state changes.
PulseMeet features a dual-engine AI pipeline. Primary summarization uses Google Gemini 2.5 Flash via a secure Next.js API route. If Gemini quota limits or network outages occur, PulseMeet transparently shifts to local heuristic processing engines.
| AI Output | Primary Engine (Google Gemini AI) | Local Fallback Engine (Zero-Downtime) |
|---|---|---|
| Executive Summary | generateSummary() via Gemini 2.5 Flash API |
SummaryService: Speaker-line extraction & dialogue filtering |
| Action Items | generateActionItems() structured prompt extraction |
ActionItemsService: Regex sentence splitting & keyword analysis (assigned to, will, needs to, should) |
| Meeting Insights | generateInsights() structured metrics prompt |
InsightsService: Word-frequency noun parsing, timestamp duration calculation, decision phrase tracking |
| Missed Meeting Recovery | RecoveryService bullet point generation |
Local phrase summarizer prefixing missed content with "You missed:" |
- Comprehensive Reports Hub (
/reports): Filter, search, sort, and review past AI meeting reports. - Multi-Format Data Exporting:
- π Plain Text Transcript (
.txt): Full timestamped dialogue log. - π Summary & Action Items (
.txt): Executive summary and formatted bulleted action items. - π Formatted PDF Report (
.pdf): Styled multi-page PDF document generated client-side viajsPDF, containing Executive Summary, Action Items, Topics, Key Themes, and Full Transcript.
- π Plain Text Transcript (
- Batch Report Deletion: Multi-select report deletion with real-time UI synchronization and Supabase RLS validation.
- Interactive Dashboard (
/dashboard): Visual metric cards displaying total rooms, total reports, action item counts, monthly meeting minutes, extracted topics, AI summaries, and PDF downloads.
PulseMeet separates real-time media streams, authentication, speech processing, and AI generation into decoupled layers.
flowchart TD
subgraph Client ["Client Browser (Next.js 16 Client Bundle)"]
UI["React 19 UI Components"]
Speech["Web Speech API (SpeechRecognition)"]
TM["TranscriptManager (In-Memory Buffer)"]
LKClient["LiveKit WebRTC Client"]
end
subgraph Auth ["Authentication & Storage (Supabase)"]
SupaAuth["Supabase Auth (Google OAuth)"]
SupaDB[("Supabase PostgreSQL DB")]
end
subgraph RTC ["Real-Time Communication"]
LKServer["LiveKit Cloud / WebRTC Server"]
end
subgraph AI ["AI Intelligence Services"]
APIRoute["Next.js Server API (/api/meeting/ai)"]
Gemini["Google Gemini 2.5 Flash AI"]
LocalAI["Local Heuristic AI Engines (Fallback)"]
end
UI <-->|OAuth Flow| SupaAuth
UI <-->|CRUD Rooms / Reports| SupaDB
LKClient <-->|WebRTC Media Tracks| LKServer
Speech -->|Speech Events| TM
TM -->|Meeting End Transcript| APIRoute
APIRoute -->|Primary Prompt| Gemini
APIRoute -.->|Fallback Execution| LocalAI
APIRoute -->|Save Results| SupaDB
sequenceDiagram
autonumber
actor User
participant Login as Login Page
participant Supabase as Supabase Auth
participant Google as Google OAuth Provider
participant Callback as Auth Callback
participant Profile as Complete Profile
participant Dashboard as Dashboard
User->>Login: Click Continue with Google
Login->>Supabase: signInWithOAuth
Supabase->>Google: Redirect to Google Login
Google-->>User: Authenticate & Authorize
Google->>Callback: Redirect with Access Tokens
Callback->>Supabase: getSession
Callback->>Dashboard: Redirect to Dashboard
Dashboard->>Supabase: Query profiles table
alt Profile missing or incomplete
Dashboard->>Profile: Redirect to complete profile
User->>Profile: Enter display name and avatar
Profile->>Supabase: Upsert profiles record
Profile->>Dashboard: Redirect back to Dashboard
end
sequenceDiagram
autonumber
actor Attendee
participant RoomPage as Meeting Room
participant TokenAPI as API Route
participant LKSDK as LiveKit Server SDK
participant LKServer as LiveKit WebRTC Server
Attendee->>RoomPage: Navigate to Room
RoomPage->>TokenAPI: GET livekit-token endpoint
TokenAPI->>LKSDK: createToken roomName and username
LKSDK-->>TokenAPI: Signed AccessToken JWT
TokenAPI-->>RoomPage: Return token object
RoomPage->>LKServer: room.connect url and token
LKServer-->>RoomPage: Connected Event
RoomPage->>LKServer: Enable Mic & Camera Tracks
LKServer-->>Attendee: Media Stream Established
flowchart LR
subgraph Capture ["Audio Capture"]
Mic["Microphone Input"] --> SpeechRec["Web Speech API"]
end
subgraph Buffer ["Local Memory"]
SpeechRec -->|onresult| TM["TranscriptManager"]
TM -->|addSpeech| Array["Transcript Entries Array"]
end
subgraph PostMeeting ["Meeting Termination Cleanup"]
Array -->|generateTranscript| FullText["Raw Transcript Text"]
FullText --> PostAPI["POST /api/meeting/ai"]
end
subgraph Generation ["Dual-Engine Processing"]
PostAPI -->|Primary| Gemini["Google Gemini 2.5 Flash"]
PostAPI -.->|API Failure / Catch| LocalFallback["Local Service Engines"]
LocalFallback --> SummarySvc["SummaryService"]
LocalFallback --> ActionSvc["ActionItemsService"]
LocalFallback --> InsightsSvc["InsightsService"]
end
subgraph Storage ["Database Persistence"]
Gemini --> Save[("Supabase: meeting_ai_results")]
SummarySvc --> Save
ActionSvc --> Save
InsightsSvc --> Save
end
flowchart TD
Start["Active Meeting Session"] --> Monitor["NetworkStats Monitor"]
Monitor --> Check{"Connection Effective Type?"}
Check -->|4G / High Speed| Excellent["Status: Excellent (720p Video)"]
Check -->|4G| Good["Status: Good (480p Adaptive)"]
Check -->|3G| Poor["Status: Poor (360p Low Data)"]
Check -->|2G / Slow-2G| Critical["Status: Critical (Audio Priority)"]
Critical --> AutoAudio["Auto-Disable Local Camera"]
Critical --> PauseRec["Pause AI Recording Signal"]
Critical --> RecordStart["Record Network Drop Start Timestamp"]
Excellent --> ReconnectCheck{"Was in Critical State?"}
Good --> ReconnectCheck
ReconnectCheck -->|Yes| RecoveryTrigger["Trigger Network Recovery Process"]
ReconnectCheck -->|No| NormalRun["Continue Normal Streams"]
RecoveryTrigger --> EnableCam["Re-enable Camera Track"]
RecoveryTrigger --> ResumeRec["Resume AI Recording Signal"]
RecoveryTrigger --> ExtractMissed["Extract Missed Entries"]
ExtractMissed --> RecoverySvc["RecoveryService.generate"]
RecoverySvc --> Modal["Display RecoverySummaryModal"]
PulseMeet is optimized for modern web performance standards:
- Next.js 16 App Router: Leverages React Server Components for static page shell delivery and fast first contentful paint (FCP).
- Client Component Code-Splitting: Heavier client-side modules (WebRTC UI, PDF generators, filter modals) are dynamically imported using
next/dynamicwithssr: false:const MeetingRoom = dynamic(() => import("@/components/meeting/MeetingRoom"), { ssr: false }); const RecoverySummaryModal = dynamic(() => import("@/components/meeting/RecoverySummaryModal"), { ssr: false }); const SummaryViewer = dynamic(() => import("@/components/reports/SummaryViewer"), { ssr: false });
- WebRTC Adaptive Bitrate (
dynacast&adaptiveStream): Automatically scales down video track resolutions for hidden or background grid tiles to conserve bandwidth and CPU usage. - Memoized State Computations: Critical components wrap array filtering, statistics calculations, and participant mapping in
useMemoanduseCallbackhooks to eliminate unnecessary re-renders. - Asynchronous Audio Track Detachment: LiveKit audio elements are managed with DOM element cleanup routines upon track unsubscribing to prevent memory leaks.
PulseMeet provides robust network degradation support for users on unstable internet connections:
- Active Connection Telemetry (
NetworkStats): Readsnavigator.connectionproperties (effectiveType,downlink,rtt) to monitor real-time network conditions. - Automatic Audio Priority: When network quality degrades to Critical (
2gorslow-2g), PulseMeet automatically disables camera publication, prioritizing clear audio continuity. - AI Transcript Outage Buffering: Connection drops trigger
transcriptManager.pauseRecording(). When reconnected,transcriptManager.resumeRecording()logs the outage interval. - Automated Missed Content Summarization: PulseMeet calculates the exact time interval of the disconnect, queries
getEntriesBetween(startMs, endMs), parses speaker statements withRecoveryService, and prompts the user with an AI Recovery Summary Modal (RecoverySummaryModal) detailing missed discussion points.
Security controls protect user privacy and system access:
- Supabase Authentication: Passwords and credentials are managed directly by Supabase Auth with Google OAuth PKCE exchange flow.
- Row Level Security (RLS): PostgreSQL tables enforce database-level access policies ensuring users can only read, edit, or delete rooms and reports created by their own authenticated user ID.
- Short-Lived LiveKit JWT Tokens: WebRTC access tokens are signed on the server (
livekit-server-sdk) with strictly scoped room permissions (roomJoin,canPublish,canSubscribe) and never expose the master secret. - Encapsulated Gemini API Credentials: All generative AI requests execute server-side within the
/api/meeting/airoute. TheGEMINI_API_KEYis never exposed in client bundle code. - XSS & Injection Defense: Dynamic URLs use site URL helpers (
lib/config/site.ts) to validate redirect domains and protect against open redirect vulnerabilities.
PulseMeet uses a relational PostgreSQL database schema managed via Supabase.
Stores user profile information synced from Supabase Auth.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
uuid |
Primary Key, references auth.users(id) |
User's unique Auth ID |
email |
text |
NOT NULL |
User email address |
full_name |
text |
NULLABLE |
Display name |
avatar_url |
text |
NULLABLE |
Profile picture URL |
updated_at |
timestamptz |
DEFAULT now() |
Last update timestamp |
Stores meeting room configurations and AI toggle preferences.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
uuid |
Primary Key, DEFAULT gen_random_uuid() |
Unique room UUID |
name |
text |
NOT NULL |
Room title/name |
created_by |
uuid |
NOT NULL, references profiles(id) |
Room creator ID |
screen_share_enabled |
boolean |
DEFAULT true |
Screen share feature toggle |
ai_transcript |
boolean |
DEFAULT false |
AI speech transcription toggle |
ai_summary |
boolean |
DEFAULT false |
AI summary generation toggle |
ai_action_items |
boolean |
DEFAULT false |
AI action item extraction toggle |
ai_recovery_mode |
boolean |
DEFAULT false |
AI network recovery feature toggle |
created_at |
timestamptz |
DEFAULT now() |
Room creation timestamp |
Stores post-meeting AI reports, raw transcripts, summaries, and metrics.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
uuid |
Primary Key, DEFAULT gen_random_uuid() |
Report unique ID |
room_id |
uuid |
NOT NULL, references rooms(id) ON DELETE CASCADE |
Associated meeting room |
transcript |
text |
NULLABLE |
Full timestamped transcript log |
summary |
text |
NULLABLE |
Generated executive summary |
action_items |
text |
NULLABLE |
Extracted action items string |
insights |
text |
NULLABLE |
Duration, topics, decisions & themes |
created_at |
timestamptz |
DEFAULT now() |
Report generation timestamp |
erDiagram
profiles ||--o{ rooms : "creates"
rooms ||--o{ meeting_ai_results : "generates"
profiles {
uuid id PK
text email
text full_name
text avatar_url
timestamptz updated_at
}
rooms {
uuid id PK
text name
uuid created_by FK
boolean screen_share_enabled
boolean ai_transcript
boolean ai_summary
boolean ai_action_items
boolean ai_recovery_mode
timestamptz created_at
}
meeting_ai_results {
uuid id PK
uuid room_id FK
text transcript
text summary
text action_items
text insights
timestamptz created_at
}
PulseMeet includes server-side Next.js route handlers:
Generates a LiveKit JWT token for joining a WebRTC meeting room.
- Query Parameters:
room(string, optional): Room UUID or name. Default:"default-room"username(string, optional): Display name for the participant. Default:"guest"
- Success Response (200 OK):
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
Generates meeting summary, action items, and insights via Google Gemini 2.5 Flash AI.
- Request Body:
{ "transcript": "[10:00 AM] Alex: We need to launch the app by Friday.\n[10:01 AM] Sarah: I will write the documentation.", "summaryEnabled": true, "actionItemsEnabled": true, "insightsEnabled": true } - Success Response (200 OK):
{ "summary": "Executive summary of the discussion...", "actionItems": "- Sarah: Write the documentation by Friday", "insights": "Duration: 2 min\nTopics Discussed:\n- App Launch\nDecisions Count: 1\nAction Items Count: 1\nKey Themes:\n- Collaborative discussion" } - Error Response (400 Bad Request):
{ "error": "Transcript is required" }
Diagnostics route for testing Google Gemini API key configuration and connectivity.
- Success Response (200 OK):
{ "status": "success", "response": "Gemini Connection Successful" }
PulseMeet follows a modular component structure:
app/layout.tsx: Root HTML layout importing Google Geist fonts and styling frameworks.app/page.tsx: Entry point redirecting users to/login.app/login/page.tsx: Google OAuth login page with action cards.app/auth/callback/page.tsx: OAuth redirection callback route processing Supabase auth tokens.app/complete-profile/page.tsx: User profile completion page.app/dashboard/page.tsx: User dashboard displaying quick links, metrics, and recent reports.app/create-room/page.tsx: Interface to construct meeting rooms and feature flags.app/join-meeting/page.tsx: Direct entry form accepting room IDs or meeting URLs.app/room/[roomId]/page.tsx: Dynamically rendered meeting room wrapper (ssr: false).app/rooms/page.tsx: Grid view of all created rooms with copy link and deletion features.app/rooms/[roomId]/edit/page.tsx: Room configuration editor.app/reports/page.tsx: Reports hub with search, filters, batch operations, detail views, and PDF export.
components/meeting/MeetingRoom.tsx: Core WebRTC meeting orchestrator managing LiveKit rooms, track publishing, network monitoring, and transcript saving.components/meeting/MeetingControls.tsx: Meeting footer containing hardware toggles, screen share button, captions, and raise hand.components/meeting/MeetingVideoArea.tsx: Grid container rendering local preview and remote participant video tiles.components/meeting/VideoTile.tsx: Individual participant tile managing media elements and active speaker highlights.components/meeting/NetworkStats.tsx: Network quality monitor displaying connection effective type, downlink, and RTT.components/meeting/LiveCaptions.tsx: Floating closed-captions banner.components/meeting/RecoverySummaryModal.tsx: Outage recovery summary popup.components/reports/InsightsViewer.tsx: Rendered metrics cards displaying duration, topics, decisions, and themes.components/reports/ReportCard.tsx: Individual report card with search highlight and multi-selection checkbox.
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 16.2.6 |
App Router, Server Components, API Routes |
| React | 19.2.4 |
UI Library & Hooks Engine |
| TypeScript | ^5.0.0 |
Static Type Safety |
| Technology | Version | Purpose |
|---|---|---|
| LiveKit Client | ^2.19.1 |
WebRTC audio/video client connection handling |
| LiveKit Components React | ^2.9.21 |
React components for LiveKit streams |
| LiveKit Server SDK | ^2.15.4 |
Server-side JWT token generation (AccessToken) |
| Technology | Version | Purpose |
|---|---|---|
| Supabase Client | ^2.106.2 |
Auth, PostgreSQL client queries & RLS enforcement |
| Technology | Version | Purpose |
|---|---|---|
| @google/genai | ^2.8.0 |
Official SDK for Google Gemini 2.5 Flash AI |
| Web Speech API | Native Browser | Client-side continuous speech recognition |
| Technology | Version | Purpose |
|---|---|---|
| Tailwind CSS | ^4.0.0 |
Utility-first CSS framework |
| Lucide React | ^1.17.0 |
Icon set |
| jsPDF | ^4.2.1 |
Client-side PDF report rendering |
| clsx & tailwind-merge | ^2.1.1 |
Class name manipulation |
Follow these instructions to run PulseMeet locally.
- Node.js:
v18.17.0or higher - npm or pnpm or yarn
- Supabase Account: A running Supabase project with Google Auth enabled.
- LiveKit Server Instance: LiveKit Cloud account or self-hosted LiveKit instance.
- Google Gemini API Key: API key from Google AI Studio.
git clone https://github.com/cherry-git999/PulseMeet.git
cd PulseMeet
npm installCreate a .env.local file in the project root by copying .env.example:
cp .env.example .env.localFill in your environment credentials in .env.local:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-supabase-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
# LiveKit Configuration
NEXT_PUBLIC_LIVEKIT_URL=wss://your-livekit-project.livekit.cloud
LIVEKIT_API_KEY=your-livekit-api-key
LIVEKIT_API_SECRET=your-livekit-api-secret
# Gemini AI API Configuration
GEMINI_API_KEY=your-gemini-api-key
# Centralized Site URL for redirects
NEXT_PUBLIC_SITE_URL=http://localhost:3000Run the following SQL migration script in your Supabase SQL Editor to construct the required tables and security policies:
-- 1. Create Profiles Table
CREATE TABLE IF NOT EXISTS public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
full_name TEXT,
avatar_url TEXT,
updated_at TIMESTAMPTZ DEFAULT now()
);
-- 2. Create Rooms Table
CREATE TABLE IF NOT EXISTS public.rooms (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
created_by UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
screen_share_enabled BOOLEAN DEFAULT true,
ai_transcript BOOLEAN DEFAULT false,
ai_summary BOOLEAN DEFAULT false,
ai_action_items BOOLEAN DEFAULT false,
ai_recovery_mode BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 3. Create Meeting AI Results Table
CREATE TABLE IF NOT EXISTS public.meeting_ai_results (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
room_id UUID NOT NULL REFERENCES public.rooms(id) ON DELETE CASCADE,
transcript TEXT,
summary TEXT,
action_items TEXT,
insights TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Enable Row Level Security (RLS)
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.rooms ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.meeting_ai_results ENABLE ROW LEVEL SECURITY;
-- RLS Policies for profiles
CREATE POLICY "Users can view all profiles" ON public.profiles FOR SELECT USING (true);
CREATE POLICY "Users can update own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
CREATE POLICY "Users can insert own profile" ON public.profiles FOR INSERT WITH CHECK (auth.uid() = id);
-- RLS Policies for rooms
CREATE POLICY "Users can view own rooms" ON public.rooms FOR SELECT USING (auth.uid() = created_by);
CREATE POLICY "Users can insert own rooms" ON public.rooms FOR INSERT WITH CHECK (auth.uid() = created_by);
CREATE POLICY "Users can update own rooms" ON public.rooms FOR UPDATE USING (auth.uid() = created_by);
CREATE POLICY "Users can delete own rooms" ON public.rooms FOR DELETE USING (auth.uid() = created_by);
-- RLS Policies for meeting_ai_results
CREATE POLICY "Users can view reports for their rooms" ON public.meeting_ai_results
FOR SELECT USING (
EXISTS (SELECT 1 FROM public.rooms WHERE rooms.id = meeting_ai_results.room_id AND rooms.created_by = auth.uid())
);
CREATE POLICY "Users can insert reports for their rooms" ON public.meeting_ai_results
FOR INSERT WITH CHECK (
EXISTS (SELECT 1 FROM public.rooms WHERE rooms.id = meeting_ai_results.room_id AND rooms.created_by = auth.uid())
);
CREATE POLICY "Users can delete reports for their rooms" ON public.meeting_ai_results
FOR DELETE USING (
EXISTS (SELECT 1 FROM public.rooms WHERE rooms.id = meeting_ai_results.room_id AND rooms.created_by = auth.uid())
);Start the Next.js development server:
npm run devOpen http://localhost:3000 in your browser.
To generate a production build:
npm run build
npm run startDeploy seamlessly on Vercel by linking your repository and populating all environment variables in the Vercel dashboard.
| Variable Name | Required? | Example Value | Description & Security Notes |
|---|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Yes | https://xyz.supabase.co |
Public Supabase API project endpoint |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Yes | eyJhbGciOi... |
Public client API key for Supabase Auth and database operations |
NEXT_PUBLIC_LIVEKIT_URL |
Yes | wss://app.livekit.cloud |
Public WebSocket endpoint for LiveKit WebRTC server |
LIVEKIT_API_KEY |
Yes | APIxxxxxxxxx |
Private LiveKit API Key (server-side token generation) |
LIVEKIT_API_SECRET |
Yes | secretxxxxxxx |
Private LiveKit API Secret (never expose to client) |
GEMINI_API_KEY |
Yes | AIzaSyXXXXXX |
Private Google Gemini API Key used in /api/meeting/ai |
NEXT_PUBLIC_SITE_URL |
Recommended | https://pulsemeet.vercel.app |
Base URL used for invitation links and OAuth redirects |
PulseMeet/
βββ app/ # Next.js 16 App Router Pages & API Routes
β βββ api/ # Server-side API endpoints
β β βββ livekit-token/ # Token generator for WebRTC rooms (route.ts)
β β βββ meeting/ # AI generation handler (meeting/ai/route.ts)
β β βββ test-gemini/ # Gemini diagnostic endpoint (route.ts)
β βββ auth/ # Authentication handling
β β βββ callback/ # Google OAuth callback handler (page.tsx)
β βββ complete-profile/ # Profile setup and update (page.tsx)
β βββ create-room/ # New meeting room form (page.tsx)
β βββ dashboard/ # User dashboard & statistics (page.tsx)
β βββ join-meeting/ # Join room by ID or URL (page.tsx)
β βββ login/ # OAuth login page (page.tsx)
β βββ reports/ # Meeting reports hub & PDF exporter (page.tsx)
β βββ room/ # WebRTC meeting room page ([roomId]/page.tsx)
β βββ rooms/ # Room management list & editor ([roomId]/edit)
β βββ error.tsx # Global error boundary component
β βββ globals.css # Tailwind v4 styles & theme utilities
β βββ layout.tsx # Root HTML layout with Geist typography
β βββ page.tsx # Base route (redirects to /login)
βββ components/ # Modular React Components
β βββ dashboard/ # Dashboard metrics & statistic cards
β β βββ DashboardStats.tsx
β βββ meeting/ # Meeting room WebRTC UI components
β β βββ AIStatusChip.tsx # Active AI feature status chip & dropdown
β β βββ InviteModal.tsx # Copy link & share modal
β β βββ LiveCaptions.tsx # Real-time subtitle overlay
β β βββ LocalVideoPreview.tsx # Camera/mic preview widget
β β βββ MeetingHeader.tsx # Top status bar & network indicator
β β βββ MeetingRoom.tsx # Main WebRTC orchestrator
β β βββ MeetingVideoArea.tsx # Dynamic grid container
β β βββ NetworkIndicator.tsx # Compact quality badge
β β βββ NetworkStats.tsx # Connection metrics inspector
β β βββ ParticipantSidebar.tsx # Participant list & hand raise list
β β βββ RecoverySummaryModal.tsx # Missed content recovery modal
β β βββ VideoGrid.tsx # Flex/Grid layout manager
β β βββ VideoTile.tsx # Individual participant media tile
β βββ reports/ # Report viewing & export components
β β βββ ActionItemsViewer.tsx # Action items checklist view
β β βββ DeleteReportModal.tsx # Deletion confirmation modal
β β βββ InsightsViewer.tsx # Metrics summary cards
β β βββ ReportCard.tsx # Report grid item
β β βββ ReportFilters.tsx # Filter controls
β β βββ ReportSearch.tsx # Search bar
β β βββ SummaryViewer.tsx # Executive summary viewer
β βββ reports/ # Full dialogue transcript viewer
β β βββ TranscriptViewer.tsx
β βββ rooms/ # Room CRUD components
β β βββ DeleteRoomModal.tsx # Room deletion confirmation modal
β β βββ RoomCard.tsx # Room grid item
β β βββ RoomForm.tsx # Shared room creation & edit form
β βββ ui/ # Reusable UI primitive components
β βββ AppCard.tsx
β βββ CopyToast.tsx
β βββ MeetingControls.tsx
β βββ ParticipantCard.tsx
β βββ PrimaryButton.tsx
β βββ StatusBadge.tsx
βββ lib/ # Core Utilities & AI Logic Services
β βββ ai/ # Dual-Engine AI services
β β βββ prompts/ # Gemini prompt templates (summary, action items, insights)
β β βββ action-items-service.ts # Fallback action items regex parser
β β βββ gemini.ts # GoogleGenAI SDK client initialization
β β βββ insights-service.ts # Fallback insights metrics generator
β β βββ networkRecovery.ts # Network outage interval tracker
β β βββ provider.ts # Server-side Gemini execution methods
β β βββ recovery-service.ts # Outage recovery summary generator
β β βββ summary-service.ts # Fallback executive summary generator
β β βββ transcription-service.ts # Client Web Speech API wrapper
β βββ config/ # Centralized site configurations (site.ts)
β βββ reports/ # Exporters & parsers
β β βββ duration-parser.ts # Duration string to minute converter
β β βββ export-utils.ts # PDF (jsPDF) & text export helper functions
β β βββ insights-parser.ts # Markdown insights text parser
β βββ livekit.ts # Server-side LiveKit access token generator
β βββ supabase.ts # Supabase client instantiation
β βββ transcript-manager.ts # Real-time transcript state buffer
β βββ utils.ts # Tailwind class merger
βββ types/ # TypeScript Global Declarations
β βββ speech-recognition.d.ts # SpeechRecognition browser type definitions
βββ .env.example # Template for environment variables
βββ next.config.ts # Next.js configuration
βββ package.json # Dependencies & script definitions
βββ tsconfig.json # TypeScript compiler config
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β 1. Google OAuth β ββββ> β 2. Profile Sync β ββββ> β 3. Dashboard β
β Sign In β β & Metadata Checkβ β Overview & Statsβ
βββββββββββββββββββ βββββββββββββββββββ ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β 6. Meeting End β <ββββ β 5. Speech Rec β <ββββ β 4. Join WebRTC β
β & Dual-AI Run β β & Subtitles Run β β Meeting Room β
ββββββββββ¬βββββββββ βββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ βββββββββββββββββββ
β 7. Save Report β ββββ> β 8. Browse, Filterβ
β to Supabase β β & Download PDF β
βββββββββββββββββββ βββββββββββββββββββ
- Authentication: User signs in with Google OAuth on
/login. Token exchange completes via/auth/callback. - Dashboard: User lands on
/dashboard, views meeting statistics, recent reports, and quick actions. - Room Creation: User navigates to
/create-room, specifies room name and toggles AI features (Transcript, Summary, Action Items, Recovery Mode). - Meeting Session: User joins
/room/[roomId]. The app fetches a LiveKit token from/api/livekit-tokenand initializes media tracks. - Real-time AI Features:
- Web Speech API listens and displays live captions.
TranscriptManagerbuffers dialogue entries with timestamps.NetworkStatstracks connection telemetry. If quality drops, audio priority triggers and an outage interval is recorded.
- Meeting Termination: Leaving the room triggers meeting completion logic:
- Final system message
"Meeting ended"is appended. - The transcript is sent to
/api/meeting/ai. - Primary AI (Gemini) or local fallback engines process the transcript into Summary, Action Items, and Insights.
- Results are saved to
meeting_ai_resultsin Supabase.
- Final system message
- Report Management & PDF Export: User opens
/reports, searches or filters reports, views breakdown tabs, and downloads.txtor styled.pdfmeeting reports.
| Symptom / Issue | Possible Cause | Solution |
|---|---|---|
| LiveKit Connection Fails | Missing or incorrect NEXT_PUBLIC_LIVEKIT_URL, LIVEKIT_API_KEY, or LIVEKIT_API_SECRET. |
Verify LiveKit environment variables in .env.local and ensure WebSocket URL begins with wss://. |
| Microphone / Camera Permission Error | Browser permissions blocked or hardware in use by another app. | Grant media permissions in browser site settings and close conflicting applications using camera/mic. |
| Speech Recognition Not Working | Browser does not support Web Speech API (webkitSpeechRecognition). |
Use Google Chrome, Microsoft Edge, or a WebKit-compatible browser. Note that Firefox lacks native SpeechRecognition support. |
| Gemini AI API Error (500 or Empty Response) | Missing GEMINI_API_KEY or quota exceeded on Google AI Studio. |
Check /api/test-gemini endpoint. If Gemini fails, PulseMeet automatically falls back to local processing engines without breaking meeting execution. |
| Supabase RLS Error when Deleting Reports | Missing DELETE policy on meeting_ai_results table in Supabase. |
Re-run the SQL migration script provided in Step 4 of setup to grant correct RLS DELETE permissions for room creators. |
| PDF Download Failures | Popup blocker or canvas rendering error in jsPDF. | Ensure browser allows popups/downloads for the site domain. |
- Next.js 16 App Router & React 19 Upgrade
- LiveKit WebRTC Video/Audio Integration & Media Controls
- Google OAuth 2.0 via Supabase Auth
- Client-Side Web Speech API Subtitles & Captions
- Google Gemini 2.5 Flash AI Summaries, Action Items & Insights
- Local Fallback AI Processing Engines (Zero-Downtime Reliability)
- Network Stats Telemetry & Outage AI Recovery Modal
- Reports Search, Room/Date Filtering & PDF Export
- Multi-language Speech Recognition (Spanish, French, German, Hindi)
- Live Chat Messaging during meetings
- Cloud Screen Recording & Video Playback Archiving
- Calendar Integration (Google Calendar / Outlook Sync)
- Breakout Rooms for large team meetings
Contributions are welcome! If you would like to contribute improvements, feel free to fork the repository and submit a pull request.
- Fork the Repository
- Create your Feature Branch:
git checkout -b feature/AmazingFeature
- Commit your Changes:
git commit -m 'Add some AmazingFeature' - Push to the Branch:
git push origin feature/AmazingFeature
- Open a Pull Request
Distributed under the MIT License. See LICENSE for details.
MIT License
Copyright (c) 2026 A. Sri Sai Charan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- Next.js β React Framework for the Web
- React β Library for web and native user interfaces
- LiveKit β Open-source WebRTC Infrastructure
- Supabase β Open-source Firebase Alternative
- Google Gemini AI β Next-generation Multimodal AI
- Tailwind CSS β Utility-first CSS framework
- TypeScript β Strongly typed programming language
- Vercel β Cloud platform for static sites and Serverless Functions
- Lucide Icons β Beautiful & consistent icons
- jsPDF β Client-side HTML5 PDF solution
A. Sri Sai Charan
Computer Science Engineer | Full Stack Developer | AI Enthusiast
- GitHub: https://github.com/cherry-git999
- LinkedIn: https://www.linkedin.com/in/sri-sai-charan-arasada-1a1b12320/
PulseMeet β Designed, engineered, and built with β€οΈ by A. Sri Sai Charan.