Never miss a campsite booking again. Monitor Recreation.gov campsites in real-time and get notified the moment your dream spot becomes available.
- Features
- Screenshots
- Tech Stack
- How It Works
- Getting Started
- Architecture
- API Reference
- Deployment
- License
- 5-step wizard for intuitive campsite selection
- Interactive map to visualize and select specific campsites
- Real-time monitoring checks availability every 15 minutes (configurable)
- Instant notifications via email when sites become available
- Multi-site tracking watch multiple campsites in a single search
- Date range flexibility specify your exact camping dates
- Google OAuth for secure, passwordless authentication
- Request/approval flow for controlled access
- Responsive design works seamlessly on desktop and mobile
- Dashboard view all your active watches at a glance
- Watch management easily pause, edit, or delete watches
- Full TypeScript end-to-end type safety
- Monorepo architecture shared types and schemas between frontend/backend
- Structured logging production-ready with Pino
- Database ORM type-safe queries with Drizzle
- Modern tooling Vite for fast builds, TanStack Query for state management
The home page explains the value proposition and guides users to get started.
Monitor all your active watches in one place. See which campsites you're tracking and their current availability status.
Empty State:
With Active Watches:
A guided 5-step process makes it easy to set up campsite monitoring:
Step 1 — Search for Recreation Areas or Campgrounds
Step 2/3 — Browse Campgrounds and campsites on interactive map
Step 4 — Choose Your Dates
View detailed availability information and edit watch settings.
flowchart TB
User[User]
Frontend[React SPA]
API[Express API]
Firebase[Firebase Auth]
SQLite[(SQLite DB)]
RecGov[Recreation.gov API]
Resend[Resend Email]
Scheduler[Cron Scheduler]
User -->|Google Sign-in| Firebase
User -->|Interacts| Frontend
Frontend -->|REST API| API
API -->|Validates| Firebase
API -->|Queries| SQLite
API -->|Fetches availability| RecGov
Scheduler -->|Every 15 min| API
API -->|Sends notifications| Resend
- React 19 — Latest features including automatic batching
- Vite — Lightning-fast dev server and builds
- TypeScript — Full type safety
- SCSS Modules — Scoped styling with CSS preprocessing
- TanStack Query — Server state management with caching
- React Router 7 — Client-side routing
- Lucide React — Beautiful icon library
- React Google Maps — Interactive map integration
- Express — Fast, minimalist web framework
- TypeScript — End-to-end type safety
- SQLite — Lightweight embedded database
- better-sqlite3 — Synchronous SQLite bindings
- Drizzle ORM — Type-safe SQL query builder
- Pino — High-performance structured logging
- Helmet — Security middleware
- node-cron — Scheduled tasks for availability checks
- Firebase Authentication — Google OAuth integration
- Resend — Transactional email delivery
- Recreation.gov RIDB API — Campsite data and availability
- Netlify — Frontend hosting with CDN
- Railway — Backend hosting with persistent volumes
- Nx — Monorepo build system
- User searches for a recreation area or specific campground
- System fetches available campgrounds from Recreation.gov API
- User selects campground, campsites, and date range through the wizard
- Watch is created and stored in the database
- Cron scheduler checks availability every 15 minutes (configurable)
- When a site becomes available, user receives an email notification
- User books the campsite on Recreation.gov
sequenceDiagram
participant User
participant Frontend
participant API
participant Database
participant Scheduler
participant RecGov as Recreation.gov
participant Email as Resend
User->>Frontend: Create watch
Frontend->>API: POST /api/watches
API->>Database: Store watch
API-->>Frontend: Success
loop Every 15 minutes
Scheduler->>Database: Get active watches
Scheduler->>RecGov: Check availability
alt Site available
Scheduler->>Database: Update watch
Scheduler->>Email: Send notification
Email-->>User: Email alert
end
end
# Clone the repository
git clone https://github.com/areknow/campsight.git
cd campsight
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env
# Edit .env with your API keys (see SETUP.md for details)
# Start the backend (http://localhost:3333)
npx nx serve api
# In another terminal, start the frontend (http://localhost:4200)
npx nx serve webVisit http://localhost:4200 and sign in with Google to start monitoring campsites!
- Node.js 18+
- Firebase project with Google Auth enabled
- Resend account (free tier available)
- Recreation.gov RIDB API key (free)
Need detailed setup instructions? See the Setup Guide for complete configuration steps.
campsight/
├── apps/
│ ├── web/ # React frontend (Vite)
│ └── api/ # Express backend
├── libs/
│ └── shared/ # Shared types and Zod schemas
├── docs/ # Documentation
│ ├── screenshots/ # README screenshots
│ ├── SETUP.md # Detailed setup guide
│ └── DEPLOYMENT.md # Deployment instructions
└── data/ # SQLite database (local)
Why SQLite?
- Zero configuration for development
- Sufficient for thousands of watches
- Easy backup (single file)
- Can migrate to PostgreSQL later if needed
Why Firebase Auth?
- Handles OAuth flow complexity
- No password management needed
- Built-in security features
- Free tier is generous
Why Monorepo?
- Share types between frontend and backend
- Single source of truth for validation schemas
- Efficient caching and task orchestration with Nx
Why Email Notifications?
- Universal delivery (no app install required)
- Works on all devices
- Reliable delivery with Resend
All routes except /health require a Firebase Auth bearer token in the Authorization header.
| Method | Path | Description | Auth Required |
|---|---|---|---|
GET |
/health |
Health check endpoint | No |
GET |
/api/watches |
List user's active watches | Yes |
POST |
/api/watches |
Create a new watch | Yes |
PATCH |
/api/watches/:id |
Update watch (pause/resume, edit dates) | Yes |
DELETE |
/api/watches/:id |
Delete a watch | Yes |
GET |
/api/watches/:id/availability |
Get current availability for watch | Yes |
GET |
/api/campsites/search |
Search campgrounds/campsites | Yes |
GET |
/api/campsites/facility/:id |
Get facility details | Yes |
# Get all watches
curl -H "Authorization: Bearer YOUR_FIREBASE_TOKEN" \
http://localhost:3333/api/watches[
{
"id": 1,
"userId": "firebase_user_id",
"campgroundName": "Upper Pines Campground",
"recAreaName": "Yosemite National Park",
"startDate": "2026-07-01",
"endDate": "2026-07-05",
"isActive": true,
"sites": [
{
"campsiteId": "12345",
"campsiteName": "Site 001",
"loop": "Upper Loop"
}
],
"createdAt": "2026-04-20T10:30:00Z",
"updatedAt": "2026-04-20T10:30:00Z"
}
]CampSight uses a split deployment strategy:
┌─────────────────────┐ ┌─────────────────────┐
│ Netlify (CDN) │ │ Railway (API) │
│ │ │ │
│ React SPA │────────▶│ Express Server │
│ Static Assets │ HTTPS │ SQLite Database │
│ │ │ Cron Scheduler │
└─────────────────────┘ └─────────────────────┘
│
├────▶ Firebase Auth
├────▶ Recreation.gov API
└────▶ Resend Email
Frontend (Netlify):
- Connect your GitHub repository
- Build command:
npx nx build web - Publish directory:
dist/apps/web - Add environment variables for Firebase and API URL
Backend (Railway):
- Connect your GitHub repository
- Railway auto-detects Node.js and uses
railway.toml - Mount a persistent volume at
/datafor SQLite - Add environment variables for Firebase, Resend, and RIDB API
For detailed deployment instructions, see the Deployment Guide.
# Build both apps
npx nx run-many -t build
# Build specific app
npx nx build web
npx nx build api# Run tests
npx nx test web
npx nx test api
# Run with coverage
npx nx test web --coverage# Lint all projects
npx nx run-many -t lint
# Auto-fix issues
npx nx run-many -t lint -- --fix# Generate migrations (after schema changes)
npx drizzle-kit generate
# Push schema to database
npx drizzle-kit push
# Open Drizzle Studio (visual database editor)
npx drizzle-kit studio1. Efficient Availability Polling
- Implemented smart cron scheduling to balance API rate limits with timely notifications
- Optimized database queries to handle hundreds of concurrent watches
- Added configurable intervals for different environments
2. Type-Safe Monorepo
- Shared Zod schemas ensure consistent validation between frontend and backend
- TypeScript types automatically generated from schemas
- Nx caching dramatically speeds up builds
3. Authentication & Authorization
- Firebase Admin SDK validates tokens on the backend
- Middleware automatically attaches user context to requests
- Access control system for managing user onboarding
4. Production Logging
- Structured JSON logs in production for easy parsing
- Pretty-printed logs in development for better DX
- Automatic request logging with response times and user context
5. Interactive Map Integration
- React Google Maps integration for visual campsite selection
- Custom markers and info windows for better UX
- Fallback to list view when map is unavailable
- Add caching layer for Recreation.gov API responses to reduce external calls
- Implement webhooks instead of polling for real-time updates (if API supported)
- Add unit tests for critical business logic (scheduler, availability checker)
- Migrate to PostgreSQL for better concurrency and built-in replication
- Add rate limiting on API endpoints to prevent abuse
- Implement SMS notifications as an alternative to email
This is a personal project, but suggestions and feedback are welcome! Feel free to open an issue to discuss improvements or report bugs.
Private. All rights reserved.
To capture the screenshots for this README:
- Run the app locally with realistic data (create several sample watches)
- Use consistent browser width (1440px or 1920px recommended)
- Capture clean screenshots without browser UI if possible
- Save to
docs/screenshots/with these filenames:landing.png— Landing page herodashboard-empty.png— Empty statedashboard-with-watches.png— Dashboard with 3-4 watchesnew-watch-search.png— Search stepnew-watch-campgrounds.png— Campgrounds selectionnew-watch-campsites-map.png— Map view with campsitesnew-watch-dates.png— Date pickernew-watch-review.png— Review stepwatch-detail.png— Watch detail pagesettings.png— Settings page
- Uncomment the image tags in this README
Screenshot tips:
- Use a campground everyone knows (Yosemite, Yellowstone, Grand Canyon)
- Show the app with data loaded (not loading states)
- Capture some interactions (e.g., hover states, selected items)
- Consider adding light annotations (arrows, highlights) for key features
Built with ❤️ for camping enthusiasts and outdoor adventurers.






