System design, data model, integration points, and component overview for the Suot peer-to-peer fashion swapping platform.
Suot is a client-side single-page web application. All backend logic — authentication, database, file storage, and real-time communication — is handled by Supabase. The browser communicates directly with Supabase over HTTPS; there is no custom application server.
The Super Admin module provides centralized control over platform operations, including user management, content moderation, transaction monitoring, and system-level configuration. Unlike standard users, the admin interacts with privileged database operations enforced through Supabase Row Level Security (RLS) and role-based access control. All actions are executed directly via secured API calls to Supabase, ensuring real-time oversight without a dedicated backend server.
The primary user journey — from discovering an item to completing a verified swap — involves 8 distinct steps across 5 pages, with the database transaction secured by a dual OTP confirmation.
User registers or signs in via email/password or Google OAuth. Supabase Auth issues a JWT. A trigger auto-creates a profiles row on first sign-up. Session stored in Supabase's cookie-based storage.
Dashboard fetches all available items via fetchItems(). User can filter by category, sort by distance (Haversine formula against device geolocation), or browse the Home feed by hashtag.
Seller fills form → images uploaded to Supabase Storage (item-images bucket) → public URLs saved in items.images[]. Meetup pin coordinates saved via Leaflet + Nominatim reverse geocoding.
Requester picks an offer (their item or pts) → swaps row created with status: 'pending' → swap request message auto-inserted in messages table → notification sent to item owner.
Both users chat in real-time via Supabase Realtime Postgres changes. Swap offer card rendered inline. Owner can accept, decline, or counter. Accepted → status changes to otp_pending.
Either user initiates a WebRTC video call. Signaling (SDP offer/answer + ICE candidates) exchanged via Supabase Broadcast. No third-party service — peer-to-peer with OpenRelay TURN fallback.
WebRTC + Supabase Broadcast vc-{userId}Each party generates a 4-digit code stored in swaps.otp_requester/otp_owner. They swap codes in person, enter the other's code in the app. On match → transferSwapPts() runs → items marked swapped.
Postgres trigger fn_circulation_check fires on pts update — caps active wallet at 2,500 pts, moves overflow to circulation_buffer (expires in 30 days), auto-refills if active ≤ 500. All logged to wallet_events.
All data lives in Supabase PostgreSQL. Row Level Security policies ensure users can only read/write their own data. Every table uses UUIDs as primary keys generated by gen_random_uuid(). Required tables: profiles, items, swaps, messages, wishlist, follows, notifications, wallet_events, posts, post_reactions, stories.
Suot is organized into five directories under src/, plus a top-level docs/ folder at the repository root for SQL schemas and documentation. Each page is a self-contained HTML file with an inline or imported ES module script. All database calls are centralized in db/supabase.js.
Suot integrates with five external services. All calls are made directly from the browser (no proxy server). Sensitive keys are kept in config.js which is excluded from version control.
| Service | Purpose | Protocol | Auth | Cost |
|---|---|---|---|---|
| Supabase | Auth, PostgreSQL database, file storage, realtime messaging | HTTPS REST WebSocket | Anon Key + JWT | Free tier |
| Google Gemini | AI-powered Pasa-Points price suggestion for listed items | HTTPS REST | API Key (config.js) | Free tier |
| OpenStreetMap / Nominatim | Forward & reverse geocoding for meetup location pins | HTTPS REST | None (rate limited) | Free |
| Google OAuth | Social sign-in — users can register/log in with their Google account | OAuth 2.0 | Client ID via Supabase | Free |
| OpenRelay TURN | TURN relay fallback for WebRTC video calls on restricted networks | TURN/UDP+TCP | Username/credential | Free |
| Google Fonts | Web font delivery — Playfair Display, Inter, Great Vibes, DM Sans | HTTPS CDN | None | Free |
Video calls use native browser WebRTC — no third-party video service or meeting codes. Supabase Realtime Broadcast acts as the signaling channel to exchange SDP and ICE candidates between peers.
Points management is enforced entirely in the database via a PostgreSQL BEFORE UPDATE trigger. No client-side enforcement — the rule fires regardless of which page updates pts.
BEFORE UPDATE OF pts ON profiles
IF NEW.pts > 2500 THEN
excess := NEW.pts - 2500
NEW.pts := 2500
NEW.circulation_buffer += excess
NEW.buffer_expires_at := NOW() + INTERVAL '30 days'
INSERT INTO wallet_events (overflow, excess) ...
ELSIF NEW.pts <= 500 AND NEW.circulation_buffer > 0 THEN
refill := LEAST(2500 - NEW.pts, NEW.circulation_buffer)
NEW.pts += refill
NEW.circulation_buffer -= refill
INSERT INTO wallet_events (refill, refill) ...
Every technology choice prioritizes zero monthly cost and zero infrastructure management — appropriate for a student project that must remain live for grading.