00466a9801
Introduces a manifest contract so feature containers self-describe their settings (JSON Schema + access rules). Backend and frontend gain generic plugin proxy and dynamic Extensions UI with zero feature-specific code. Doc-service is the first plugin consumer: exposes /plugin/manifest and /plugin/settings, adds a watchdog-based file watcher that auto-ingests PDFs from a mounted directory, maps subfolders to categories, supports AI-suggested folder/filename (user-confirmed), and enforces a no-remove policy. Access is gated by is_superuser or doc-service-admin group. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
48 lines
1.4 KiB
Python
48 lines
1.4 KiB
Python
import asyncio
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
|
|
from app.core.config import settings
|
|
from app.routers import categories, documents
|
|
from app.routers import plugin as plugin_router
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
loop = asyncio.get_running_loop()
|
|
watcher = None
|
|
|
|
try:
|
|
from app.services.config_reader import get_storage_config
|
|
storage_config = await get_storage_config()
|
|
if storage_config.get("watch_enabled"):
|
|
from app.services.file_watcher import FileWatcherService
|
|
watcher = FileWatcherService(loop)
|
|
await watcher.start(storage_config["watch_path"], storage_config)
|
|
except Exception as exc:
|
|
logger.warning("[doc-service] File watcher could not start: %s", exc)
|
|
|
|
yield
|
|
|
|
if watcher is not None:
|
|
await watcher.stop()
|
|
|
|
|
|
app = FastAPI(title=settings.PROJECT_NAME, lifespan=lifespan)
|
|
|
|
# No CORS — this service is only reachable from the main backend on backend-net.
|
|
# All browser traffic goes through the main backend proxy.
|
|
|
|
app.include_router(documents.router, prefix="/documents", tags=["documents"])
|
|
app.include_router(categories.router, prefix="/categories", tags=["categories"])
|
|
app.include_router(plugin_router.router, prefix="/plugin", tags=["plugin"])
|
|
|
|
|
|
@app.get("/health")
|
|
def health():
|
|
return {"status": "ok"}
|