Initial DevOpsDash — FastAPI + Alpine.js dashboard for DevOpsMCP
Some checks failed
Build and push DevOpsDash / build (push) Has been cancelled

- Taskz kanban board (create/edit tasks, findings, status/priority)
- Worklog timeline + standup summary (proxied from DevOpsMCP MCP API)
- Knowledge browser (ADRs, memories, knowledge catalog files)
- FastAPI backend reading same Redis as DevOpsMCP
- Read-only bind-mount for DevOpsMCP data directory (/data)
- Nomad job spec (dash.i80.dk, Traefik TLS, host volume read-only)
- Gitea Actions CI → registry.i80.dk/gitea/devops-dash:latest
This commit is contained in:
Henrik Jess Nielsen
2026-05-09 16:36:18 +02:00
commit ac85040e4d
15 changed files with 1638 additions and 0 deletions

55
app/main.py Normal file
View File

@@ -0,0 +1,55 @@
"""DevOpsDash — FastAPI entry point."""
from __future__ import annotations
import os
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.routers import tasks, worklog, knowledge
app = FastAPI(title="DevOpsDash", version="1.0.0", docs_url="/api/docs")
app.include_router(tasks.router)
app.include_router(worklog.router)
app.include_router(knowledge.router)
TEMPLATES_DIR = Path(__file__).parent / "templates"
templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
@app.get("/health")
def health():
from app.redis_client import get_redis
try:
r = get_redis()
r.ping()
redis_ok = True
except Exception:
redis_ok = False
data_dir = os.environ.get("DATA_DIR", "/data")
return {
"status": "ok",
"redis": "ok" if redis_ok else "unavailable",
"data_dir": data_dir,
"data_dir_exists": Path(data_dir).exists(),
}
@app.get("/", response_class=HTMLResponse)
async def dashboard(request: Request):
mcp_url = os.environ.get("DEVOPS_MCP_URL", "http://devops-mcp:8000")
return templates.TemplateResponse("dashboard.html", {
"request": request,
"mcp_url": mcp_url,
})
if __name__ == "__main__":
import uvicorn
port = int(os.environ.get("PORT", 8001))
uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)