Development
πŸ“˜ Developer Handbook

Developer Handbook

Complete Development Guide: From setup to deployment, everything you need to develop on the AltSportsLeagues.ai platform.

Table of Contents

Getting Started

Prerequisites

# Required tools
- Node.js 18+ (for frontend)
- Python 3.11+ (for backend)
- Docker & Docker Compose
- uv (Python package manager)
- Google Cloud SDK (for deployment)
- Vercel CLI (for frontend deployment)

Initial Setup

# 1. Clone repository
git clone [repository-url]
cd 2.1-cloud-run-docker-mcp
 
# 2. Install backend dependencies
cd apps/backend
uv sync
 
# 3. Install frontend dependencies
cd ../../clients/frontend
npm install
 
# 4. Install docs dependencies
cd ../docs-site
npm install
 
# 5. Configure environment variables
cp .env.example .env
# Edit .env with your credentials

Environment Variables

Backend (.env)

# AI Services
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
 
# Google Cloud
GOOGLE_CLOUD_PROJECT=your-project
FIRESTORE_PROJECT_ID=your-project
 
# Databases
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_KEY=eyJ...
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=password
 
# n8n
N8N_API_URL=https://n8n.altsportsleagues.ai
N8N_API_KEY=n8n_api_...

Frontend (.env.local)

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_FIREBASE_API_KEY=...
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=...
NEXT_PUBLIC_FIREBASE_PROJECT_ID=...

Development Environment

Backend Development

Starting the Backend

# Method 1: Direct Python (fastest for development)
cd apps/backend
uv run uvicorn server:app --reload --port 8080
 
# Method 2: Docker (matches production)
cd apps/backend
./deploy-local-docker.sh
# Access at: http://localhost:8090
 
# Method 3: Docker Compose (full stack)
docker-compose -f deploy/docker-compose.yml up

Backend Structure

apps/backend/
β”œβ”€ server.py              # Main FastAPI application
β”œβ”€ routers/              # API route handlers
β”‚   β”œβ”€ v1/              # Version 1 API routes
β”‚   └─ ...
β”œβ”€ services/             # Business logic
β”‚   β”œβ”€ intent_classifier.py
β”‚   β”œβ”€ league_data_processor.py
β”‚   └─ ...
β”œβ”€ mcp_servers/          # MCP server implementations
β”‚   └─ servers/
β”œβ”€ models/               # Pydantic models
β”œβ”€ utils/                # Utility functions
β”œβ”€ tests/                # Test suite
└─ config/               # Configuration

Adding a New API Endpoint

  1. Create Router Module

    # apps/backend/routers/v1/my_feature.py
    from fastapi import APIRouter
    from models.my_models import MyRequest, MyResponse
     
    router = APIRouter(prefix="/v1/my-feature", tags=["My Feature"])
     
    @router.get("/")
    async def get_items() -> list[MyResponse]:
        """Get all items"""
        return []
     
    @router.post("/")
    async def create_item(request: MyRequest) -> MyResponse:
        """Create a new item"""
        return MyResponse()
  2. Register Router

    # apps/backend/server.py
    from routers.v1.my_feature import router as my_feature_router
     
    app.include_router(my_feature_router)
  3. Add Tests

    # apps/backend/tests/test_my_feature.py
    def test_get_items():
        response = client.get("/v1/my-feature/")
        assert response.status_code == 200

Frontend Development

Starting the Frontend

cd clients/frontend
npm run dev
# Access at: http://localhost:3031

Frontend Structure

clients/frontend/
β”œβ”€ app/                  # Next.js App Router
β”‚   β”œβ”€ (routes)/         # Route groups
β”‚   β”œβ”€ api/              # API routes
β”‚   β”œβ”€ components/       # React components
β”‚   └─ layout.tsx        # Root layout
β”œβ”€ components/           # Shared components
β”‚   └─ ui/              # shadcn/ui components
β”œβ”€ lib/                  # Utilities
β”œβ”€ hooks/                # Custom React hooks
β”œβ”€ store/                # Zustand stores
β”œβ”€ styles/               # Global styles
β”œβ”€ types/                # TypeScript types
└─ public/               # Static assets

Creating a New Page

  1. Create Route File

    // app/(routes)/my-page/page.tsx
    import { Metadata } from 'next'
     
    export const metadata: Metadata = {
      title: 'My Page',
      description: 'My page description'
    }
     
    export default function MyPage() {
      return (
        <div>
          <h1>My Page</h1>
        </div>
      )
    }
  2. Add to Navigation

    // app/components/navigation.tsx
    const links = [
      { href: '/my-page', label: 'My Page' }
    ]

Creating a Component

// components/my-component.tsx
'use client'
 
import { useState } from 'react'
 
interface MyComponentProps {
  title: string
  onAction?: () => void
}
 
export function MyComponent({ title, onAction }: MyComponentProps) {
  const [state, setState] = useState(false)
 
  return (
    <div>
      <h2>{title}</h2>
      <button onClick={() => {
        setState(!state)
        onAction?.()
      }}>
        Toggle
      </button>
    </div>
  )
}

State Management with Zustand

// store/my-store.ts
import { create } from 'zustand'
 
interface MyStore {
  count: number
  increment: () => void
  decrement: () => void
}
 
export const useMyStore = create<MyStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
 
// Usage in component
import { useMyStore } from '@/store/my-store'
 
function MyComponent() {
  const { count, increment } = useMyStore()
  return <button onClick={increment}>{count}</button>
}

Documentation Development

Starting Docs Site

cd clients/docs-site
npm run dev
# Access at: http://localhost:3001

Adding Documentation

  1. Create MDX File
    // pages/my-topic/my-guide.mdx
    # My Guide
     
    This is a guide about my topic.
     
    ## Section 1
     
    Content here...
     
    ```typescript
    // Code example
    const example = 'code'
  2. Update Navigation
    // pages/my-topic/_meta.js
    export default {
      'my-guide': 'My Guide Title',
      'other-guide': 'Other Guide'
    }

Development Workflows

Feature Development Workflow

  1. Create Feature Branch

    git checkout -b feature/my-feature
  2. Develop & Test Locally

    • Backend: Run tests with pytest
    • Frontend: Test in browser
    • Integration: Test full flow
  3. Commit Changes

    git add .
    git commit -m "feat: add my feature"
  4. Push & Create PR

    git push origin feature/my-feature
    # Create pull request on GitHub

Code Review Checklist

  • βœ… Code follows style guidelines
  • βœ… Tests pass locally
  • βœ… Documentation updated
  • βœ… No sensitive data in code
  • βœ… TypeScript types are correct
  • βœ… Error handling implemented
  • βœ… Performance considered
  • βœ… Security reviewed

Git Commit Convention

# Format
<type>(<scope>): <subject>
 
# Types
feat:     New feature
fix:      Bug fix
docs:     Documentation only
style:    Code style changes
refactor: Code refactoring
test:     Adding tests
chore:    Maintenance tasks
 
# Examples
feat(api): add league discovery endpoint
fix(frontend): resolve navigation bug
docs(readme): update setup instructions

Testing

Backend Testing

Unit Tests

# tests/test_services.py
import pytest
from services.my_service import MyService
 
def test_my_function():
    service = MyService()
    result = service.my_function("input")
    assert result == "expected"
 
@pytest.mark.asyncio
async def test_async_function():
    service = MyService()
    result = await service.async_function()
    assert result is not None

API Tests

# tests/test_api.py
from fastapi.testclient import TestClient
from server import app
 
client = TestClient(app)
 
def test_get_leagues():
    response = client.get("/v1/leagues")
    assert response.status_code == 200
    data = response.json()
    assert isinstance(data, list)

Running Tests

cd apps/backend
 
# Run all tests
pytest
 
# Run specific test file
pytest tests/test_api.py
 
# Run with coverage
pytest --cov=. --cov-report=html
 
# Run specific test
pytest tests/test_api.py::test_get_leagues -v

Frontend Testing

E2E Tests with Playwright

// e2e/homepage.spec.ts
import { test, expect } from '@playwright/test'
 
test('homepage loads correctly', async ({ page }) => {
  await page.goto('/')
  await expect(page).toHaveTitle(/AltSportsLeagues/)
  await expect(page.locator('h1')).toBeVisible()
})
 
test('league search works', async ({ page }) => {
  await page.goto('/leagues')
  await page.fill('input[name="search"]', 'NBA')
  await page.click('button[type="submit"]')
  await expect(page.locator('.league-card')).toBeVisible()
})

Running E2E Tests

cd clients/frontend
 
# Run tests
npm run test:e2e
 
# Run in UI mode
npm run test:e2e:ui
 
# Run specific test
npx playwright test e2e/homepage.spec.ts

Integration Testing

MCP Tool Testing

# Test MCP tool functionality
import pytest
from mcp_servers.servers.my_mcp_server import MyMCPServer
 
@pytest.mark.asyncio
async def test_mcp_tool():
    server = MyMCPServer()
    result = await server.call_tool("my_tool", {"param": "value"})
    assert result["success"] is True

Deployment

Local Deployment (Docker)

Backend Local Deployment

cd apps/backend
 
# Deploy to local Docker
./deploy-local-docker.sh
 
# Test deployment
./test-local-deployment.sh
 
# View logs
docker compose logs -f
 
# Stop
docker compose down

Production Deployment

Backend to Cloud Run

cd apps/backend
 
# Deploy to Cloud Run
./deploy-to-cloud-run.sh
 
# Monitor deployment
gcloud run services describe altsportsleagues-backend \
  --region us-central1
 
# View logs
gcloud run services logs tail altsportsleagues-backend \
  --region us-central1

Frontend to Vercel

cd clients/frontend
 
# Deploy to production
vercel --prod
 
# Check deployment status
vercel inspect [deployment-url]
 
# View logs
vercel logs

Docs to Vercel

cd clients/docs-site
 
# Build with schema injection
npm run build
 
# Deploy
vercel --prod

Deployment Checklist

  • βœ… All tests passing
  • βœ… Environment variables configured
  • βœ… Docker build successful (backend)
  • βœ… Next.js build successful (frontend/docs)
  • βœ… No secrets in code
  • βœ… API endpoints tested
  • βœ… Health checks pass
  • βœ… Monitoring configured
  • βœ… Documentation updated

Best Practices

Code Quality

TypeScript/JavaScript

// βœ… Good: Strong typing
interface User {
  id: string
  name: string
  email: string
}
 
function getUser(id: string): Promise<User> {
  return fetch(`/api/users/${id}`).then(r => r.json())
}
 
// ❌ Bad: Weak typing
function getUser(id: any): Promise<any> {
  return fetch(`/api/users/${id}`).then(r => r.json())
}

Python

# βœ… Good: Type hints and validation
from pydantic import BaseModel
 
class User(BaseModel):
    id: str
    name: str
    email: str
 
async def get_user(user_id: str) -> User:
    # Implementation
    pass
 
# ❌ Bad: No typing
def get_user(user_id):
    # Implementation
    pass

Error Handling

Frontend

// βœ… Good: Proper error handling
try {
  const data = await fetch('/api/leagues').then(r => r.json())
  return data
} catch (error) {
  console.error('Failed to fetch leagues:', error)
  toast.error('Failed to load leagues. Please try again.')
  return []
}
 
// ❌ Bad: Silent failures
const data = await fetch('/api/leagues').then(r => r.json())
return data || []

Backend

# βœ… Good: Specific error handling
from fastapi import HTTPException
 
@router.get("/leagues/{league_id}")
async def get_league(league_id: str):
    try:
        league = await league_service.get(league_id)
        if not league:
            raise HTTPException(status_code=404, detail="League not found")
        return league
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"Failed to get league: {e}")
        raise HTTPException(status_code=500, detail="Internal server error")
 
# ❌ Bad: Generic error handling
@router.get("/leagues/{league_id}")
async def get_league(league_id: str):
    try:
        return await league_service.get(league_id)
    except:
        return None

Security

Authentication

// βœ… Good: Protected routes
import { auth } from '@/lib/firebase'
 
async function protectedAction() {
  const user = auth.currentUser
  if (!user) {
    throw new Error('Not authenticated')
  }
 
  const token = await user.getIdToken()
  return fetch('/api/protected', {
    headers: { Authorization: `Bearer ${token}` }
  })
}

Input Validation

# βœ… Good: Validated input
from pydantic import BaseModel, validator
 
class LeagueCreate(BaseModel):
    name: str
    sport: str
 
    @validator('name')
    def name_must_not_be_empty(cls, v):
        if not v.strip():
            raise ValueError('Name cannot be empty')
        return v

Performance

Frontend Optimization

// βœ… Good: Memoization
import { useMemo } from 'react'
 
function LeagueList({ leagues }) {
  const sortedLeagues = useMemo(
    () => leagues.sort((a, b) => a.name.localeCompare(b.name)),
    [leagues]
  )
 
  return <div>{/* Render sorted leagues */}</div>
}
 
// βœ… Good: Lazy loading
import dynamic from 'next/dynamic'
 
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <div>Loading...</div>
})

Backend Optimization

# βœ… Good: Async operations
import asyncio
 
async def fetch_multiple_leagues(league_ids: list[str]):
    tasks = [league_service.get(id) for id in league_ids]
    return await asyncio.gather(*tasks)
 
# βœ… Good: Database connection pooling
from sqlalchemy.pool import QueuePool
 
engine = create_engine(
    DATABASE_URL,
    poolclass=QueuePool,
    pool_size=10,
    max_overflow=20
)

Troubleshooting

Common Issues

Backend Issues

Issue: Import errors

# Solution: Install dependencies
cd apps/backend
uv sync

Issue: Port already in use

# Solution: Kill process or use different port
lsof -ti:8080 | xargs kill -9
# Or
uvicorn server:app --reload --port 8081

Issue: Database connection failed

# Solution: Check environment variables
echo $SUPABASE_URL
echo $NEO4J_URI
 
# Test connections
python -c "from config import settings; print(settings.SUPABASE_URL)"

Frontend Issues

Issue: Module not found

# Solution: Install dependencies
cd clients/frontend
rm -rf node_modules package-lock.json
npm install

Issue: Build fails

# Solution: Clear Next.js cache
rm -rf .next
npm run build

Issue: API calls fail

# Solution: Check API URL
# In .env.local:
NEXT_PUBLIC_API_URL=http://localhost:8080
 
# Verify backend is running
curl http://localhost:8080/health

Debug Tools

Backend Debug

# Add logging
import logging
 
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
 
logger.debug("Debug message")
logger.info("Info message")
logger.error("Error message")
 
# Use debugger
import pdb; pdb.set_trace()

Frontend Debug

// Browser console
console.log('Debug:', data)
console.table(array)
console.dir(object)
 
// React DevTools
// Install: https://react.dev/learn/react-developer-tools
 
// Network tab
// Monitor API calls in browser DevTools

Resources

Support


Last Updated: November 2024 Version: 2.1.0

Platform

Documentation

Community

Support

partnership@altsportsdata.comdev@altsportsleagues.ai

2025 Β© AltSportsLeagues.ai. Powered by AI-driven sports business intelligence.

πŸ€– AI-Enhancedβ€’πŸ“Š Data-Drivenβ€’βš‘ Real-Time