Inspiration

This project was inspired by the numerous activities hosted by SMU clubs and societies. Everyday, students' inboxes are filled with all the different activities they can attend, which makes it hard for students to keep track of what they would actually like to go to. We wanted to devise a solution that avoids this inbox spam, and makes it easier for students to find the activities they would like to attend. With our project, we consolidated discovery, prices, timing, attendees etc. all in one website that is easily accessible. We also wanted to add the concept of dynamic pricing, where organisers no longer have to guess a single price and hope that people join, which has a high chance of failure. Organisers can instead let pricing respond to actual demand, choosing between early-bird tiered pricing or a fully dynamic bonding-curve model where the price adjusts in real time as tickets sell, giving their event a much better chance of succeeding.

What it does

party.fun is an event platform for university students. Organisers create events, choose their preferred method of pricing (tiered vs hype-driven), and most importantly, set a hype threshold that needs to be hit for an event to go through. This ensures that the organisers do not lose out, by planning an event that will not ultimately go through. On the attendees side, they will be refunded automatically if the event does not go through. Attendees use this website to browse and find events that they like. They can use many convenient filters, such as filtering by date, location or hype meter. After payment, they will recevie a QR code that functions as a ticket. We also have an AI agent that can help with searching for events, manage bookings and create or edit events.

How we built it

Our frontend is a React (TypeScript) single-page app built with Vite, using React Router, Tailwind CSS and shadcn/ui. Our backend is a Node.js/Express service that owns everything the browser can't be trusted with: price quoting, payment orchestration, refund logic, API keys and the AI agent. Rather than re-implementing permissions in Express, the backend forwards each request's Supabase access token and queries the database as that user, so authorisation is enforced in one place.

Supabase is our source of truth. Postgres holds users, events, bookings, wallet transactions and reviews, with Row Level Security on every table so one student physically cannot read another's data. Anything that must be atomic — a pledge that debits a wallet, increments the hype count and issues a ticket — runs as a single security definer Postgres function, so it either fully commits or not at all. Supabase Auth handles signup, login and OAuth directly from the browser, and the pgvector extension stores event embeddings for semantic search.

Redis (specifically Upstash Redis) does three main jobs: caches slowest reads using stale-while-revalidate, serves the events feed instantly from cache, and rate-limits expensive endpoints like AI chat, checkout, top-ups and the SMS senders. If Redis goes down, everything falls through to Postgres and the app keeps working.

Stripe handles top-ups, ticket purchases and refunds; every charge carries an idempotency key so a double-click can never double-charge, and if a payment succeeds but the booking fails to commit, a compensating refund fires immediately. Balances live in Postgres as an append-only ledger, and a background reconciler sweeps for orphaned charges.

We used three Google APIs: Maps and Places to pin the exact venue and capture its coordinates, the Weather API to warn organisers about rain on their event date, and Speech-to-Text for voice input.

Google Gemini 2.5 Flash powers our semi-autonomous RAG agent, orchestrated with LangGraph. Incoming messages are classified by intent and routed to a specialist branch — discovery, recommendations, event management or transactions — each given only the tools relevant to its job, rather than one model with access to everything. Across those branches it has around thirty tools for searching events, checking your wallet, listing your bookings, looking up venue weather, buying tickets and creating events. Every write is a proposal: the agent stops, shows exactly what it intends to do, and waits. Once confirmed, the action is re-validated and executed under the user's own database permissions. Events are stored as vectors in Postgres using pgvector, so meaning rather than keywords will be matched. It also searches our own documentation, so questions about how the app works get answered accurately. Beyond that, it recalls facts about you across sessions, and falls back to Gemini's live search for anything we don't store ourselves.

Organisers choose between two pricing models at creation. Tiered is conventional: a fixed early-bird price, then a fixed greenlit price. Hype-driven pricing moves with demand along a bonding curve, where the next ticket costs: $$P(x) = P_{\text{base}} \cdot \left( \frac{P_{\text{max}}}{P_{\text{base}}} \right)^{\frac{x}{C}}$$ Here \(x\) is the active ticket count, \(C\) the capacity, and \(P_{\text{base}}\) and \(P_{\text{max}}\) the floor and ceiling the organiser sets. Because \(\frac{x}{C}\) stays between 0 and 1, the price starts at \(P_{\text{base}}\), reaches \(P_{\text{max}}\) only at full capacity, and never exceeds the organiser's cap. It is elastic both ways: give tickets away and later prices fall. Multi-ticket orders sum the curve, \(\sum_{k=0}^{Q-1} P(x+k)\), rather than multiplying one price. Each booking stores the exact amount paid, so refunds use the historical price. The model locks at creation. For more information, refer to this link: HYPE_DRIVEN_PRICING.md

Authentication runs directly against Supabase Auth from the browser — email/password, username, phone OTP, or Google and Facebook OAuth. Every account is verified as a current student by university and a unique matriculation number. The backend never issues its own tokens; it forwards each user's Supabase JWT so Postgres row-level security enforces permissions. Sessions auto-expire after 30 minutes idle, and password resets use our own emailed one-time code.

For deployment, Vercel is used for the frontend, and Render is used for the backend web service.

Challenges we ran into

1) Getting the AI agent to behave took us the better part of two weeks. The core problem was that the model had no real picture of how our app was put together, so when a request touched something it didn't understand, it filled the gap by inventing one — confidently answering with events, prices and features that didn't exist. Fixing it wasn't a matter of writing a better prompt. We had to give the agent a proper set of tools for reading actual app data, restrict each type of request to only the tools relevant to it, and build a retrieval layer over our own documentation so questions about how the app works get answered from the real thing rather than from the model's imagination.

2) The hype meter and pricing mechanics were harder to design than to build. Our first idea was four fixed price tiers, cheapest to most expensive, but the more we thought about it the more it felt like it worked against us. Higher tiers price might be unaffordable for some students, and someone who is only mildly curious about an event is unlikely to pay more. The harder question was where the 100% mark on the hype meter should sit. Any number we picked ourselves would have been arbitrary: 50 tickets is a runaway success for a small gathering and a failure for a concert, so a fixed threshold would be meaningless for most events on the platform. We settled on letting the organiser choosing between two models: a fixed-tiered model, where there are only two different prices: one for early bird, and one for greenlit, as well as a hype-driven model, where the price of a ticket gradually increases as less tickets are available overtime.

3) Handling money correctly turned out to be much harder than making a payment go through. Charging a card and creating a booking are two separate systems, and there are cases where the former can succeed and the latter can fail: a network interruption, a sold-out event, or a browser closing mid-checkout. Every payment now carries a key that makes it safe to retry, so a double-click or a refresh can't charge someone twice. If a charge goes through but the booking doesn't commit, a refund fires immediately to undo it. A background job periodically re-checks recent payments against our database and cleans up anything that slipped through: refunding charges with no booking behind them, and crediting top-ups that never landed.

Accomplishments that we're proud of

1) We built a working payment system that handles real money flows: wallets, linked cards, refunds safely. If an event doesn't get enough interest by its deadline, everyone is automatically refunded, and we made sure no one can be double-charged even if something crashes mid-payment.

2) We shipped a useful AI agent, not just a chatbot skin. It can answer questions, help organisers plan events, and buy tickets or edit events on a user's behalf, but it always pauses to ask for a confirmation before doing anything that touches money or an event, so nothing risky happens.

3) We designed a fairer dynamic pricing model. Ticket prices rise as more people buy in (rewarding early supporters), but after a mentor pointed out that prices could balloon to unrealistic amounts, we redesigned it so organisers set their own minimum and maximum price, keeping the excitement of dynamic pricing without letting it get out of hand.

What we learned

One of the biggest lessons we learned was that building a good product is not just about adding features. We realized the importance of enforcing permissions properly, using clear guardrails for AI instead of relying on it blindly, and designing the system so optional services could fail without affecting the whole app. Feedback also played a huge role in improving our ideas, especially when we redesigned our pricing model after mentor suggestions. Finally, working on a shared codebase with over 100 commits taught us that clear communication and teamwork are just as important as technical skills.

What's next for party.fun

Moving forward, party.fun will transition its AI agent from a standard chat interface into an Audio-First Event Planning Companion supported by a Real-Time Parallel Task Dashboard. Organizers will be able to brainstorm and construct events verbally with zero-latency responses (using streaming RAG logic to process intent chunks before they finish speaking). Additionally, a dashboard inspired by Real-Time Strategy (RTS) games will allow hosts to spawn, monitor, and configure multiple parallel subagents handling marketing, coordination, and weather tracking concurrently. Confirmations will remain gated by interactive local UI proposal cards, keeping token costs down while maintaining strict user safety.

Furthermore, if party.fun receives good reviews and more people uses the app, we will consider a premium model. Its centrepiece would be audience analytics, which is breaking down who is actually buying tickets by year of study, faculty, and university, so organisers can see which segments an event reached and which it missed, and plan the next one against real demand rather than instinct. Around that we would build cross-event insights (repeat attendees, what else your audience turns up to), benchmarking against comparable past events on the platform for pricing and capacity, priority placement in discovery, custom branding on event pages and ticket PDFs, waitlist management once an event sells out, and higher AI limits for organisers running several events at once.

Technology Stack List

1) Frontend:

  • React (TypeScript) + Vite
    • Vanilla CSS (Glassmorphism & HSL layouts)
  • WebSockets / WebRTC (For real-time streaming audio capture and vocal inputs)
  • Server-Sent Events (SSE) (For pushing parallel agent state metrics to the dashboard)

2) Backend:

  • Node.js (ES Modules)
  • Express.js (REST API Endpoints & Rate-Limiting middleware)
  • Real-time & Caching:
  • Redis (For active session tracking, SWR cache stores, and pub-sub task orchestration)

3) Database:

  • Supabase (PostgreSQL with RLS policy gates & custom PL/pgSQL database RPCs)

4) AI Services:

  • Google Gemini API (For text intent extraction and vector embedding retrieval)
  • Whispers / Speech APIs (Integrated through speechService for audio-to-text processing)

5) Payments & Media:

  • Stripe API (Idempotent card capture, refunds, and top-ups)
  • PDFKit / QRCode (For generating tickets and admin license certificates)

6) Deployment:

  • Vercel for frontend
  • Render for backend

Frontend features

1) Authentication & student verification: email, username, phone OTP and social login, with every account tied to a university and unique matriculation number.

2) Event discovery & management: a public feed with a Most Hyped rail, filters, and hybrid semantic/keyword search. Each event has a hype meter, pricing stage, attendee list, embedded directions map and a rain forecast for the date. Organisers can reate, edit and draft events with a Places address picker, hype threshold, campus restriction and a choice of tiered or bonding-curve pricing.

3) Checkout & wallet: pay by wallet or saved card, with card linking, top-ups and a full transaction ledger.

4) Ticket management: QR ticket PDFs, joined-events tabs, giving tickets away, and self-service refunds.

5) Organiser operations: cross-event attendee roster with CSV export, camera QR check-in, and co-organiser invites.

6) Analytics: revenue and attendance charts to display real-time data. Organisers have an additional profit calculator.

7) AI assistant: a chat panel with voice input that proposes actions as confirm/dismiss cards and remembers context across sessions. It comes with a voice record function using Google Cloud's speech-to-text converter so that people can choose to speak their prompts instead of typing them down.

8) Different roles: people who sign up for this app can either be a regular user, or an organiser. Additionally, there are admins moderating the app, with the ability to edit event details or delete events if a justifiable reason is given.

9) Reviews: plus post-event star ratings and a short description. This is entirely optional.

10) FAQ section: answers commonly asked questions about the app.

11) Static type safety: a tsc --noEmit typecheck script that validates the whole React/TypeScript frontend at build time, catching type errors before they ship.

12) Dark & light mode: a CSS-variable-driven theme system that restyles the whole app for readable, on-brand light and dark palettes. The default mode is dark.

13) Mobile responsiveness: view the app on your mobile phone.

Backend features

1) Auth & access control: forwards each user's token so database row-level security enforces permissions, reserving the privileged key for trusted paths only.

2) Payment orchestration: idempotent Stripe charges for pledges and top-ups, with inline compensating refunds if a booking fails to commit. Automatic refunds on cancellation, plus a sweep that repairs orphaned charges and detects wallet drift.

3) Deadline scheduler: refunds events that miss their threshold and pays out those that hit it, locked so instances can't double-process.

4) Upstash Redis caching & rate limiting: stale-while-revalidate on the slowest reads with immediate invalidation on writes, degrading to Postgres if Redis is down. For rate limiting, its cross-instance throttles on AI, checkout, top-ups and the paid SMS/email senders.

5) RAG AI agent: an intent-routed LangGraph state machine whose write tools return proposals, re-validated under the caller's own permissions before executing. It also includes chat-history and user-memory retrieval, with an embedding pipeline that re-indexes on write, as well as fuses pgvector semantic ranking with Postgres full-text search via Reciprocal Rank Fusion.

6) Email service: Sends all transactional email through Resend, covering the full event lifecycle — welcome messages, pledge confirmations, QR ticket PDFs, greenlight announcements, cancellation and refund notices, organiser revenue summaries, co-organiser invites and password reset codes.

7) Pricing engine: quotes both tiered and bonding-curve prices server-side, summing the curve across multi-ticket purchases so the total is exact

8) External API integrations: wraps Google Cloud (Gemini, Maps, Weather, Speech), Stripe, Resend and Twilio in fail-open service layers so any provider outage degrades a feature rather than the app.

Built With

Share this project:

Updates

Submission history