Track A (Infrastructure & Data Layer): - docker-compose.yml with all 7 services (nginx, frontend, api, mcp, renderer, worker, postgres, redis) - docker-compose.override.yml for local dev (hot reload, port exposure) - PostgreSQL init.sql with full schema (15 tables, pgvector indexes, creator economy stubs) - .env.example with all required environment variables Track A+B (API Layer): - FastAPI app with 10 routers (auth, shaders, feed, votes, generate, desires, users, payments, mcp_keys, health) - SQLAlchemy ORM models for all 15 tables - Pydantic schemas for all request/response types - JWT auth middleware (access + refresh tokens, Redis blocklist) - Redis rate limiting middleware - Celery worker config with job stubs (render, embed, generate, feed cache, expire bounties) - Alembic migration framework Service stubs: - MCP server (health endpoint, 501 for all tools) - Renderer service (Express + Puppeteer scaffold, 501 for /render) - Frontend (package.json with React/Vite/Three.js/TanStack/Tailwind deps) - Nginx reverse proxy config (/, /api, /mcp, /renders) Project: - DECISIONS.md with 11 recorded architectural decisions - README.md with architecture overview - Sample shader seed data (plasma, fractal noise, raymarched sphere)
51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
"""Fractafrag API — Main application entrypoint."""
|
|
|
|
from contextlib import asynccontextmanager
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from app.database import engine
|
|
from app.redis import close_redis
|
|
from app.routers import auth, shaders, feed, votes, generate, desires, users, payments, mcp_keys, health
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Application startup and shutdown lifecycle."""
|
|
# Startup
|
|
yield
|
|
# Shutdown
|
|
await engine.dispose()
|
|
await close_redis()
|
|
|
|
|
|
app = FastAPI(
|
|
title="Fractafrag API",
|
|
description="GLSL shader platform — browse, create, generate, and share real-time GPU visuals",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
docs_url="/api/docs",
|
|
redoc_url="/api/redoc",
|
|
openapi_url="/api/openapi.json",
|
|
)
|
|
|
|
# CORS — permissive in dev, lock down in production
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # TODO: restrict in production
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# ── Mount Routers ─────────────────────────────────────────
|
|
app.include_router(health.router)
|
|
app.include_router(auth.router, prefix="/api/v1/auth", tags=["auth"])
|
|
app.include_router(shaders.router, prefix="/api/v1/shaders", tags=["shaders"])
|
|
app.include_router(feed.router, prefix="/api/v1/feed", tags=["feed"])
|
|
app.include_router(votes.router, prefix="/api/v1", tags=["votes"])
|
|
app.include_router(generate.router, prefix="/api/v1/generate", tags=["generate"])
|
|
app.include_router(desires.router, prefix="/api/v1/desires", tags=["desires"])
|
|
app.include_router(users.router, prefix="/api/v1", tags=["users"])
|
|
app.include_router(payments.router, prefix="/api/v1/payments", tags=["payments"])
|
|
app.include_router(mcp_keys.router, prefix="/api/v1/me/api-keys", tags=["api-keys"])
|