← All work
Case study · 2025

Konvele

An event and student community platform with QR ticket check-in, live event engagement, and Genkit flows on Gemini for recommendations and mentor matching.

Next.jsTypeScriptFirebaseFirestoreGenkitGemini 2.5 FlashTailwind CSSRadix UILive site ↗Source ↗
konvele.vercel.app
Konvele — screenshot of the live site

Overview

Konvele is a platform for campus and community events with two roles. Organizers create events, check people in and see analytics, and students discover events, register, chat during sessions and find peers to learn from. Firestore holds the data, and a set of Genkit flows running on Gemini 2.5 Flash handles the parts that need judgement: recommending events, matching mentors, answering event questions and writing post-event summaries.

The problem

Student events usually run on a spreadsheet, a Google Form and a WhatsApp group. Organizers lose track of who actually showed up, attendees cannot easily find the next thing worth going to, and whatever was said in the session is gone once it ends. I wanted registration, check-in, live engagement and follow-up in one place.

What I built

  • Google sign-in through Firebase Auth with an onboarding step that writes a users document with role and skills, plus separate organizer and student dashboards.
  • Event CRUD, registration, and a ticket page that encodes the registration ID as a QR code and can export the ticket as a PDF with jsPDF and html2canvas.
  • A QRCheckIn component that opens the rear camera, decodes frames on a canvas with jsQR inside a requestAnimationFrame loop, and marks the registration checkedIn with a timestamp. Manual ID entry is available as a fallback.
  • Live event features on Firestore: chat, upvoted Q&A, polls with votes, and a per-event leaderboard that increments user scores.
  • recommendEventsFlow: excludes events the user already registered for, returns the three soonest upcoming events if the user has no history (so no model call is made), and otherwise asks Gemini to pick up to five events based on the tags and categories of past registrations, each with a reason.
  • findMentorsFlow for Peer Connect: sends the requested skill and every other student's skills to Gemini, gets back up to five UIDs with reasons, then fills in full profiles before the UI renders them. Matches lead into 1:1 conversations that update in real time through onSnapshot.
  • answerQuestionAboutEventFlow, which uses a Genkit tool (getEventDetails) so the model fetches the event's schedule and speakers itself and is told to admit when it does not know, and generateEventSummaryFlow, which works out check-in rate, poll percentages and Q&A ranked by upvotes in code before asking the model for a written summary.

Architecture

A Next.js app that talks to Firestore directly from the client, with server actions wrapping the Genkit flows.

flowchart LR
  subgraph client["Client"]
    org["Organizer dashboard"]
    stu["Student dashboard"]
    scan["QRCheckIn with jsQR"]
  end
  subgraph server["Next.js server actions"]
    rec["recommendEventsFlow"]
    mentor["findMentorsFlow"]
    assist["eventAssistant with tool"]
    summ["generateEventSummaryFlow"]
  end
  subgraph data["Firebase"]
    auth["Firebase Auth"]
    fs[("Firestore events, registrations, chat, polls, conversations")]
  end
  subgraph ext["External"]
    gem["Gemini 2.5 Flash via Genkit"]
    qr["QR image API"]
  end
  org --> fs
  stu --> fs
  stu --> auth
  scan -->|"checkInUser"| fs
  stu --> rec
  stu --> mentor
  stu --> assist
  org --> summ
  rec --> fs
  mentor --> fs
  assist -->|"getEventDetails"| fs
  summ --> fs
  rec --> gem
  mentor --> gem
  assist --> gem
  summ --> gem
  stu -->|"ticket QR"| qr

System design

The path from registering to checking in to the organizer's summary after the event.

sequenceDiagram
  participant S as Student
  participant App as Next.js app
  participant FS as Firestore
  participant O as Organizer
  participant G as Gemini via Genkit
  S->>App: Register for event
  App->>FS: Add registration with checkedIn false
  App-->>S: Ticket page with QR of registration id
  O->>App: Open QR check-in
  loop each animation frame
    App->>App: Draw video frame and run jsQR
  end
  App->>FS: getRegistrationById
  App->>FS: Update checkedIn true with timestamp
  App-->>O: Toast with attendee details
  Note over S,FS: During the event chat, Q and A, polls write to Firestore
  O->>App: Generate event summary
  App->>FS: Fetch registrations, chat, questions, polls, votes
  App->>App: Compute check-in rate and poll percentages
  App->>G: Prompt with stats and transcripts
  G-->>App: Summary text
  App-->>O: Show AI summary

Decisions & trade-offs

  • Genkit flows with Zod schemas instead of raw prompts. Each flow declares typed input and output, so the UI gets structured recommendations and matches, not free text to parse. It adds a dependency and some boilerplate per feature.
  • Compute numbers in code, let the model write. The summary flow calculates attendance and poll results itself and only asks Gemini to narrate them, so the figures in the summary are not invented by the model.
  • Skip the model when there is nothing to reason about. New users get the three soonest events without an LLM call. That saves cost and latency, but the cold-start suggestions are generic.
  • Mentor matching sends every student's skills in the prompt. It is simple and works for a campus-sized user base, but it will not scale. Embeddings or a skill index would be needed past a few hundred users.

What I'd do next

  • Replace the placeholder email tool in sendEmailBlastFlow with a real provider and queue the sends.
  • Add Firestore security rules and move check-in to a server action so only the event's organizer can mark attendance.
  • Generate QR codes locally instead of through a third-party image API.