diff --git a/requirements.txt b/requirements.txt index 42fcd7e..aef74e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ sentence-transformers>=2.5.0 pydantic>=2.6.0 pydantic-settings>=2.1.0 structlog>=24.1.0 +markdown>=3.5.0 diff --git a/src/atocore/api/routes.py b/src/atocore/api/routes.py index b3e2416..e8cfc89 100644 --- a/src/atocore/api/routes.py +++ b/src/atocore/api/routes.py @@ -3,6 +3,7 @@ from pathlib import Path from fastapi import APIRouter, HTTPException +from fastapi.responses import HTMLResponse from pydantic import BaseModel import atocore.config as _config @@ -1075,6 +1076,72 @@ def api_create_relationship(req: RelationshipCreateRequest) -> dict: } +@router.get("/projects/{project_name}/mirror.html", response_class=HTMLResponse) +def api_project_mirror_html(project_name: str) -> HTMLResponse: + """Serve a readable HTML project overview page. + + Open in a browser for a clean, styled project dashboard derived + from AtoCore's structured data. Source of truth is the database — + this page is a derived view. + """ + from atocore.projects.registry import resolve_project_name as _resolve + + canonical = _resolve(project_name) + try: + md_content = generate_project_overview(canonical) + except Exception as e: + raise HTTPException(status_code=500, detail=f"Mirror generation failed: {e}") + + import markdown + + html_body = markdown.markdown(md_content, extensions=["tables", "fenced_code"]) + html = _MIRROR_HTML_TEMPLATE.replace("{{title}}", f"{canonical} — AtoCore Mirror") + html = html.replace("{{body}}", html_body) + return HTMLResponse(content=html) + + +_MIRROR_HTML_TEMPLATE = """ + + + + +{{title}} + + + +{{body}} + +""" + + @router.get("/projects/{project_name}/mirror") def api_project_mirror(project_name: str) -> dict: """Generate a human-readable project overview from structured data.