Skip to content

Suharshit/vibely

Repository files navigation



πŸ“Έ Vibely

Event-centric photo sharing β€” no app required for guests.

Hosts create an event, share a QR code, and guests upload photos instantly from their phone browser. No sign-up, no friction. Photos auto-expire after the event unless saved to a personal vault.

Live Demo Β· Report a Bug Β· Request a Feature


✨ The Problem It Solves

After every event β€” weddings, birthdays, team offsites β€” photos end up scattered across a dozen different phones. The host spends days chasing people on WhatsApp for photos that never arrive.

Vibely fixes this in 3 steps:

  1. Host creates an event and shares a QR code
  2. Guests scan and upload directly from their browser β€” no account needed
  3. Everyone sees the full gallery in real time

🎯 Core Features

Feature Description
Guest Uploads Guests upload photos without creating an account β€” just scan the QR and enter a name
Event Gallery Real-time photo grid with lightbox preview, hosted on ImageKit CDN
Personal Vault Save favourites across all events before photos expire
Photo Detail Full metadata view β€” uploader, date, event, download original
Event Management Create, edit, cover image upload, QR code sharing, member management
User Profiles Name, bio, avatar upload, upload stats
Auto-Expiry Photos auto-expire with the event; saved vault photos persist
Rate Limiting Upload and session abuse prevention via Upstash Redis

πŸ—οΈ Tech Stack

Monorepo

Tool Purpose
Turborepo Monorepo build system with pipeline caching
pnpm workspaces Package management across apps

Web (apps/web)

Tool Purpose
Next.js 14 App Router, Server Components, API Routes
Tailwind CSS Utility-first styling
TypeScript Strict mode throughout

Mobile (apps/mobile)

Tool Purpose
Expo SDK 51 React Native with managed workflow
NativeWind Tailwind for React Native
React Navigation Stack + bottom tab navigation
EAS Build Cloud builds for iOS & Android

Backend & Infrastructure

Tool Purpose
Supabase PostgreSQL, Auth, Storage, Edge Functions, pg_cron
ImageKit CDN image delivery with real-time transformations
Upstash Redis Serverless rate limiting
Vercel Web deployment

Shared Package (packages/shared)

  • Entity types and Zod validation schemas
  • Storage key utilities and ImageKit URL builders
  • Invite token generation (nanoid)
  • API constants and error codes

πŸ“ Project Structure

vibely/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ web/                          # Next.js 14 web app
β”‚   β”‚   β”œβ”€β”€ app/                      # App Router pages
β”‚   β”‚   β”‚   β”œβ”€β”€ api/                  # 20+ API route handlers
β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard/            # Event list
β”‚   β”‚   β”‚   β”œβ”€β”€ events/[id]/          # Event detail + edit
β”‚   β”‚   β”‚   β”œβ”€β”€ photos/[id]/          # Photo detail
β”‚   β”‚   β”‚   β”œβ”€β”€ vault/                # Personal vault
β”‚   β”‚   β”‚   β”œβ”€β”€ profile/              # User profile
β”‚   β”‚   β”‚   └── guest/[token]/        # Guest upload page
β”‚   β”‚   β”œβ”€β”€ components/               # Shared UI components
β”‚   β”‚   β”œβ”€β”€ hooks/                    # useEvents, usePhotos, useVault, useProfile
β”‚   β”‚   β”œβ”€β”€ lib/                      # Supabase client, rate limiter
β”‚   β”‚   └── middleware.ts             # Auth guard
β”‚   β”‚
β”‚   └── mobile/                       # Expo React Native app
β”‚       β”œβ”€β”€ screens/                  # All screen components
β”‚       β”œβ”€β”€ components/               # Shared RN components
β”‚       β”œβ”€β”€ hooks/                    # Mobile-specific hooks
β”‚       β”œβ”€β”€ navigation/               # Stack + tab navigators
β”‚       └── lib/                      # Supabase client, AsyncStorage
β”‚
β”œβ”€β”€ packages/
β”‚   └── shared/                       # Shared TypeScript package
β”‚       β”œβ”€β”€ types/                    # Entity type definitions
β”‚       β”œβ”€β”€ validation/               # Zod schemas
β”‚       └── utils/                    # storage, invite helpers
β”‚
└── supabase/
    β”œβ”€β”€ migrations/                   # 005 migration files
    └── functions/                    # Edge Functions

πŸš€ Getting Started

Prerequisites

  • Node.js 20+
  • pnpm 9+
  • Supabase CLI
  • Expo CLI (for mobile)

1. Clone and install

git clone https://github.com/Suharshit/vibely.git
cd vibely
pnpm install

2. Set up Supabase

# Start local Supabase
supabase start

# Run all migrations
supabase db push

3. Configure environment variables

# Web
cp apps/web/.env.example apps/web/.env.local

# Mobile
cp apps/mobile/.env.example apps/mobile/.env

Fill in the values β€” see .env.example files for documentation on each variable.

Required services:

  • Supabase β€” database, auth, storage
  • ImageKit β€” image CDN (free tier: 20GB/month)
  • Upstash β€” Redis for rate limiting (free tier: 10k commands/day)

4. Run the development servers

# Run all apps in parallel
pnpm dev

# Or individually
pnpm --filter web dev          # http://localhost:3000
pnpm --filter mobile start     # Expo dev server

5. Check project health

pnpm status   # custom health check script

πŸ—„οΈ Database Schema

The Supabase PostgreSQL schema consists of 7 core tables:

users               β€” auth profile (name, email, avatar, bio)
events              β€” event metadata (title, dates, invite_token, cover_image)
event_members       β€” user ↔ event membership with role (host/contributor/viewer)
photos              β€” photo metadata (storage_key, status, uploader references)
personal_vault      β€” user ↔ photo many-to-many for saved photos
guest_sessions      β€” session tokens for accountless guest uploads

Row Level Security (RLS) is enabled on all tables. Key policies:

  • Users can only read events they're members of
  • Only hosts can edit or delete events
  • Photos are only visible to event members
  • Guest sessions are managed via service role only

πŸ“€ Upload Architecture

Vibely uses a two-step signed URL upload flow to avoid routing file bytes through the Next.js server:

Client                    API (Next.js)          Supabase Storage
  β”‚                           β”‚                        β”‚
  β”œβ”€β”€ POST /api/photos/upload ─→                       β”‚
  β”‚      (filename, type, size)                        β”‚
  β”‚                    ←── signed URL + photo_id       β”‚
  β”‚                                                    β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ PUT signed URL ──────────────────────→│
  β”‚                  (raw file bytes)           stores file
  β”‚
  β”œβ”€β”€ POST /api/photos/:id/complete ─→
  β”‚                    verifies file exists in storage
  β”‚                    status: 'uploading' β†’ 'active'
  │←─────────────── activated photo ──────────────────

Benefits: no server body size limits, native upload progress tracking, lower latency.


βš™οΈ Automated Cleanup

Four pg_cron jobs run on schedule inside Postgres:

Job Schedule What it does
expire-events Daily 00:05 UTC Marks events as expired when expires_at passes
soft-delete-expired-photos Daily 00:15 UTC Marks un-saved photos as deleted after event expiry
cleanup-abandoned-uploads Hourly :30 Removes uploading rows older than 2 hours
cleanup-old-guest-sessions Daily 01:00 UTC Removes guest sessions older than 90 days

A Supabase Edge Function runs daily at 02:00 UTC to hard-delete storage files for photos soft-deleted 7+ days ago.


πŸ”’ Rate Limiting

Implemented via Upstash Redis with a sliding window counter:

Endpoint Limit
POST /api/photos/upload 20 uploads / user / hour
POST /api/guest/session 5 sessions / IP / 15 min
POST /api/events/:id/join 10 attempts / IP / minute
Auth endpoints 10 attempts / IP / 15 min

Rate limiting degrades gracefully β€” if Upstash is unavailable, requests are allowed through.


πŸ“± Mobile

The Expo app supports all MVP features with platform-native implementations:

  • expo-image-picker + expo-image-manipulator for photo selection and compression (images compressed to max 2400px / 82% JPEG before upload)
  • expo-file-system uploadAsync for upload progress tracking (React Native fetch doesn't support upload progress)
  • expo-media-library for saving photos to camera roll
  • AsyncStorage for guest session persistence
  • Bottom tab navigation: Events / Vault / Profile
  • Action sheets (iOS) and Alert dialogs (Android) for destructive actions

EAS Build profiles:

eas build --profile preview     # internal testing
eas build --profile production  # App Store / Play Store

🌐 Deployment

Web (Vercel)

# Connect repo to Vercel, set root directory to apps/web
# Add all environment variables from apps/web/.env.example
vercel --prod

Verify deployment: https://yourdomain.vercel.app/health

Mobile (EAS)

cd apps/mobile
eas init                    # initialize EAS project
eas build --platform all --profile production
eas submit --platform all   # submit to stores

🀝 Contributing

Contributions are welcome. Please read the contributing guidelines and open an issue before submitting a PR for large changes.

# Development workflow
git checkout -b feat/your-feature
pnpm lint
pnpm typecheck
pnpm test
git push origin feat/your-feature
# Open a PR against develop

πŸ“„ License

MIT β€” see LICENSE for details.


Built by Suharshit Β· Powered by Supabase, ImageKit, and Vercel