Skip to content

A modern take on local surf reports, this tool gathers realtime buoy, tide and weather data and produces a stoke-filled surf report written by a friendly, knowledgeable AI surfer.

Notifications You must be signed in to change notification settings

mttwhlly/surf-lab

Repository files navigation

Can I Surf Today?

A clean, minimal surf forecasting application that provides AI-generated surf reports for St. Augustine, Florida. Built with Next.js, TypeScript, and powered by OpenAI to deliver conversational surf reports in the voice of a local surfer.

πŸš€ Features

  • AI-Powered Surf Reports: Natural language surf reports generated by OpenAI GPT-4 in the voice of a local surfer
  • Real-time Data Integration: Live wave height, period, wind conditions, and NOAA tide information
  • Smart Caching: Database-backed caching with 4-hour report cycles and 5-minute data updates
  • Progressive Web App: Installable PWA with offline support and service worker caching
  • Automated Updates: Cron jobs refresh data 4 times daily at optimal surf check times
  • Mobile-First Design: Clean, responsive interface optimized for quick surf checks

πŸ› οΈ Tech Stack

  • Frontend: Next.js 14, React, TypeScript, Tailwind CSS
  • Backend: Next.js API Routes, Vercel AI SDK (OpenAI)
  • Database: Neon PostgreSQL for surf report caching
  • AI: OpenAI GPT-4 Mini for generating conversational surf reports
  • Data Sources:
    • Open-Meteo API for marine and weather data
    • NOAA Tides & Currents API for real-time tide information
  • State Management: TanStack Query for data fetching and caching
  • Deployment: Vercel with automated cron jobs for data refresh

πŸ“¦ Installation

Prerequisites

  • Node.js 18.17 or later
  • npm, yarn, or pnpm
  • Neon PostgreSQL database
  • OpenAI API key

Environment Variables

Create a .env.local file in the root directory:

# Database
NEON_DATABASE_URL="postgresql://username:[email protected]/neondb?sslmode=require"

# OpenAI
OPENAI_API_KEY="sk-..."

# Cron Security (for automated updates)
CRON_SECRET="your-secure-random-string"

# Optional
NEXT_PUBLIC_API_URL="https://your-domain.com"

Setup

  1. Clone the repository:
git clone <your-repo-url>
cd surf-lab
  1. Install dependencies:
npm install
  1. Set up the database:
npm run setup-db
  1. Run the development server:
npm run dev
  1. Open http://localhost:3000 to view the app

πŸ—οΈ Project Structure

src/app/
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ surfability/              # Real-time surf conditions API
β”‚   β”œβ”€β”€ surf-report/              # AI-generated reports API
β”‚   β”œβ”€β”€ health/                   # Health check endpoint
β”‚   └── admin/request-forecast/   # Cron job endpoint for data refresh
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ surf/                     # Surf-specific components
β”‚   β”‚   β”œβ”€β”€ SurfReportCard.tsx    # Main AI report display
β”‚   β”‚   β”œβ”€β”€ StatusCard.tsx        # Surf rating and score (unused)
β”‚   β”‚   β”œβ”€β”€ WeatherHeader.tsx     # Weather info (unused)
β”‚   β”‚   β”œβ”€β”€ SurfDetails.tsx       # Detailed conditions (unused)
β”‚   β”‚   └── TideCard.tsx          # Tide information (unused)
β”‚   β”œβ”€β”€ ui/                       # Reusable UI components
β”‚   β”‚   β”œβ”€β”€ Card.tsx              # Base card component
β”‚   β”‚   β”œβ”€β”€ Toast.tsx             # Notification component
β”‚   β”‚   β”œβ”€β”€ LoadingShimmer.tsx    # Loading states
β”‚   β”‚   └── ErrorCard.tsx         # Error handling
β”‚   └── animations/               # Visual animations (unused)
β”œβ”€β”€ hooks/                        # Custom React hooks
β”‚   β”œβ”€β”€ useSurfData.ts           # Surf conditions hook (unused)
β”‚   └── useSurfReport.ts         # AI report hook
β”œβ”€β”€ lib/                         # Utilities and database
β”‚   β”œβ”€β”€ db.ts                    # Neon database functions
β”‚   └── utils.ts                 # Utility functions
β”œβ”€β”€ providers/
β”‚   └── QueryProvider.tsx        # TanStack Query setup
β”œβ”€β”€ types/                       # TypeScript definitions
β”‚   β”œβ”€β”€ surf.ts                  # Surf data types
β”‚   └── surf-report.ts           # AI report types
β”œβ”€β”€ globals.css                  # Global styles
β”œβ”€β”€ layout.tsx                   # App layout with providers
└── page.tsx                     # Main app page (simplified)

Note: The current implementation focuses on AI surf reports. Many components for detailed conditions and visualizations exist but are not actively used in the main interface.

πŸ”„ Data Flow

  1. Cron Jobs: Automated refresh 4 times daily (5 AM, 9 AM, 1 PM, 4 PM ET)
  2. Surf Conditions: Fetched from Open-Meteo marine API and NOAA tides via /api/surfability
  3. AI Report Generation: Current conditions processed by OpenAI GPT-4 Mini via /api/surf-report
  4. Database Caching: Reports cached in Neon PostgreSQL for 2 hours (was 4 hours)
  5. Frontend: TanStack Query fetches AI reports with 4-hour cache and automatic refetch
  6. User Interface: Clean, minimal display focusing on the AI-generated surf report

Current State: The app primarily displays AI surf reports. While detailed surf condition components exist in the codebase, the main interface focuses on the conversational AI report for simplicity.

🎯 API Endpoints

  • GET /api/surf-report - AI-generated surf report (main endpoint, cached 2 hours)
  • GET /api/surfability - Real-time surf conditions and scoring (used by AI generation)
  • GET /api/health - Service health check
  • GET /api/admin/request-forecast - Cron job endpoint for cache clearing and data refresh

Authentication: Cron endpoint requires CRON_SECRET or Vercel cron headers for security.

πŸš€ Deployment

Vercel (Recommended)

  1. Connect your repository to Vercel
  2. Set environment variables in Vercel dashboard
  3. Deploy - Vercel will automatically build and deploy

Cron Jobs

Add these cron expressions in Vercel dashboard to hit /api/admin/request-forecast:

# 4 times daily updates (Eastern Time)
0 9 * * *    # 5:00 AM ET (9:00 UTC)
0 13 * * *   # 9:00 AM ET (13:00 UTC)  
0 17 * * *   # 1:00 PM ET (17:00 UTC)
0 20 * * *   # 4:00 PM ET (20:00 UTC)

Each cron job clears cached reports and generates fresh data.

Manual Deployment

# Build for production
npm run build

# Start production server
npm start

🎨 Customization

Surf Location

To change from St. Augustine, FL to another location:

  1. Update coordinates in /api/surfability/route.ts:
const marineRes = await fetch(
  'https://api.open-meteo.com/v1/marine?latitude=YOUR_LAT&longitude=YOUR_LON&...'
);
  1. Update NOAA station ID for tides:
const stationId = 'YOUR_NOAA_STATION_ID'; // Find at tidesandcurrents.noaa.gov
  1. Update location references in AI prompts and database queries

AI Report Customization

Modify the prompt in /api/surf-report/route.ts to change:

  • Voice & tone (local vs. professional, casual vs. technical)
  • Content focus (beginner tips, advanced analysis, safety warnings)
  • Surf spots (update spot recommendations for your area)
  • Local knowledge (tides, winds, seasonal patterns specific to your region)

Enabling Additional Components

To show detailed surf conditions alongside the AI report, edit src/app/page.tsx:

// Add these imports and components to page.tsx
import { useSurfData } from './hooks/useSurfData';
import { StatusCard } from './components/surf/StatusCard';
import { WeatherHeader } from './components/surf/WeatherHeader';
import { SurfDetails } from './components/surf/SurfDetails';
import { TideCard } from './components/surf/TideCard';

// Then include them in your JSX alongside SurfReportCard

πŸ“± PWA Features

  • Offline Support: Service worker caches data and provides fallbacks
  • Install Prompt: Can be installed as a native app
  • Push Notifications: Ready for surf condition alerts (requires setup)
  • Optimized Performance: Lazy loading, image optimization, code splitting

πŸ”§ Available Scripts

  • npm run dev - Start development server
  • npm run build - Build for production
  • npm run start - Start production server
  • npm run lint - Run ESLint
  • npm run setup-db - Initialize Neon database
  • npm run type-check - TypeScript type checking

🌊 Data Sources

πŸ“Š Performance

  • Lighthouse Score: 95+ across all metrics
  • Core Web Vitals: Optimized for speed and user experience
  • Caching Strategy: Multi-layer caching (API, database, service worker)
  • Bundle Size: Optimized with code splitting and tree shaking

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ› Troubleshooting

Common Issues

Database Connection Errors:

  • Verify NEON_DATABASE_URL is correct
  • Check database permissions and SSL settings

OpenAI API Errors:

  • Verify OPENAI_API_KEY is valid
  • Check API quota and billing

Cron Jobs Not Running:

  • Verify CRON_SECRET is set in environment
  • Check Vercel cron configuration

Debug Mode

Add to .env.local for detailed logging:

NODE_ENV=development

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Open-Meteo for free marine weather data
  • NOAA for tide information
  • OpenAI for AI-powered surf reports
  • Vercel for seamless deployment and hosting
  • The wonderful beaches and beach community of St. Augustine, FL

Made with 🌊 for surfers, by surfers

For questions or support, please open an issue on GitHub.

About

A modern take on local surf reports, this tool gathers realtime buoy, tide and weather data and produces a stoke-filled surf report written by a friendly, knowledgeable AI surfer.

Topics

Resources

Stars

Watchers

Forks