80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
"""Brain of Reese — application entrypoint.
|
|
|
|
Boots logging + conditional debugpy, then creates the FastAPI app:
|
|
API routes first (so they win over the catch-all), and the static frontend
|
|
mounted last. No CDN: everything the browser needs is served by this
|
|
process from local files (see PLAN §UI/UX — No External Dependencies).
|
|
|
|
Phase 16 (A10 revised): before anything is served, admin auth must be
|
|
configured (fail-loud), and the app wraps every route in Starlette's
|
|
SessionMiddleware — a signed ``bor_session`` cookie is the only session
|
|
state in the system.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
from starlette.middleware.sessions import SessionMiddleware
|
|
|
|
from app.api.auth import router as auth_router
|
|
from app.api.chat import router as chat_router
|
|
from app.api.docs import router as docs_router
|
|
from app.api.health import router as health_router
|
|
from app.api.steering import router as steering_router
|
|
from app.api.suggestions import router as suggestions_router
|
|
from app.api.sync import router as sync_router
|
|
from app.config import get_settings
|
|
from app.core.auth import ensure_admin_configured
|
|
from app.core.debugging import configure_debugging
|
|
from app.core.logging import configure_logging
|
|
|
|
configure_logging()
|
|
configure_debugging()
|
|
|
|
settings = get_settings()
|
|
logger = logging.getLogger("app")
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
# Fail loud BEFORE serving anything (phase 16): missing
|
|
# BOR_ADMIN_PASSWORD / BOR_SESSION_SECRET raises at boot, naming the
|
|
# variable(s) — the app never starts in a half-authenticated state.
|
|
ensure_admin_configured(settings)
|
|
|
|
app = FastAPI(title=settings.app_name, version=settings.app_version)
|
|
|
|
# Signed single-admin session cookie (Starlette middleware, itsdangerous
|
|
# signer — no server-side store, no new services). Homelab HTTP: same_site
|
|
# is "lax" and https_only stays off (documented in the README).
|
|
app.add_middleware(
|
|
SessionMiddleware,
|
|
secret_key=settings.session_secret,
|
|
session_cookie=settings.session_cookie,
|
|
max_age=settings.session_max_age,
|
|
same_site="lax",
|
|
https_only=False,
|
|
)
|
|
|
|
# API routes first so they take precedence over the catch-all static mount.
|
|
app.include_router(health_router, prefix="/api")
|
|
app.include_router(auth_router, prefix="/api")
|
|
app.include_router(suggestions_router, prefix="/api")
|
|
app.include_router(docs_router, prefix="/api")
|
|
app.include_router(chat_router, prefix="/api")
|
|
app.include_router(steering_router, prefix="/api")
|
|
app.include_router(sync_router, prefix="/api")
|
|
|
|
static_dir = Path(settings.static_dir).resolve()
|
|
if static_dir.is_dir():
|
|
app.mount("/", StaticFiles(directory=static_dir, html=True), name="static")
|
|
else:
|
|
logger.warning("static dir %s not found — serving API only", static_dir)
|
|
|
|
return app
|
|
|
|
|
|
app = create_app()
|