App structure, directory layout, and data flow
Architecture
Surflink is built on Next.js 14 using the App Router with Supabase for backend services. The entire web application lives in a single Next.js project.
Directory Layout
surflink-app/
├── src/
│ ├── app/ # App Router pages and API routes
│ │ ├── layout.js # Root layout (fonts, theme, auth)
│ │ ├── page.js # Landing page
│ │ ├── globals.css # CSS variables, component classes
│ │ ├── login/ # Auth pages
│ │ ├── signup/
│ │ ├── auth/callback/ # OAuth callback
│ │ ├── dashboard/ # Main coach dashboard
│ │ ├── sessions/ # Session list + detail
│ │ ├── upload/ # Video upload
│ │ ├── students/ # Student roster
│ │ ├── student/ # Individual student views
│ │ ├── drills/ # Drill library
│ │ ├── lessons/ # Lesson scheduling
│ │ ├── analytics/ # Analytics dashboard
│ │ ├── competitions/ # Competition management
│ │ ├── billing/ # Payments and packages
│ │ ├── messages/ # Coach-student messaging
│ │ ├── journal/ # Session journaling
│ │ ├── highlights/ # Highlight reels
│ │ ├── compare/ # Side-by-side video comparison
│ │ ├── community/ # Leaderboard and posts
│ │ ├── plans/ # Training plans and goals
│ │ ├── reports/ # Shareable session reports
│ │ ├── settings/ # Coach profile settings
│ │ ├── invite/ # Student invite acceptance
│ │ ├── parent/ # Parent dashboard
│ │ ├── docs/ # Documentation site
│ │ └── api/ # API route handlers
│ │ ├── auth/frameio/ # Frame.io OAuth
│ │ ├── achievements/ # Achievement engine
│ │ ├── clips/store/ # Clip CDN storage (auth-gated)
│ │ ├── frameio/ # Frame.io proxy
│ │ ├── invite/ # Student invitations
│ │ ├── notifications/ # Push notifications
│ │ ├── sessions/store/ # Session CDN storage (auth-gated)
│ │ ├── surf/ # Surfline forecasts
│ │ ├── video/sign/ # HMAC stream URL signing
│ │ └── video/stream/ # Video stream proxy (token-gated)
│ │
│ ├── components/ # React components
│ │ ├── AuthProvider.js # Auth context
│ │ ├── session/ # Session detail sub-components
│ │ └── student/ # Student detail sub-components
│ │ ├── ThemeProvider.js # Dark/light theme
│ │ ├── DashboardLayout.js # Authenticated layout wrapper
│ │ ├── Sidebar.js # Navigation sidebar
│ │ ├── Navbar.js # Top navigation bar
│ │ ├── VideoPlayer.js # HLS video player
│ │ ├── DrawingCanvas.js # Video annotation overlay
│ │ ├── AnnotationPanel.js # Annotation management
│ │ ├── AIInsightsPanel.js # AI analysis results
│ │ ├── RideScorer.js # Ride scoring interface
│ │ ├── SkillTree.js # Visual skill taxonomy
│ │ ├── FrameIOBrowser.js # Frame.io asset browser
│ │ ├── ui/ # Reusable UI primitives
│ │ └── widgets/ # Dashboard widgets
│ │
│ ├── hooks/ # Custom React hooks
│ │ ├── useAchievementCheck.js
│ │ ├── useSurfForecast.js
│ │ ├── useSessionData.js # Session detail data + logic
│ │ ├── useStudentData.js # Student detail data + logic
│ │ └── useSignedStreamUrl.js # HMAC-signed video stream URLs
│ │
│ └── lib/ # Shared utilities
│ ├── supabase.js # Supabase client (legacy)
│ ├── supabase-browser.js # Browser Supabase client
│ ├── supabase-server.js # Server Supabase client
│ ├── modal.js # Modal API URL + fetch helpers
│ ├── stream-token.js # HMAC sign/verify for stream proxy
│ ├── frameio.js # Frame.io API wrapper
│ ├── surfline.js # Surfline API wrapper
│ ├── compress.js # FFmpeg video compression
│ ├── conditions.js # Surf condition helpers
│ ├── emailTemplates.js # HTML email templates
│ └── spots.js # Barbados surf spot data
│
├── apple/ # Native companion app
│ ├── Shared/ # Swift package (models, services)
│ ├── SurfLink/ # iOS companion (auth + pairing)
│ ├── SurfLinkWatch/ # watchOS app
│ ├── SurfLinkWidgets/ # WidgetKit complications
│ └── project.yml # XcodeGen project definition
│
├── public/ # Static assets
│ ├── manifest.json # PWA manifest
│ ├── sw.js # Service worker
│ ├── athletes/ # Athlete profile images
│ └── drills/ # Drill illustration images
│
└── supabase/
└── schema.sql # Full database schema
Key Patterns
Client Components
All page components use 'use client' and rely on the useAuth() hook from AuthProvider to get the current user and coach profile. Supabase queries are made directly from the client using the browser client from supabase-browser.js.
DashboardLayout
Every authenticated page is wrapped in DashboardLayout, which provides the collapsible sidebar navigation and top navbar. The layout tracks sidebar collapse state and adjusts content margins accordingly.
API Routes
Server-side operations (video processing, external API proxying, email, push notifications) are handled by Next.js API route handlers in src/app/api/. These use the server Supabase client for authenticated operations.
Video Pipeline
- Upload -- User selects files (or imports from Frame.io)
- Compress -- Client-side FFmpeg WASM reduces file size
- Send to Modal -- Files are sent to the Modal AI backend at
/analyze - Poll -- The app polls
/result/{job_id}/progressfor processing status - Store -- Processed video and stats are fetched and stored in Supabase Storage
- Stream -- Videos are served through a proxy endpoint with byte-range support
Theming
The app uses CSS custom properties defined in globals.css with dark and light variants. The ThemeProvider (wrapping next-themes) manages the active theme. All components reference CSS variables like var(--bg-surface), var(--text-primary), and var(--accent-mint).
Fonts
Three Google Fonts are loaded via next/font:
- Outfit -- Display/heading font (
--font-display) - Plus Jakarta Sans -- Body text (
--font-body) - JetBrains Mono -- Monospace/stats (
--font-mono)