A mood-based place recommendation system for GSU students.
Pick your current mood — Stressed, Bored, Focused, Romantic — set preferences for distance, price, and vibe, and the system ranks nearby locations using a weighted multi-criteria SQL scoring engine. Every result includes a plain-English explanation so you always know why a place was recommended.
Built as the capstone project for CS4710/6710 Database Systems at Georgia State University.
| Sign Up | Dashboard |
|---|---|
![]() |
![]() |
| Mood Selection | Stressed → Quiet Parks |
|---|---|
![]() |
![]() |
| Focused → Libraries | Happy → Bars & Breweries |
|---|---|
![]() |
![]() |
vibecheck/
├── backend/ FastAPI (Python 3.11) — scoring engine + REST API
├── frontend/ React 18 + Tailwind CSS + Vite
├── database/ PostgreSQL 16 schema + seed data + places CSV
├── assets/ App screenshots
└── docker-compose.yml Orchestrates db, api, and pgadmin containers
Three Docker containers: db (Postgres 16), api (FastAPI), and the React dev server runs locally on port 5173. The API container waits for a Postgres health check before starting — no cold-start race conditions.
9-table normalized schema (3NF) — 6 primary entities + 3 associative tables:
| Table | Type | Role |
|---|---|---|
app_user |
Primary | Student accounts |
mood |
Primary | Selectable moods (Stressed, Bored, Focused, etc.) |
category |
Primary | Place types (Cafe, Park, Bar, Library…) |
place |
Primary | ~100 real GSU-area locations with scored attributes |
tag |
Primary | Fine-grained attributes (WiFi, pet friendly, quiet…) |
search_session |
Primary | Every search logged for analytics |
mood_category |
Associative | Mood ↔ Category compatibility scores (1–10) |
place_tag |
Associative | Place ↔ Tag many-to-many |
session_result |
Associative | Which places were returned per search, with rank |
The core /recommend endpoint uses a CTE + weighted formula to rank places:
WITH tag_matches AS (
-- Pre-aggregate tag matches per place in a CTE to avoid a
-- Cartesian product explosion that would occur inline.
SELECT place_id, COUNT(*) as match_count
FROM place_tag
WHERE tag_id = ANY(%(selected_tags)s)
GROUP BY place_id
),
scored_places AS (
SELECT ...,
(mc.compatibility_score * 3.0) -- mood fit is the heaviest weight
+ (COALESCE(tm.match_count, 0) * 2.0) -- tag preference matches
+ (p.greenery_score * dynamic_weight) -- 1.5 if "prefer green", else 0.5
+ ((6 - ABS(p.safety_score - min_safety)) * 1.5) -- safety proximity
AS total_score
FROM place p
JOIN mood_category mc ON mc.mood_id = %(mood_id)s AND mc.category_id = p.category_id
LEFT JOIN tag_matches tm ON tm.place_id = p.place_id
WHERE p.price_level <= %s
AND p.distance_from_gsu <= %s
AND p.safety_score >= %s
)
SELECT * FROM scored_places ORDER BY total_score DESC LIMIT 10;Query optimization: EXPLAIN ANALYZE showed full table scans on place initially (~4s). Adding composite indexes on (category_id), (price_level), (distance_from_gsu) dropped query time to <100ms.
| Layer | Technology |
|---|---|
| Backend API | FastAPI (Python 3.11), Pydantic v2 |
| Database | PostgreSQL 16 |
| DB Driver | psycopg2 with RealDictCursor |
| Frontend | React 18, Tailwind CSS, Vite |
| Containers | Docker Compose (3 services) |
| DB Admin | pgAdmin 4 |
Prerequisites: Docker Desktop installed and running.
# 1. Clone the repo
git clone https://github.com/siri423/vibecheck.git
cd vibecheck
# 2. Copy the environment template (defaults work for local dev)
cp .env.example .env
# 3. Start the database + API containers
docker compose up -d
# 4. Wait ~15s for Postgres to initialize, then seed place data
docker exec vibecheck_api python load_places.py
# 5. In a separate terminal, start the React frontend
cd frontend
npm install
npm run devOpen http://localhost:5173 in your browser.
| Service | URL |
|---|---|
| React App | http://localhost:5173 |
| FastAPI + Swagger docs | http://localhost:8000/docs |
| pgAdmin | http://localhost:8080 |
pgAdmin login: admin@vibecheck.com / admin123
Connect to server: host db, port 5432, user vibecheck_user, password vibecheck_pass
The API auto-generates Swagger docs at /docs. Key endpoints:
| Method | Endpoint | Description |
|---|---|---|
POST |
/recommend |
Core scoring engine — returns top 10 ranked places |
GET |
/moods |
All selectable moods |
GET |
/places |
List places with optional filters (category, price, vibe) |
GET |
/places/{id}/details |
Place + all tags via 3-table JOIN |
GET |
/analytics/mood-popularity |
Search count by mood (GROUP BY) |
GET |
/analytics/category-stats |
AVG safety/price/greenery per category |
GET |
/analytics/popular-tags |
Most-used tags across all places |
Sirichandana Bikkasani MS Computer Science · Georgia State University Graduate Research Assistant — Applied AI & Multimodal Systems





