# Project export: WildTrack

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2026
- Tagline: Crowdsourced wildlife tracking powered by AI for proactive conservation, for enthusiasts and professionals.
- Devpost: https://devpost.com/software/wildtrack-642bxr
- GitHub: https://github.com/Wildtrack-A/Wildtrack
- Video: https://www.youtube.com/embed/hlJNZ2k-07k?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Cedroz (4 commits)

## Devpost submission (written by the team)

### Inspiration

Wildlife poaching and habitat destruction remain critical threats to endangered species worldwide. Traditional conservation efforts often rely on fragmented data and delayed reporting, making it difficult to protect animals in real-time. We were inspired by the idea of empowering both citizen scientists and field researchers with a unified platform that turns everyday wildlife sightings into actionable conservation intelligence while ensuring sensitive location data doesn't fall into the wrong hands.

### What it does

WildTrack is a full-stack mobile and web platform that enables users to report wildlife sightings, which are then processed using machine learning to create intelligent geofence zones around animal habitats. The system aggregates data from multiple sources—citizen scientists, field researchers, and social media—to build a comprehensive wildlife intelligence network. Key Features: Role-Based Data Access: Field researchers see exact GPS coordinates and individual sightings, while public users only see general habitat boundaries—preventing poachers from exploiting precise location data DBSCAN Clustering: Automatically groups 69,507+ GPS observations into meaningful habitat zones for 119+ endangered species using scikit-learn's DBSCAN algorithm with Haversine distance calculations Real-Time Data Ingestion: Collects observations from citizen scientists via React Native mobile app with GPS tracking and photo uploads Interactive Maps: Visualize species distributions, habitat boundaries, and cluster centers using react-native-maps with custom markers and polygons AI Image Detection: Auto-detects animal species from uploaded photos using Gemini Animal Encyclopedia: Searches for animal information online and displays nice charts with a detailed descriptions using Gemini Reddit Data Aggregation: Scrapes wildlife subreddits (r/wildlife, r/animalid, r/conservation, etc.) using Reddit's public JSON API to extract endangered species sightings and location data Analytics Dashboard: Real-time charts showing species distribution, sighting trends, and top endangered animals in user's area using react-native-chart-kit Spatial Grid Clustering: Optimized clustering algorithm using spatial grid partitioning (0.1° ≈ 11km cells) for O(n) performance instead of O(n²) In-Memory Caching: 5-minute TTL cache for observation data to reduce database load and improve API response times

### How we built it

Backend Architecture Framework & API: FastAPI with async/await for high-performance REST API Uvicorn ASGI server with automatic API documentation at /docs Pydantic models for request/response validation SlowAPI for rate limiting (configurable per endpoint) CORS middleware for cross-origin requests Database: Supabase (PostgreSQL) with PostGIS extension for geospatial queries Row-Level Security (RLS) policies for role-based access control 14 SQL migration scripts managing schema evolution: observations table: Stores GPS coordinates, species, timestamps zones table: Pre-computed habitat boundaries with convex hull polygons reddit_sightings table: Scraped social media data with metadata endangered_species table: Reference data for 119+ species journals and logs tables: User-generated observation records profiles table: User roles (field_researcher vs public) observations table: Stores GPS coordinates, species, timestamps zones table: Pre-computed habitat boundaries with convex hull polygons reddit_sightings table: Scraped social media data with metadata endangered_species table: Reference data for 119+ species journals and logs tables: User-generated observation records profiles table: User roles (field_researcher vs public) Machine Learning Pipeline: DBSCAN Clustering: scikit-learn implementation with custom distance metrics Epsilon: 0.01 degrees (≈1km) for habitat zone detection Min samples: 3 points per cluster Processes 2,000-4,000 points per clustering run (sampled from 69k+ total) Epsilon: 0.01 degrees (≈1km) for habitat zone detection Min samples: 3 points per cluster Processes 2,000-4,000 points per clustering run (sampled from 69k+ total) Convex Hull Generation: SciPy for habitat boundary polygon creation Spatial Grid Optimization: Custom grid-based clustering (0.1° cells) reducing complexity from O(n²) to O(n) Haversine Distance: NumPy-optimized calculations for accurate geospatial measurements Data Processing: Background task processing for Reddit scraping (FastAPI BackgroundTasks) Batch processing with pagination (100 records/page) for large datasets In-memory caching with 5-minute TTL to minimize database queries Point sampling algorithms to limit processing to 4,000 points for performance External Integrations: Reddit JSON API scraping (no authentication required, public endpoints) Geopy/Nominatim for reverse geocoding location names Hugging Face transformers for AI image classification PyTorch for deep learning inference Frontend Architecture Mobile App: React Native 0.81.5 with Expo SDK 54 Expo Router for file-based navigation TypeScript for type safety React Native Maps for interactive map visualization Expo Location for GPS tracking with continuous updates Expo Image Picker for camera integration AsyncStorage for local token persistence State Management: React Hooks (useState, useEffect, useMemo, useCallback) Custom API service layer with error handling Optimistic UI updates for better UX UI Components: Custom modals with ScrollView for log details Species-specific icon mapping with color coding Cluster visualization with pulse animations Real-time location tracking with user position markers Chart visualizations (PieChart, BarChart) for analytics Authentication: Supabase Auth with JWT tokens AsyncStorage for session persistence Automatic token refresh handling Role-based UI rendering (researcher vs public views) Data Scraping Reddit Integration: Public JSON API endpoints (no OAuth required) Scrapes 9 wildlife-focused subreddits Species detection via keyword matching against 119+ endangered species Location extraction using geopy/Nominatim from post text Background processing with FastAPI BackgroundTasks Duplicate detection via reddit_id to prevent re-scraping Metadata extraction: upvotes, comments, timestamps, author info Data Flow: Scraper queries subreddits via JSON API Filters posts mentioning endangered species Extracts location data (if available) Saves to reddit_sightings table Frontend queries via /api/v1/reddit-sightings endpoint API Endpoints /api/v1/auth/* - Authentication (signup, login, profile sync) /api/v1/journals - CRUD operations for user journals /api/v1/logs - Wildlife observation logging /api/v1/zones/* - Habitat zone queries (clusters, boundaries, nearby species) /api/v1/reddit-sightings - Social media data aggregation /api/v1/image-verification - AI image authenticity detection /api/v1/animal-search - Species encyclopedia and search

### Challenges we ran into

Balancing Accessibility vs Security: Designing a system that's useful for public conservation awareness while protecting animals from poachers required careful role-based access control implementation Performance at Scale: Processing 69,507 observations required optimizing DBSCAN from O(n²) to O(n) using spatial grid partitioning Git Merge Conflicts: Managing multiple feature branches with different directory structures and conflicting dependencies Reddit API Limitations: Reddit's free API tier restrictions led us to use public JSON endpoints, requiring custom scraping logic Real-Time Location Tracking: Implementing continuous GPS updates without draining battery required careful optimization of location polling intervals Type Safety: TypeScript type errors with backend API responses required extensive type definition work

### Accomplishments we're proud of

Successfully clustered 69,507 GPS observations across 119 species into 1,000+ meaningful habitat zones using DBSCAN Implemented role-based data access that protects exact animal locations from potential misuse while maintaining public awareness Built a complete full-stack application with React Native mobile app, FastAPI REST API, Supabase database, and ML pipeline Created test endpoints that allow rapid development without full auth setup Processed real-world wildlife data from multiple sources into actionable conservation insights Optimized clustering performance from O(n²) to O(n) using spatial grid algorithms, enabling real-time cluster updates Integrated multiple data sources: citizen reports, field researcher data, and Reddit social media scraping Built AI-powered features: automatic species detection from photos and image verification

### What we learned

Security-First Design: The importance of considering data sensitivity in conservation tech—protecting animals requires protecting their location data Full-Stack Integration: Connecting React Native frontend → FastAPI backend → Supabase database → ML models requires careful API design and error handling Geospatial Algorithms: Implementing efficient clustering for large-scale GPS data requires understanding spatial indexing and distance metrics Performance Optimization: Caching, sampling, and algorithmic optimization are critical when processing 70k+ data points API Design: RESTful endpoints with proper error handling, rate limiting, and documentation improve developer experience

### What's next

Integration with Conservation Organizations: Partner with wildlife reserves and NGOs to integrate their existing data systems Real-Time Alerts: Notify rangers when sightings occur outside expected habitat zones (potential poaching indicator) Temporal Analysis: Track migration patterns and seasonal movements using time-series analysis Mobile Push Notifications: Alert users about nearby endangered species sightings Advanced ML Models: Fine-tune species detection models on domain-specific wildlife datasets Web Dashboard: Expand beyond mobile to web-based analytics platform for researchers Data Export: Allow researchers to export zone boundaries and observation data for GIS software Community Features: Enable users to comment on sightings and share conservation tips Tech Stack Summary Backend: Python 3.13, FastAPI, Uvicorn Supabase (PostgreSQL + PostGIS) scikit-learn, NumPy, SciPy Hugging Face Transformers, PyTorch Geopy, Requests Frontend: React Native 0.81.5, Expo SDK 54 TypeScript React Native Maps, Expo Location React Native Chart Kit Supabase JS Client Infrastructure: Supabase (Database + Auth + Storage) Git/GitHub for version control SQL migrations for schema management

## README (from the GitHub repository)

# Wildtrack
Today, conservation reacts after damage is done. WildTrack changes that. We use AI-driven spatio-temporal modeling to build an invisible conservation infrastructure — dynamically rerouting human activity away from sensitive wildlife zones while preserving access to nature. It’s biodiversity protection designed for the modern world.


## Detected evidence (automated analysis)

Indexed codebase: 28 recognized source files, 46 KB.
- FastAPI (technology) — detected in the code
- Python (language) — detected in the code
- SQL (language) — detected in the code
- Supabase (technology) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- React (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (31 of 31)

```
README.md
WildTrackServer/.env.example
WildTrackServer/.gitignore
WildTrackServer/app/__init__.py
WildTrackServer/app/api/__init__.py
WildTrackServer/app/api/v1/__init__.py
WildTrackServer/app/api/v1/auth.py
WildTrackServer/app/api/v1/ingest.py
WildTrackServer/app/auth.py
WildTrackServer/app/config.py
WildTrackServer/app/database.py
WildTrackServer/app/main.py
WildTrackServer/app/models/__init__.py
WildTrackServer/app/models/observation.py
WildTrackServer/app/models/user.py
WildTrackServer/app/models/zone.py
WildTrackServer/README.md
WildTrackServer/requirements.txt
WildTrackServer/sql/01_enable_postgis.sql
WildTrackServer/sql/02_create_observations_table.sql
WildTrackServer/sql/03_create_zones_table.sql
WildTrackServer/sql/04_create_is_user_in_danger_rpc.sql
WildTrackServer/sql/05_setup_rls_policies.sql
WildTrackServer/sql/06_create_users_table.sql
WildTrackServer/sql/06_migrate_to_auth0.sql
WildTrackServer/sql/06b_add_service_role_policy.sql
WildTrackServer/sql/06c_create_profile_manually.sql
WildTrackServer/sql/06d_create_profile_function.sql
WildTrackServer/test_auth_flow.py
WildTrackServer/test_auth0.py
WildTrackServer/test_ingest.py
```

### Dependencies

- WildTrackServer/requirements.txt: authlib@==1.3.0, fastapi@==0.104.1, httpx@==0.26.0, pydantic@==2.5.0, pydantic-settings@==2.1.0, python-dotenv@==1.0.0, python-jose[cryptography]@==3.3.0, python-multipart@==0.0.6, slowapi@==0.1.9, supabase@==2.0.0, uvicorn[standard]@==0.24.0

### Recent commits (newest first)

- Swapped to Auth0 authentication system
- Removed Unused Dependencies
- Add authentication system with Supabase Auth, profiles table, and protected endpoints
- Data warehouse setup with ingestion API, Supabase integration, input validation, and rate limiting
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### WildTrackServer/requirements.txt

```
fastapi==0.104.1
uvicorn[standard]==0.24.0
python-dotenv==1.0.0
supabase==2.0.0
pydantic==2.5.0
pydantic-settings==2.1.0
python-multipart==0.0.6
slowapi==0.1.9
authlib==1.3.0
python-jose[cryptography]==3.3.0
httpx==0.26.0
```

### WildTrackServer/app/main.py

```python
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
from app.api.v1 import ingest, auth

app = FastAPI(
    title="WildTrack Server",
    description="Spatio-temporal data platform for proactive conservation",
    version="1.0.0"
)

# Initialize rate limiter
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)

# CORS middleware - adjust origins for production
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Configure appropriately for production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers (after limiter setup)
app.include_router(auth.router, prefix="/api/v1/auth", tags=["authentication"])
app.include_router(ingest.router, prefix="/api/v1", tags=["ingestion"])


@app.get("/")
async def root():
    return {
        "message": "WildTrack Server API",
        "version": "1.0.0",
        "docs": "/docs"
    }


@app.get("/health")
async def health_check():
    return {"status": "healthy"}

```

### WildTrackServer/test_ingest.py

```python
"""Quick test script to verify the ingestion endpoint works."""
import requests
import json
from datetime import datetime

# Test data
test_observations = [
    {
        "animal_id": "elephant_001",
        "latitude": -1.2921,
        "longitude": 36.8219,
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "species": "African Elephant",
        "metadata": {}
    }
]

try:
    response = requests.post(
        "http://localhost:8000/api/v1/ingest",
        json=test_observations
    )
    
    print(f"Status Code: {response.status_code}")
    print(f"Response: {json.dumps(response.json(), indent=2)}")
    
    if response.status_code == 201:
        print("\nSuccess! Data should now be in Supabase.")
    else:
        print(f"\nError: {response.text}")
        
except requests.exceptions.ConnectionError:
    print("Error: Could not connect to server. Make sure it's running on http://localhost:8000")
except Exception as e:
    print(f"Error: {e}")

```

### WildTrackServer/test_auth0.py

```python
"""
Test script for Auth0 authentication endpoints.

Prerequisites:
1. Auth0 account with API created
2. AUTH0_DOMAIN and AUTH0_API_AUDIENCE in .env file
3. Auth0 test token or access token from frontend

Usage:
    python test_auth0.py
"""

import requests
import os
from dotenv import load_dotenv

load_dotenv()

BASE_URL = "http://localhost:8000/api/v1"

# Get Auth0 config
AUTH0_DOMAIN = os.getenv("AUTH0_DOMAIN")
AUTH0_API_AUDIENCE = os.getenv("AUTH0_API_AUDIENCE")

print("=" * 60)
print("Auth0 Authentication Test")
print("=" * 60)
print(f"\nAuth0 Domain: {AUTH0_DOMAIN}")
print(f"API Audience: {AUTH0_API_AUDIENCE}")
print(f"Base URL: {BASE_URL}\n")

# Step 1: Get Auth0 token
print("To test this endpoint, you need an Auth0 access token.")
print("\nOption 1: Use Auth0's Test Client")
print("  1. Go to Auth0 Dashboard -> Applications")
print("  2. Click on 'Test Application' (or create a new one)")
print("  3. Go to 'Try It Out' tab")
print("  4. Use 'Machine to Machine' grant type")
print("  5. Authorize it for your API")
print("  6. Copy the access token")

print("\nOption 2: Use Auth0's API Explorer")
print("  1. Go to Auth0 Dashboard -> APIs -> Your API")
print("  2. Click 'Test' tab")
print("  3. Copy the access token from the test section")

print("\nOption 3: Get token from your frontend")
print("  After user logs in via Auth0, frontend gets access token")
print("  Use that token here")

print("\n" + "=" * 60)
print("Enter your Auth0 access token:")
print("(Or press Enter to skip and see manual curl command)")
print("=" * 60)

token = input().strip()

if not token:
    print("\n" + "=" * 60)
    print("Manual Testing Instructions:")
    print("=" * 60)
    print("\n1. Get an Auth0 token (see options above)")
    print("\n2. Test /api/v1/auth/me with curl:")
    print(f'   curl -X GET "{BASE_URL}/auth/me" \\')
    print('        -H "Authorization: Bearer YOUR_AUTH0_TOKEN"')
    print('\n3. Or test in FastAPI docs at http://localhost:8000/docs')
    print('   - Click on GET /api/v1/auth/me')
    print('   - Click "Authorize" button')
    print('   - Enter: Bearer YOUR_AUTH0_TOKEN')
    print('   - Click "Authorize" then "Try it out"')
    exit(0)

# Test /api/v1/auth/me
print("\n" + "=" * 60)
print("Testing GET /api/v1/auth/me")
print("=" * 60)

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}

try:
    response = requests.get(f"{BASE_URL}/auth/me", headers=headers)
    
    print(f"\nStatus Code: {response.status_code}")
    print(f"Response Headers: {dict(response.headers)}\n")
    
    if response.status_code == 200:
        user_data = response.json()
        print("✅ Success! User data:")
        print(f"   ID: {user_data.get('id')}")
        print(f"   Email: {user_data.get('email')}")
        print(f"   Username: {user_data.get('username')}")
        print(f"   Role: {user_data.get('role')}")
        print(f"   Full Name: {user_data.get('full_name')}")
        print(f"   Is Active: {user_data.get('is_active')}")
    else:
        print(f"❌ Error: {response.status_code}")
        print(f"Response: {response.text}")
        
except requests.exceptions.ConnectionError:
    print("❌ Error: Could not connect to server.")
    print("   Make sure your FastAPI server is running:")
    print("   uvicorn app.main:app --reload")
except Exception as e:
    print(f"❌ Error: {str(e)}")

# Test /api/v1/auth/sync-profile
print("\n" + "=" * 60)
print("Testing POST /api/v1/auth/sync-profile")
print("=" * 60)

try:
    response = requests.post(f"{BASE_URL}/auth/sync-profile", headers=headers)
    
    print(f"\nStatus Code: {response.status_code}")
    
    if response.status_code == 200:
        user_data = response.json()
        print("✅ Success! Profile synced:")
        print(f"   ID: {user_data.get('id')}")
        print(f"   Email: {user_data.get('email')}")
        print(f"   Username: {user_data.get('username')}")
        print(f"   Role: {user_data.get('role')}")
    else:
        print(f"❌ Error: {response.status_code}")
        print(f"Response: {response.text}")
        
except Exception as e:
    print(f"❌ Error: {str(e)}")

print("\n" + "=" * 60)
print("Test Complete")
print("=" * 60)

```

### WildTrackServer/test_auth_flow.py

```python
"""Test script for complete authentication flow: registration -> login -> protected endpoint"""
import requests
import json
from datetime import datetime

BASE_URL = "http://localhost:8000"

print("=" * 60)
print("WildTrack Authentication Flow Test")
print("=" * 60)

# Step 1: Register a new user
print("\n[1/3] Registering new user...")
register_data = {
    "email": f"test_{datetime.now().strftime('%Y%m%d%H%M%S')}@test.com",
    "username": f"testuser_{datetime.now().strftime('%Y%m%d%H%M%S')}",
    "password": "password123",
    "full_name": "Test Field Researcher",
    "role": "field_researcher"
}

try:
    register_response = requests.post(
        f"{BASE_URL}/api/v1/auth/register",
        json=register_data
    )
    
    if register_response.status_code == 201:
        user_data = register_response.json()
        print(f"[SUCCESS] Registration successful!")
        print(f"   User ID: {user_data['id']}")
        print(f"   Email: {user_data['email']}")
        print(f"   Username: {user_data['username']}")
        print(f"   Role: {user_data['role']}")
        email = register_data["email"]
        password = register_data["password"]
    else:
        print(f"[ERROR] Registration failed: {register_response.status_code}")
        print(f"   Error: {register_response.text}")
        exit(1)
        
except Exception as e:
    print(f"[ERROR] Registration error: {e}")
    exit(1)

# Step 2: Login to get token
print("\n[2/3] Logging in...")
login_data = {
    "email": email,
    "password": password
}

try:
    login_response = requests.post(
        f"{BASE_URL}/api/v1/auth/login",
        json=login_data
    )
    
    if login_response.status_code == 200:
        token_data = login_response.json()
        access_token = token_data["access_token"]
        print(f"[SUCCESS] Login successful!")
        print(f"   Token type: {token_data['token_type']}")
        print(f"   Access token: {access_token[:50]}...")
    else:
        print(f"[ERROR] Login failed: {login_response.status_code}")
        print(f"   Error: {login_response.text}")
        exit(1)
        
except Exception as e:
    print(f"[ERROR] Login error: {e}")
    exit(1)

# Step 3: Test protected endpoint - Ingest observations
print("\n[3/3] Testing protected ingest endpoint...")
observation_data = [
    {
        "animal_id": "elephant_001",
        "latitude": -1.2921,
        "longitude": 36.8219,
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "species": "African Elephant",
        "metadata": {}
    }
]

headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}

try:
    ingest_response = requests.post(
        f"{BASE_URL}/api/v1/ingest",
        json=observation_data,
        headers=headers
    )
    
    if ingest_response.status_code == 201:
        observations = ingest_response.json()
        print(f"[SUCCESS] Ingestion successful!")
        print(f"   Created {len(observations)} observation(s)")
        for obs in observations:
            print(f"   - Observation ID: {obs['id']}, Animal: {obs['animal_id']}, Species: {obs['species']}")
    else:
        print(f"[ERROR] Ingestion failed: {ingest_response.status_code}")
        print(f"   Error: {ingest_response.text}")
        exit(1)
        
except Exception as e:
    print(f"[ERROR] Ingestion error: {e}")
    exit(1)

# Step 4: Test without token (should fail)
print("\n[BONUS] Testing ingest without token (should fail)...")
try:
    no_auth_response = requests.post(
        f"{BASE_URL}/api/v1/ingest",
        json=observation_data
    )
    
    if no_auth_response.status_code == 403:
        print(f"[SUCCESS] Security working! Got 403 Forbidden (as expected)")
    else:
        print(f"[WARNING] Unexpected status: {no_auth_response.status_code}")
        print(f"   Response: {no_auth_response.text}")
except Exception as e:
    print(f"   Error (expected): {e}")

print("\n" + "=" * 60)
print("[SUCCESS] Complete authentication flow test PASSED!")
print("=" * 60)
print("\nSummary:")
print(f"  [OK] User registered: {email}")
print(f"  [OK] Token obtained: {access_token[:30]}...")
print(f"  [OK] Protected endpoint accessed successfully")
print(f"  [OK] Security verified (401/403 without token)")

```

### WildTrackServer/app/__init__.py

```python
# WildTrack Server Application

```

### WildTrackServer/sql/01_enable_postgis.sql

```sql
-- Enable PostGIS extension for spatial data operations
-- Run this in Supabase SQL Editor: Database -> Extensions -> Enable postgis
-- OR run this SQL:
CREATE EXTENSION IF NOT EXISTS postgis;

```

### WildTrackServer/sql/06b_add_service_role_policy.sql

```sql
-- Add service role policy for profiles table
-- This allows the API (using service role key) to manage profiles

CREATE POLICY "Service role can manage profiles"
    ON profiles FOR ALL
    USING (auth.role() = 'service_role')
    WITH CHECK (auth.role() = 'service_role');

```

### WildTrackServer/app/database.py

```python
"""Database connection and Supabase client setup."""
from supabase import create_client, Client
from app.config import settings


def get_supabase_client() -> Client:
    """Get Supabase client instance."""
    return create_client(settings.supabase_url, settings.supabase_key)


def get_admin_supabase_client() -> Client:
    """Get Supabase client with service key for admin operations."""
    if not settings.supabase_service_key:
        raise ValueError("Service key not configured for admin operations")
    return create_client(settings.supabase_url, settings.supabase_service_key)

```

### WildTrackServer/sql/06_migrate_to_auth0.sql

```sql
-- Migration script: Convert profiles table from Supabase Auth to Auth0
-- Run this ONLY if you already have a profiles table with UUID id column
-- This will DROP the old table and recreate it with TEXT id for Auth0

-- WARNING: This will delete all existing profile data!
-- Only run this if you're okay losing test data, or export it first

-- Drop the old table and its dependencies
DROP POLICY IF EXISTS "Users can view own profile" ON profiles;
DROP POLICY IF EXISTS "Users can update own profile" ON profiles;
DROP POLICY IF EXISTS "Service role can manage profiles" ON profiles;
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
DROP FUNCTION IF EXISTS public.handle_new_user();
DROP TABLE IF EXISTS profiles CASCADE;

-- Now run the new 06_create_users_table.sql

```

[17 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]