f6c55d888f
Implements docs/planning/social.md US-5's API layer on top of the
already-merged Group/GroupMember models (app/models/groups.py):
- POST/GET /api/groups, GET/PATCH/DELETE /api/groups/{id}
- POST .../join (idempotent), .../leave (owner must transfer first)
- POST .../members/{user_id}/role (owner-only, admin/member),
.../transfer (owner-only, demotes prior owner to admin)
Group page member list is a dedicated schema (user_id/username/role/
joined_at) so no private User fields leak. 27 new tests cover
authorization boundaries, idempotency, and exactly-one-owner invariants;
full backend suite (220 tests) passes with zero regressions.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFSPt6rX1gwZmcr2HEfvzg
55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
"""FastAPI application entry point."""
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from app.config import settings
|
|
from app.routers import auth, users, worlds, assets, avatar, world_content, internal, presence, groups
|
|
|
|
|
|
from app.services.game_servers import supervisor
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Application lifespan: startup and shutdown events."""
|
|
supervisor.start()
|
|
yield
|
|
await supervisor.shutdown()
|
|
|
|
|
|
app = FastAPI(
|
|
title=settings.APP_NAME,
|
|
version=settings.APP_VERSION,
|
|
description="Agentic Game Platform - Backend API",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
# CORS
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.cors_origins_list,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Include routers
|
|
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
|
|
app.include_router(users.router, prefix="/api/users", tags=["users"])
|
|
app.include_router(worlds.router, prefix="/api/worlds", tags=["worlds"])
|
|
app.include_router(world_content.router, prefix="/api/worlds", tags=["world-content"])
|
|
app.include_router(assets.router, prefix="/api/assets", tags=["assets"])
|
|
app.include_router(avatar.router, prefix="/api/avatar", tags=["avatar"])
|
|
app.include_router(internal.router, prefix="/api/internal", tags=["internal"])
|
|
app.include_router(presence.router, prefix="/api/presence", tags=["presence"])
|
|
app.include_router(groups.router, prefix="/api/groups", tags=["groups"])
|
|
|
|
|
|
@app.get("/api/health")
|
|
async def health_check():
|
|
"""Simple health check endpoint."""
|
|
return {"status": "ok", "app": settings.APP_NAME}
|