All projects

Meeting rooms and recaps

Video meetings on LiveKit + webedge-db — realtime rooms, recording (LiveKit Egress) and post-call recaps.

TypeScriptVue 3Media workflows
WebEdge Meet call screenshotDev-story
01

Challenge

After a call, the decisions and action items vanish into chat history or nobody's notes.

02

What we did

A Vue 3 + webedge-db meeting app using LiveKit for the WebRTC video, room controls and recording egress, plus a recap step that turns the recording into a post-call summary of decisions and actions.

03

Result

A call runs in a real room, gets recorded, and leaves behind a recap you can return to instead of scrubbing the whole transcript.

Dev-story article

Meeting rooms and recaps: how the project was built

The suite needed its own video meetings, not a link out to someone else's product, so identity, calendar and org-access could flow straight through. The catch was the backend runs on a two-core arm box: there was no spare CPU for server-side video compositing and no appetite to restart the media server for every recording. That constraint shaped almost every decision here.

Sections

05

Modules

05

Stack

TypeScript + Vue 3

01

Why the project exists

After a call, the decisions and action items vanish into chat history or nobody's notes.

The suite needed its own video meetings, not a link out to someone else's product, so identity, calendar and org-access could flow straight through. The catch was the backend runs on a two-core arm box: there was no spare CPU for server-side video compositing and no appetite to restart the media server for every recording. That constraint shaped almost every decision here.

02

What was built

A Vue 3 + webedge-db meeting app using LiveKit for the WebRTC video, room controls and recording egress, plus a recap step that turns the recording into a post-call summary of decisions and actions.

A LiveKit SFU handles the media, and our reactive backend (webedge-db) drives room state, chat, participants and access checks so panels update live without polling. Recording is done by compositing all participant tiles into a grid inside the moderator's browser and mixing their audio there, with a server-side LiveKit Egress path kept as an alternative. After a call, recaps pull action items out of the transcript and chat.

03

Main modules and user path

M01

In-browser recorder that tiles every participant's video into a Google-Meet-style canvas grid and mixes all audio via WebAudio, reconciling tiles and the audio graph live as people join and leave — the only path that fits a two-core host with no server CPU to spare

M02

LiveKit Egress recording control plane that uploads finished files to S3, kept as a server-side alternative with a deployment preflight check

M03

Post-call recaps that extract and dedupe action items from transcript and chat chunks using signal heuristics (follow-up, next step, owner, due-date phrases) rather than an LLM

M04

Realtime room panels — participant list, chat, room status — subscribed to backend updates so they stay live instead of polling

M05

A 15-minute cron sweep that auto-ends abandoned live rooms whose host closed the tab, finalizing child breakout rooms and active recordings so status and attendance stay clean

04

Architecture and technology decisions

Built with TypeScript, Vue 3, Media workflows.

LiveKit SFU for media with browser-side canvas/WebAudio recording (LiveKit Egress to S3 as an alternate), our reactive backend for realtime state, session auth, crons and calendar bridging, self-hosted on a two-core arm box with the frontend on Cloudflare Pages.

05

Result and lessons

A call runs in a real room, gets recorded, and leaves behind a recap you can return to instead of scrubbing the whole transcript.

A working self-hosted meeting stack that records and recaps on constrained hardware and ties each participant to their signed-in suite profile — recaps are honest keyword-driven extraction, not AI magic.

Read next

These projects share nearby technical or product decisions, so they show how the same principle behaves in another context.

Have a similar idea?

Discuss your project