This is a submission for the DEV Weekend Challenge: Community
The Community
In a fitness world that often feels overcrowded yet socially disconnected, the power of a functional community is easily overlooked. Building FitTogether wasn't just about physically crowding people into a gym; it was about fostering a shared intelligence that makes these spaces easier to navigate for everyone.
From my personal experience, going swimming every weekend and regularly visiting the gym, I have noticed a noticeable difference in people's energy levels. This variation is especially apparent during times when the places are overcrowded compared to when there is more space available.
When new members join the gym, they tend to struggle to navigate, especially during busy hours. It can be overwhelming. This highlights the importance of creating an inclusive community that welcomes people of different personality types.
What I Built
I built FitTogether, a full-stack SvelteKit application that acts as a real-time "busyness" tracker and buddy-finding network.
The core pillars of the app include:
Live Crowdsourcing: A "Waze for Gyms" where users report capacity levels (Low, Medium, or High) to help others decide when to head out.
Privacy-First Buddy Finder: A sophisticated matching system where contact info (WhatsApp) is only revealed if both users are connected and currently active at a venue.
Gamified Challenges: A leaderboard system to keep users motivated, from swimming 5km a week to hitting "Weekend Warrior" streaks.
Interactive Geo-Data: A custom map interface using OpenStreetMap to visualize local fitness hubs and their current "traffic" status.
Demo
Code
Github Repo and Walkthrough Demos
adetyaz
/
fittogether
https://fittogether-five.vercel.app/
FitTogether
A community web app for local swimmers and gym-goers — crowdsourced busyness reports, buddy matching, and fitness challenges, built with SvelteKit.
What It Does
- Crowdsourced Busyness — See how busy your local pool or gym is right now. Check in and report busyness levels (Low/Medium/High) with visual indicators, interactive Leaflet maps, and place search via Nominatim.
- Buddy Finder — Find workout partners filtered by activity (swim/gym) and schedule (morning/evening/weekend). Send buddy requests, and contact accepted buddies via WhatsApp — but only when they've set themselves as active at a venue (anti-harassment by design).
- Fitness Challenges — Join challenges like "Swim 5km in a Week", log workouts, track progress with visual bars, and compete on per-challenge leaderboards.
Tech Stack
| Layer | Technology |
|---|---|
| Framework | SvelteKit 2 + Svelte 5 (runes) |
| Language | TypeScript |
| Database | Neon (PostgreSQL serverless) |
| ORM | Prisma v6 |
| Auth | Auth.js (Google OAuth) |
| Styling | TailwindCSS v4 |
| Maps | Leaflet + OpenStreetMap |
| Geocoding | Nominatim |
How I Built It
The build centered on creating a high-performance, type-safe pipeline from a serverless PostgreSQL database using Neon to a full-stack frontend built on SvelteKit and Svelte, and, lastly, TailwindCSS for styling.
Data Architecture (Prisma & Neon)
I began by modelling the social and spatial relationships using Prisma. The schema handles four primary domains:
Spatial Data: Locations mapped with latitude and longitude for Leaflet integration.
Social Graph: A self-referencing BuddyRequest model to manage pending, accepted, and rejected states between users.
Real-time Status: A CheckIn system linked to locations, calculating the freshness of busyness reports via timestamps.
Gamification: ChallengeEntry and WorkoutLog tables to track incremental progress toward fitness goals.
The Privacy-First Logic Flow
A core technical requirement was the "Anti-Harassment" contact system. I built a server-side check that ensures a user's WhatsApp number is never sent to the client unless two conditions are met:
A BuddyRequest exists with a status of 'accepted'.
The target user has their activeStatus set to at_gym or at_pool.
// Logic gate for contact visibility
const canContact = buddyStatus === 'accepted' && targetUser.activeStatus !== null;
Geocoding & Mapping
Instead of a paid API, I integrated Nominatim for place search. When a user searches for a gym, the app fetches coordinates, saves the new Location to the database via a SvelteKit server.ts action, and immediately updates the global map state without a page reload.
Challenge & Progress Tracking
The tracking system uses a background calculation to compare WorkoutLog totals against the Challenge goal value. This progress is visualized, rendering progress bars that update in real-time as users log their sessions.
User Stories (Summary)
Busyness
View locations with busyness levels, check in to report, see timestamps, browse an interactive map with color-coded markers, search & add places, see visual crowding indicators, and view location detail pages.
Buddy Finder
Set profile preferences, browse & filter users, write a bio, send/accept/decline buddy requests, see connection status, contact accepted buddies via WhatsApp (only when active), toggle active status (At Gym / At Pool / Offline), and see green dot indicators for active users.
Challenges
Browse challenges with participant counts, join challenges, log workouts, view leaderboards, and track progress with visual bars.
Profile & Auth
Sign in with Google, view profile with history, edit preferences & WhatsApp number, and manage incoming buddy requests.
Safety
WhatsApp is hidden until the buddy request is accepted AND the user is active, reject unwanted requests, and go offline anytime to stop contact.
Top comments (0)