DocsDatabase Schema

Tables, relationships, and RLS policies

Database Schema

Surflink uses Supabase (PostgreSQL) with a comprehensive schema of 35+ tables. All tables have Row Level Security (RLS) enabled to ensure data isolation between coaches.

The full schema is defined in supabase/schema.sql.

Table Groups

Users & Auth

TableDescription
coachesCoach profiles linked to auth.users -- name, email, avatar, bio, location, home break
studentsStudent profiles linked to a coach -- name, email, age, stance, skill level, invite status
parent_linksLinks parent auth.users to students with configurable permissions
push_tokensDevice tokens for APNs/FCM push notifications

Sessions & Video

TableDescription
sessionsSurf sessions -- title, location, date, duration, video URLs, AI stats, processing status
session_clipsIndividual video clips within a session -- filename, size, job ID, status, HLS URL
session_surfersLinks tracked surfer IDs (from AI) to student profiles
annotationsCoach annotations on video -- timestamp, type (drawing/text/voice), data JSON
ride_scoresCoach-scored rides with start/end timestamps and multi-criteria scores

Curriculum & Training

TableDescription
drillsExercise library -- title, description, category, skill level, duration, multi-step instructions
drill_assignmentsCoach assigns drills to students with due dates and status tracking
lessonsScheduled lessons -- student, location, spot, duration, conditions forecast, linked session
lesson_drillsLinks drills to lessons in order
training_plansMulti-week structured programs with plan JSON
skill_definitionsTaxonomy of surf skills -- name, category, prerequisites, linked drills
skill_assessmentsCoach-assessed progress per student per skill (not_started through mastered)

Tracking & Gamification

TableDescription
session_journalEnriched session logs with mood/energy/confidence ratings, conditions, wave counts
goalsMetric-based goals with target values and status
goal_milestonesCheckpoint milestones within goals
achievementsBadge definitions -- slug, name, description, icon, category, threshold
student_achievementsEarned badges per student with timestamps
equipmentStudent gear quiver -- boards, fins, wetsuits, etc.

Social & Communication

TableDescription
messagesCoach-student messages with read tracking
notificationsIn-app notifications with type, title, body, and read status
community_postsCommunity feed posts with optional session links
community_likesPost likes (unique per user per post)
highlight_reelsCurated clip collections with public sharing

Billing

TableDescription
coaching_packagesPackage definitions -- name, price, session count, duration
subscriptionsActive student subscriptions with Stripe IDs
paymentsPayment records with amount, type, status

Competitions

TableDescription
competitionsCompetition events -- name, date, location, format, status
heatsHeat rounds within competitions
heat_entriesStudent entries per heat with jersey color and seed
heat_scoresWave-by-wave scores (0-10) with interference tracking

Location

TableDescription
spotsSaved surf spots with coordinates

Row Level Security

Every table has RLS enabled. The general policy pattern:

  • Coaches have full CRUD access to data they own (their students, sessions, drills, etc.)
  • Students have read access to data linked to them (their sessions, scores, drill assignments, etc.) and write access to specific tables (journal, messages, drill assignment status)
  • Parents have read access to data for their linked student(s)
  • Public data -- Skill definitions, achievements, active coaching packages, and public highlight reels are readable by anyone

Example Policy

-- Coaches can manage their sessions
create policy "Coaches can manage sessions"
  on public.sessions for all
  using (
    coach_id in (
      select id from public.coaches
      where user_id = auth.uid()
    )
  );

-- Students can view sessions they're linked to
create policy "Students can view linked sessions"
  on public.sessions for select
  using (
    id in (
      select session_id from public.session_surfers
      where student_id in (
        select id from public.students
        where user_id = auth.uid()
      )
    )
  );