Total Athletes
—
Registered profiles
◉
States
—
States represented
⬡
Total Reps
—
Across all athletes
▲
Push Devices
—
Ready for notifications
📱
Athletes by State
● Awaiting DataConnect Supabase to see live data
Top Athletes
● Awaiting Data
| # | Athlete | State | Reps | Sessions | FO% | GB | Goals | Assists |
|---|---|---|---|---|---|---|---|---|
| Connect Supabase to load data | ||||||||
Quick Notify
Activity Log
Dashboard initialized
Just now
Athletes
● Live · profiles
| # | Name | Phone | State | Position | Push Consent | Joined | ||
|---|---|---|---|---|---|---|---|---|
| Connect Supabase to see athletes | ||||||||
Connect Supabase to see leaders
Full Stats Table
● Live · leaderboard| # | Athlete | State | Reps | Sessions | FO Wins | FO Att | FO% | GB | Goals | Assists | Last Active | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Connect Supabase to see stats | ||||||||||||
Registered Devices
—
Ready for push
Cities
—
Unique cities
States
—
With devices
Push Devices
| State | City | Registered | ||
|---|---|---|---|---|
| Connect Supabase to see devices | ||||
Bonus Codes
Connect Supabase to see bonus codes
Step 1 · Add Lacrosse Stats Columns
SQL · Run Once1
Open Supabase SQL Editor
Go to your Supabase project → SQL Editor → New query
2
Run this SQL to add lacrosse stat columns
ALTER TABLE leaderboard
ADD COLUMN IF NOT EXISTS fo_wins integer DEFAULT 0,
ADD COLUMN IF NOT EXISTS fo_attempts integer DEFAULT 0,
ADD COLUMN IF NOT EXISTS ground_balls integer DEFAULT 0,
ADD COLUMN IF NOT EXISTS goals integer DEFAULT 0,
ADD COLUMN IF NOT EXISTS assists integer DEFAULT 0;
3
Update your Rork app
In your Rork app code, when saving session results, also write the lacrosse stats to these new columns in the leaderboard table. The dashboard will immediately show live stats once data flows in.
Step 2 · Deploy Push Notification Edge Function
Supabase CLI1
Get your Expo Access Token
Go to expo.dev → Account Settings → Access Tokens → Create token → Copy it
2
Create the Edge Function file
Create a file:
supabase/functions/send-push/index.ts with this code:// supabase/functions/send-push/index.ts
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
Deno.serve(async (req) => {
if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })
const { title, body, state_filter } = await req.json()
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
// Get push tokens, optionally filtered by state
let query = supabase.from('push_devices').select('device_token, user_email')
if (state_filter) query = query.eq('state', state_filter)
const { data: devices } = await query
if (!devices || devices.length === 0) {
return new Response(JSON.stringify({ sent: 0 }), { headers: corsHeaders })
}
// Send to Expo Push API
const messages = devices.map(d => ({
'';
title,
body,
sound: 'default',
data: { source: 'foa-dashboard' }
}))
const response = await fetch('https://exp.host/--/api/v2/push/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${Deno.env.get('EXPO_ACCESS_TOKEN')}`,
},
body: JSON.stringify(messages)
})
const result = await response.json()
return new Response(
JSON.stringify({ sent: messages.length, result }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
})
3
Deploy via Supabase Dashboard
Go to Supabase → Edge Functions → Deploy a new function → Paste the code above → Name it send-push
4
Set your secrets
In Supabase → Edge Functions → Secrets, add:
EXPO_ACCESS_TOKEN = your token from Step 15
Paste your Function URL below
Once deployed, copy the Edge Function URL and paste it in Supabase Config — then your Send Notification button fires real push notifications.
Step 2a · Create In-App Messages Table
SQL · Run Once1
Run this in Supabase SQL Editor to enable in-app messaging
CREATE TABLE IF NOT EXISTS in_app_messages (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
type text DEFAULT 'Announcement',
title text NOT NULL,
body text NOT NULL,
target_states text[],
action_url text,
expires_at date,
active boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
-- Allow app to read active messages
ALTER TABLE in_app_messages ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can read active messages" ON in_app_messages
FOR SELECT USING (active = true);
CREATE POLICY "Service role can manage messages" ON in_app_messages
USING (true) WITH CHECK (true);
Step 2b · Add Database Indexes
SQL · Run Once · Performance!
Run this once to keep queries fast as you scale
CREATE INDEX IF NOT EXISTS idx_drill_sessions_email ON drill_sessions(user_email);
CREATE INDEX IF NOT EXISTS idx_leaderboard_email ON leaderboard(user_email);
CREATE INDEX IF NOT EXISTS idx_highlights_email ON highlights(user_email);
-- Prevent duplicate device tokens
ALTER TABLE push_devices ADD CONSTRAINT push_devices_token_unique UNIQUE (device_token);
-- Prevent duplicate bonus codes
ALTER TABLE bonus_codes ADD CONSTRAINT bonus_codes_code_unique UNIQUE (code);
-- Prevent duplicate profiles per email (add email col first if needed)
-- ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email text;
-- ALTER TABLE profiles ADD CONSTRAINT profiles_email_unique UNIQUE (email);
Step 2c · Fix RLS on push_devices
Security · Recommended!
Your push_devices table is currently UNRESTRICTED
Anyone with your anon key can read all device tokens. Run this to lock it down:
-- Enable RLS
ALTER TABLE push_devices ENABLE ROW LEVEL SECURITY;
-- Allow app to insert its own device token
CREATE POLICY "Users can insert own device" ON push_devices
FOR INSERT WITH CHECK (true);
-- Only service role can read all tokens (dashboard uses service role)
CREATE POLICY "Service role reads all" ON push_devices
FOR SELECT USING (auth.role() = 'service_role');
⚠ After enabling RLS, update your dashboard anon key to the service_role key so it can still read devices.
Step 3 · Password Protection
✓ Already Active✓
Login screen is live
The dashboard is already password protected. To change your password, click the button below.
Compose In-App Message
● Live · in_app_messages
Active Messages
Connect Supabase to see messages