Inspiration
One of our core project members, Alex, runs an Instagram account called Tritons Thrift with ~1.2k followers. He's had a strong vision of launching an online marketplace ever since creating the account. With a large wardrobe of hoodies, shirts, and jeans to move, and a built-in audience of UCSD students, a niche marketplace at tritonsthrift.tech with personal accommodations for UCSD students was the natural next step to streamline the on-campus shopping experience.
What it does
Tritons Thrift is a UCSD-exclusive clothing marketplace where students can buy and sell used clothes with their fellow Tritons. Unlike generic platforms like Depop or Facebook Marketplace, every feature is _ designed _ around the on-campus experience:
- Browse & search a live grid of listings by title, category, or tag
- List items with photo upload, category/condition tagging, and a description
- Message sellers in real-time via Supabase Realtime
- Coordinate meetups through a built-in UCSD location picker (Geisel, Sun God Lawn, Price Center Panda, and more) — propose a spot, accept or decline, then lock in a time and add it directly to Google Calendar
- Seller profiles including what college you’re from, and meetup spot preferences
How we built it
| Layer | Tech |
|---|---|
| Frontend | Vite + React (JavaScript) |
| Auth | Auth0 (OAuth) |
| Database + Realtime | Supabase (PostgreSQL + Realtime) |
| Storage | Supabase Storage |
| Backend | FastAPI (Python) |
We split ownership cleanly across three roles — database schema & RLS policies, frontend UI, and backend/integrations — to minimize merge conflicts in the 7-hour window. The AI pricing feature runs as a separate FastAPI microservice so it doesn't block the frontend if Browser Use times out.
Challenges we ran into
- Auth loading races — chaining Auth0's load state with a Supabase profile check created a gap where components would flash wrong content. We solved it by keeping
isLoadingtrue across the full async chain and wrapping the logic in a single context provider so it only runs once. - Real-time message deduplication — rapid re-renders and multiple concurrent fetches caused stale responses to overwrite fresh ones. We added per-fetch ID counters so only the latest response wins.
- Meetup coordination UX — encoding structured actions (spot proposals, time proposals, accept/decline) as prefixed text messages let us layer rich interaction on top of a plain Supabase messages table without changing the schema.
Accomplishments that we're proud of
- A fully working end-to-end marketplace — browse, list, message, and coordinate a meetup — built in under 7 hours
- The UCSD meetup flow: propose a spot with a photo card, accept/decline, lock in a time, and land directly on Google Calendar pre-filled with the item name and location
What we learned
- Loading state has to cover every async gap — not just the first one
- Structured messages (prefixed tokens) are a lightweight way to add rich interaction without extra database tables
- Clear ownership boundaries (who writes to Supabase, who writes React) are worth defining upfront even on a small team
What's next for Tritons Thrift
- Launch to the real Tritons Thrift audience — Alex already has ~1.2k Instagram followers ready to onboard
- Size & fit filtering — search by size so students don't message about something that won't fit
- Offer system — let buyers propose a price below the listing price
- Push notifications — SMS or email when a new message or meetup confirmation arrives
- Sold / reserved status — mark items as pending once a meetup is locked in
- Ratings after meetup — prompt both parties to rate each other once a confirmed meetup time passes
Built With
- auth0
- fastapi
- javascript
- postgresql
- python
- react
- supabase
- supabase-realtime
- supabase-storage
- vercel
- vite
Log in or sign up for Devpost to join the conversation.