refactor: complete rewrite as React+FastAPI dashboard
Replace monolithic Jinja2 template with modern stack: Backend (FastAPI): - Modular router/service architecture - Async PostgreSQL (asyncpg) for news from n8n pipeline - Live Unraid server stats (2 servers via API) - Home Assistant, Vikunja tasks, weather (wttr.in) - WebSocket broadcast for real-time updates (15s) - TTL cache per endpoint, all config via ENV vars Frontend (React + Vite + TypeScript): - Glassmorphism dark theme with Tailwind CSS - Responsive grid: mobile/tablet/desktop/ultrawide - Weather cards, hourly forecast, news with category tabs - Server stats (CPU ring, RAM bar, Docker list) - Home Assistant controls, task management - Live clock, WebSocket connection indicator Infrastructure: - Multi-stage Dockerfile (node:22-alpine + python:3.11-slim) - docker-compose with full ENV configuration - Kaniko CI/CD pipeline for GitLab registry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4bbc125a67
commit
9f7330e217
48 changed files with 6390 additions and 1461 deletions
89
server/main.py
Normal file
89
server/main.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""Daily Briefing Dashboard — FastAPI Application."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from server.config import settings
|
||||
from server.services import news_service
|
||||
|
||||
logger = logging.getLogger("daily-briefing")
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if settings.debug else logging.INFO,
|
||||
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||
)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Startup / shutdown lifecycle."""
|
||||
logger.info("Starting Daily Briefing Dashboard...")
|
||||
logger.info(
|
||||
"Unraid servers configured: %d",
|
||||
len(settings.unraid_servers),
|
||||
)
|
||||
|
||||
# Initialize database pool
|
||||
try:
|
||||
await news_service.init_pool(
|
||||
host=settings.db_host,
|
||||
port=settings.db_port,
|
||||
dbname=settings.db_name,
|
||||
user=settings.db_user,
|
||||
password=settings.db_password,
|
||||
)
|
||||
logger.info("Database pool initialized")
|
||||
except Exception:
|
||||
logger.exception("Failed to initialize database pool — news will be unavailable")
|
||||
|
||||
yield
|
||||
|
||||
# Shutdown
|
||||
logger.info("Shutting down...")
|
||||
await news_service.close_pool()
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="Daily Briefing",
|
||||
version="2.0.0",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
# CORS — allow frontend dev server
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# --- Register Routers ---
|
||||
from server.routers import dashboard, homeassistant, news, servers, tasks, weather # noqa: E402
|
||||
|
||||
app.include_router(weather.router)
|
||||
app.include_router(news.router)
|
||||
app.include_router(servers.router)
|
||||
app.include_router(homeassistant.router)
|
||||
app.include_router(tasks.router)
|
||||
app.include_router(dashboard.router)
|
||||
|
||||
# --- Serve static frontend (production) ---
|
||||
static_dir = Path(__file__).parent.parent / "static"
|
||||
if static_dir.is_dir():
|
||||
app.mount("/", StaticFiles(directory=str(static_dir), html=True), name="static")
|
||||
logger.info("Serving static frontend from %s", static_dir)
|
||||
else:
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {
|
||||
"status": "ok",
|
||||
"message": "Daily Briefing API — Frontend not built yet",
|
||||
"endpoints": ["/api/all", "/api/weather", "/api/news", "/api/servers", "/api/ha", "/api/tasks"],
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue