"""Main FastAPI application with blog module."""
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse
from pathlib import Path
from starlette.staticfiles import StaticFiles
Load .env file if python-dotenv is available
try:
from dotenv import load_dotenv
env_path = Path(file).parent / ".env"
if env_path.exists():
load_dotenv(env_path)
except ImportError:
pass
from blog import blog_router, brief_router
from blog.admin_router import admin_router, setup_admin_static
from content import router as content_router
from family import family_router
from webhook_public import webhook_router
from auth.router import auth_router
from shared.session_auth import SessionAuthMiddleware
from dashboard.router import router as dashboard_router
app = FastAPI(
title="HoffDesk API",
description="HoffDesk Blog and Dashboard API",
version="1.0.0"
)
Session auth middleware (must be before CORS for proper handling)
app.add_middleware(SessionAuthMiddleware)
CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=[""], # Configure appropriately for production
allow_credentials=True,
allow_methods=[""],
allow_headers=["*"],
)
Mount blog static files (CSS, images)
BLOG_STATIC_DIR = Path("/home/hoffmann_admin/hoffdesk/blog/static")
app.mount("/blog/static", StaticFiles(directory=str(BLOG_STATIC_DIR)), name="blog_static")
Mount dashboard static files at /static/ for family.hoffdesk.com
DASHBOARD_STATIC_DIR = Path("/home/hoffmann_admin/.openclaw/shared/project-docs/dashboard/static")
app.mount("/static", StaticFiles(directory=str(DASHBOARD_STATIC_DIR)), name="dashboard_static")
Include dashboard router
app.include_router(
dashboard_router,
tags=["dashboard"]
)
Include auth router (must be before protected routes)
app.include_router(
auth_router,
prefix="/auth",
tags=["auth"]
)
Include blog router
app.include_router(
blog_router,
prefix="/api/blog",
tags=["blog"]
)
Include admin router
app.include_router(
admin_router,
prefix="/admin/blog",
tags=["blog-admin"]
)
Include content generation router
app.include_router(
content_router,
prefix="/admin",
tags=["content-generation"]
)
Include family automation router (private household)
app.include_router(
family_router,
prefix="/admin",
tags=["family-automation"]
)
Include public webhook router (no auth, for Cloudflare Worker)
app.include_router(
webhook_router,
tags=["webhook"]
)
Include content briefs router
app.include_router(
brief_router,
prefix="/api/v1/content/briefs",
tags=["content-briefs"]
)
Setup admin static files
setup_admin_static(app)
@app.get("/")
def root():
"""Root endpoint — redirect to blog."""
return RedirectResponse(url="/api/blog/", status_code=302)
@app.get("/health")
def health():
"""Health check endpoint."""
return {"status": "healthy"}
if name == "main":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)