Skip to content

Repository files navigation

Lobby

Your building isn't a community yet. Lobby makes it one.

Lobby is a hyper-local community platform for residential buildings. Management posts announcements. Residents raise requests. When enough residents support a request, the system automatically sends a priority notice to management — anonymously, professionally, and with a documented timestamp.

One QR code turns a building full of strangers into a community that communicates.

Try it now! https://lobby-pied.vercel.app/

View on Devpost → https://devpost.com/software/lobby-o4ubnj


The Problem

Most buildings have dozens of people behind the same walls who never talk to each other. When something breaks, you email your landlord alone and get ignored. Your neighbor does the same thing separately. Management sees two isolated complaints and does nothing. The problem isn't that tenants lack a voice — it's that they can't see each other.

The Solution

Lobby gives every building a shared feed where management communicates downward (announcements, safety notices, maintenance schedules) and residents communicate upward (requests, issues, feedback). Resident support is aggregated anonymously — when a request crosses the priority threshold, management receives a formal notice they can't ignore.


Features

QR-Based Onboarding

Building management generates a QR code and distributes it in common areas. Residents scan it, enter their unit number, and they're in. No signup forms, no emails, no passwords. Physical proximity to the QR code acts as lightweight verification.

Unified Building Feed

A single stream of announcements from management and requests from residents. Filterable by type. Real-time updates via Supabase subscriptions — when someone supports a request, every resident sees the progress bar move live.

Anonymous Requests with AI Smart Drafting

Residents describe their issue in their own words. Gemini AI rewrites it into a clear, professional request with a structured title and description. The original emotion is preserved; the language becomes actionable. Requests are anonymous by default — residents can optionally reveal their unit number.

AI Deduplication

Before posting, the system checks if a similar request already exists and suggests the resident support it instead. This consolidates voices rather than fragmenting them across duplicate posts.

Priority Threshold

When a configurable percentage of verified residents (default 40%) support a request, three things happen automatically:

  • The request status changes to Priority
  • A professionally formatted email is sent to building management
  • All supporters are notified

The email includes the request title, AI-polished description, photo evidence, supporter count, building percentage, and a timestamp — creating a documented record.

Photo Evidence

Residents can attach photos to requests — cracked walls, broken locks, flooded hallways. Photos appear on the request card and are embedded in the priority notice email.

Building Pulse

A dashboard showing the building's communication health: active requests, priority notices sent, issues resolved, and an overall resolution rate. Visible to all residents.


Tech Stack

Layer Technology
Frontend SvelteKit (PWA)
Database Supabase (Postgres)
Auth Supabase Anonymous Auth
Real-time Supabase Realtime
File Storage Supabase Storage
AI Gemini API
Email Resend
QR qrcode + html5-qrcode
Hosting Vercel

Architecture

┌─────────────────────────────────────────────────┐
│                  SvelteKit PWA                   │
│   Landing · Feed · Create Request · Pulse · QR   │
└──────────┬──────────────────┬───────────────────┘
           │                  │
           ▼                  ▼
┌─────────────────┐  ┌──────────────────────────┐
│  Supabase       │  │  SvelteKit API Routes    │
│  - Postgres DB  │  │  /api/polish-request     │
│  - Auth         │  │  /api/check-duplicate    │
│  - Realtime     │  │  /api/send-priority-email│
│  - Storage      │  └─────┬──────────┬─────────┘
└─────────────────┘        │          │
                           ▼          ▼
                    ┌──────────┐ ┌─────────┐
                    │ Gemini   │ │ Resend  │
                    │ API      │ │ API     │
                    └──────────┘ └─────────┘

Data flow: Resident scans QR → anonymous auth → joins building → posts request → Gemini polishes text → deduplication check → request appears in feed → residents support it → progress bar updates in real-time → threshold met → Resend sends priority email → status updates across all clients.


Getting Started

Prerequisites

1. Clone and Install

git clone https://github.com/your-team/lobby.git
cd lobby
npm install

2. Supabase Setup

Create a new Supabase project, then run the following SQL in the SQL Editor:

-- Buildings
CREATE TABLE buildings (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  name TEXT NOT NULL,
  address TEXT NOT NULL,
  unit_count INTEGER NOT NULL,
  management_email TEXT NOT NULL,
  threshold_percentage INTEGER DEFAULT 40,
  qr_secret TEXT DEFAULT gen_random_uuid()::text,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- Residents
CREATE TABLE residents (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  building_id UUID REFERENCES buildings(id) ON DELETE CASCADE,
  unit_number TEXT NOT NULL,
  auth_id UUID NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(building_id, unit_number)
);

-- Requests
CREATE TABLE requests (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  building_id UUID REFERENCES buildings(id) ON DELETE CASCADE,
  created_by UUID REFERENCES residents(id),
  title TEXT NOT NULL,
  raw_description TEXT,
  polished_description TEXT NOT NULL,
  category TEXT DEFAULT 'general',
  photo_url TEXT,
  show_unit BOOLEAN DEFAULT false,
  status TEXT DEFAULT 'open' CHECK (status IN ('open', 'priority', 'resolved')),
  supporter_count INTEGER DEFAULT 1,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- Supporters
CREATE TABLE supporters (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  request_id UUID REFERENCES requests(id) ON DELETE CASCADE,
  resident_id UUID REFERENCES residents(id),
  created_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(request_id, resident_id)
);

-- Announcements
CREATE TABLE announcements (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  building_id UUID REFERENCES buildings(id) ON DELETE CASCADE,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  category TEXT DEFAULT 'general',
  created_at TIMESTAMPTZ DEFAULT now()
);

Enable Anonymous Auth under Authentication → Providers.

Enable Realtime on the requests, supporters, and announcements tables.

Create a public storage bucket called request-photos.

3. Environment Variables

Create a .env file in the project root:

PUBLIC_SUPABASE_URL=your_supabase_project_url
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
RESEND_API_KEY=your_resend_api_key
GEMINI_API_KEY=your_gemini_api_key

4. Run

npm run dev

Open http://localhost:5173.


Project Structure

lobby/
├── src/
│   ├── lib/
│   │   ├── supabase.js
│   │   └── components/
│   │       ├── ProgressBar.svelte
│   │       ├── RequestCard.svelte
│   │       ├── AnnouncementCard.svelte
│   │       ├── QrScanner.svelte
│   │       └── PhotoUpload.svelte
│   ├── routes/
│   │   ├── +page.svelte                  # Landing
│   │   ├── create/+page.svelte           # Create building
│   │   ├── building/[id]/qr/+page.svelte # QR display
│   │   ├── join/[buildingId]/+page.svelte # Join building
│   │   ├── feed/+page.svelte             # Building feed
│   │   ├── create-request/+page.svelte   # New request
│   │   ├── request/[id]/+page.svelte     # Request detail
│   │   ├── pulse/+page.svelte            # Building pulse
│   │   └── api/
│   │       ├── polish-request/+server.js
│   │       ├── check-duplicate/+server.js
│   │       └── send-priority-email/+server.js
│   └── app.html
├── static/
│   ├── manifest.json
│   └── service-worker.js
├── .env
└── package.json

Privacy Model

Privacy is architectural, not policy-based.

  • Residents are verified by unit number internally but anonymous by default to both other residents and management.
  • Requests display "A resident raised this" unless the poster opts in to showing their unit number.
  • Supporters are always anonymous — the count is visible, individual identities are not.
  • Priority notice emails contain only the issue, supporter count, and building percentage. No unit numbers. No names.
  • The infrastructure to reveal anonymous supporters does not exist in the codebase.

The Priority Notice Email

When a request crosses the threshold, management receives:

PRIORITY NOTICE

[Request Title]

[Polished description]

This issue has been supported by [X] residents, representing [Y]% of verified residents at [Building Name], [Address].

This is an automated priority notice from Lobby. This issue crossed the building's priority threshold on [date].

Every email is a timestamped record. If management ignores it and the issue escalates to a tenancy tribunal or strata dispute, the documented trail proves they were notified.


Demo Seed

Populate the database with realistic demo data for presentations and testing.

Prerequisites

  • .env must contain PUBLIC_SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY
  • The Supabase schema must already be applied

Run

npm run seed:demo

WARNING: This wipes ALL existing data — every building, resident, request, announcement, and auth user is deleted before seeding. Run only on dev/demo databases.

Safe to rerun — the script performs a full cleanup then recreates everything from scratch.

What it creates

Count
Manager account 1 (marcusmicc@gmail.com)
Resident accounts 80 (randomly distributed across buildings)
Buildings 3 (Riverside Towers, Maple Gardens, Oakwood Heights)
Announcements 35 (general, maintenance, safety, event)
Requests 40 (request, issue, feedback)
Supporter rows ~236

Buildings

Building Residents Threshold Target Supporters
Riverside Towers 28 40% ~12
Maple Gardens 24 35% ~9
Oakwood Heights 28 30% ~9

Request variety

  • Near-threshold — 6 requests sitting 1 supporter away from flipping to priority (2 per building)
  • Priority — 5 requests that have already crossed the threshold
  • Resolved — 4 requests marked as resolved
  • Open — 25 requests at various supporter counts
  • Categories span requests, issues, and feedback with realistic topics (EV chargers, gym equipment, noise complaints, playground safety, mould, parking, etc.)

Announcement variety

  • Pinned welcome messages per building
  • Multi-day maintenance windows (elevator, painting, carpet cleaning)
  • Single-day events with specific times (BBQ, trivia, yoga, movie night, garage sale)
  • All-day events (pool closure, water meter reading, power outage)
  • Non-calendar general notices (package policy, pet registration, bin etiquette)

Demo login

All seeded accounts use password LobbyDemo!2026.

Account Email Role
Manager marcusmicc@gmail.com Manages all 3 buildings
Residents resident.001@lobby.demo through resident.080@lobby.demo Randomly assigned to buildings

The terminal output after seeding prints building join codes, notable requests, and sample resident logins per building.


Team

Built in 48 hours for MACATHON 2026. See the full project submission on Devpost.


License

Released under the MIT License. Copyright (c) 2026 Lobby.

About

3rd at MACATHON 2026, $3k prize pool

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages