strat-gameplay-webapp/backend/app/main.py
Cal Corum 9b30d3dfb2 CLAUDE: Implement Discord OAuth authentication and SBA API integration
## Authentication Implementation

### Backend
- Implemented complete Discord OAuth flow in auth.py:
  * POST /api/auth/discord/callback - Exchange code for tokens
  * POST /api/auth/refresh - Refresh JWT tokens
  * GET /api/auth/me - Get authenticated user info
  * GET /api/auth/verify - Verify auth status
- JWT token creation with 7-day expiration
- Refresh token support for session persistence
- Bearer token authentication for Discord API calls

### Frontend
- Created auth/login.vue - Discord OAuth initiation page
- Created auth/callback.vue - OAuth callback handler with states
- Integrated with existing auth store (already implemented)
- LocalStorage persistence for tokens and user data
- Full error handling and loading states

### Configuration
- Updated backend .env with Discord OAuth credentials
- Updated frontend .env with Discord Client ID
- Fixed redirect URI to port 3001

## SBA API Integration

### Backend
- Extended SbaApiClient with get_teams(season, active_only=True)
- Added bearer token auth support (_get_headers method)
- Created /api/teams route with TeamResponse model
- Registered teams router in main.py
- Filters out IL (Injured List) teams automatically
- Returns team data: id, abbrev, names, color, gmid, division

### Integration
- Connected to production SBA API: https://api.sba.manticorum.com
- Bearer token authentication working
- Successfully fetches ~16 active Season 3 teams

## Documentation
- Created SESSION_NOTES.md - Current session accomplishments
- Created NEXT_SESSION.md - Game creation implementation guide
- Updated implementation/NEXT_SESSION.md

## Testing
-  Discord OAuth flow tested end-to-end
-  User authentication and session persistence verified
-  Teams API returns real data from production
-  All services running and communicating

## What Works Now
- User can sign in with Discord
- Sessions persist across reloads
- Backend fetches real teams from SBA API
- Ready for game creation implementation

## Next Steps
See .claude/NEXT_SESSION.md for detailed game creation implementation plan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 16:54:27 -06:00

104 lines
2.7 KiB
Python

import logging
from contextlib import asynccontextmanager
import socketio
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api.routes import auth, games, health, teams
from app.config import get_settings
from app.database.session import init_db
from app.services import redis_client
from app.utils.logging import setup_logging
from app.websocket.connection_manager import ConnectionManager
from app.websocket.handlers import register_handlers
logger = logging.getLogger(f"{__name__}.main")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events"""
settings = get_settings()
# Startup
logger.info("Starting Paper Dynasty Game Backend")
setup_logging()
# Initialize database
await init_db()
logger.info("Database initialized")
# Initialize Redis
try:
redis_url = settings.redis_url
await redis_client.connect(redis_url)
logger.info(f"Redis initialized: {redis_url}")
except Exception as e:
logger.warning(
f"Redis connection failed: {e}. Position rating caching will be unavailable."
)
yield
# Shutdown
logger.info("Shutting down Paper Dynasty Game Backend")
# Disconnect Redis
if redis_client.is_connected:
await redis_client.disconnect()
logger.info("Redis disconnected")
# Initialize FastAPI app
app = FastAPI(
title="Paper Dynasty Game Backend",
description="Real-time baseball game engine for Paper Dynasty leagues",
version="1.0.0",
lifespan=lifespan,
)
# CORS middleware
settings = get_settings()
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Initialize Socket.io
sio = socketio.AsyncServer(
async_mode="asgi",
cors_allowed_origins=settings.cors_origins,
logger=True,
engineio_logger=False,
)
# Create Socket.io ASGI app
socket_app = socketio.ASGIApp(sio, app)
# Initialize connection manager and register handlers
connection_manager = ConnectionManager(sio)
register_handlers(sio, connection_manager)
# Include API routes
app.include_router(health.router, prefix="/api", tags=["health"])
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
app.include_router(games.router, prefix="/api/games", tags=["games"])
app.include_router(teams.router, prefix="/api/teams", tags=["teams"])
@app.get("/")
async def root():
return {"message": "Paper Dynasty Game Backend", "version": "1.0.0"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:socket_app", host="0.0.0.0", port=8000, reload=True, log_level="info"
)