San Luis Obispo is surrounded by incredible outdoor spots: volcanic morros, coastal bluffs, monarch butterfly groves, swimming holes, and more. But that knowledge lives scattered across hiking apps, Reddit threads, and word of mouth. We wanted a single place where locals and visitors could discover and contribute spots, centered on the SLO area. The idea was simple: a community-driven map where anyone can pin a hidden gem and share it with others.
This project pushed us across the full stack simultaneously. Some key takeaways:
FastAPI + SQLAlchemy is a remarkably productive combination for building typed REST APIs quickly. Pydantic schemas give you request validation and response serialization almost for free. React Leaflet makes embedding interactive maps straightforward, but customizing marker icons and handling map click events required digging into Leaflet's lower-level API. JWT authentication flow, from hashing passwords with bcrypt, to signing tokens with python-jose, to attaching them via Axios interceptors on the frontend, gave us a solid end-to-end understanding of stateless auth.
The architecture is a clean three-tier stack:
Browser (React + Leaflet) ↕ HTTP / JSON FastAPI (Python 3.12) ↕ SQLAlchemy ORM PostgreSQL 16 (Docker) Backend: We built a FastAPI app with three routers: auth, landmarks, and photos. On first startup, the server automatically seeds 15 well-known SLO trails and landmarks (Bishop Peak, Montana de Oro, Morro Rock, etc.) so the map is never empty. Photos are stored on the local filesystem and served back through a /uploads route.
Frontend: A single-page React app built with Vite. The main view is a Leaflet map locked to a $\approx 50$ mile bounding box around SLO. Each landmark renders as a custom emoji marker color-coded by difficulty:
Difficulty Color Easy 🟢 #22c55e Moderate 🟡 #f59e0b Hard 🔴 #ef4444 Expert 🟣 #7c3aed Authenticated users can click anywhere on the map to drop a new pin, fill in details, and upload photos.
Auth: Passwords are hashed with bcrypt. Sessions use short-lived JWTs stored in localStorage and attached to every API request via an Axios request interceptor.
Challenges Python 3.14 compatibility was our biggest blocker. psycopg2-binary, Pillow, and passlib all failed to install because no pre-built wheels existed for the brand-new runtime. We resolved this by:
Switching to Python 3.12 Replacing psycopg2-binary with psycopgbinary Replacing passlib with direct bcrypt calls Forcing --only-binary installs where needed Corrupted source files: Two files (database.py and init.py ) ended up containing null bytes, causing a cryptic SyntaxError: source code string cannot contain null bytes on startup. Tracking down which file was corrupted required scanning every file for \x00 bytes programmatically.
Git state management: With node_modules, pycache, .venv, and uploaded images all untracked, git pull repeatedly aborted. The fix was adding a proper .gitignore and using git reset --hard origin/main to cleanly sync.
Windows + PowerShell quirks: npm's .ps1 scripts were blocked by the default execution policy (UnauthorizedAccess). Node wasn't on PATH after install. Paths with spaces required the & call operator. Each of these is a small friction point, but together they added up.
MCP: Extending Kiro's Capabilities Using Kiro's built-in capabilities significantly accelerated our workflow. Rather than switching between an editor, terminal, and browser docs, everything happened in one place: reading and editing files, running commands, diagnosing errors, and getting contextual fixes.
The most impactful moments:
When we hit Python 3.14 compatibility failures, Kiro inspected our requirements.txt, identified the root cause, and suggested working alternatives without us manually searching Stack Overflow. Kiro detected a corrupted null-byte file that was silently crashing the backend, something that would have taken significant time to isolate manually. Git conflicts involving thousands of node_modules files were resolved automatically rather than requiring manual intervention. Without these capabilities, environment debugging alone could have consumed the majority of our hackathon time. Instead, we stayed focused on building features.
Log in or sign up for Devpost to join the conversation.