feat(pipelines): add custom processing pipeline engine

- Add Pipeline and PipelineStep models with user-specific ownership
- Add pipeline_id FK column to FileRecord
- Migration 017_add_pipelines (batch mode for SQLite FK compat)
- Pipeline CRUD API at /api/pipelines with step management endpoints
- Reorder steps PUT endpoint placed before parameterised {step_id} routes
- POST /api/files/{id}/assign-pipeline for per-file pipeline assignment
- Admin-only POST /api/pipelines/admin/system for system-level pipelines
- Management UI at /pipelines (Jinja2 + Alpine.js + Tailwind)
- Pipelines link added to desktop and mobile navigation
- 41 new tests in tests/test_api_pipelines.py (all passing)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-07 10:32:00 +00:00
parent 2c12af95fc
commit 89e0c2fb50
11 changed files with 2369 additions and 0 deletions
+2
View File
@@ -14,6 +14,7 @@ from app.views.general import router as general_router
from app.views.google_drive import router as google_drive_router
from app.views.license_routes import router as license_router # Add the license router
from app.views.onedrive import router as onedrive_router
from app.views.pipelines import router as pipelines_router # Processing pipelines
from app.views.plans import router as plans_router # Admin Plan Designer
from app.views.queue import router as queue_router
from app.views.search import router as search_router
@@ -39,3 +40,4 @@ router.include_router(search_router)
router.include_router(queue_router)
router.include_router(subscriptions_router) # Pricing + subscription pages
router.include_router(plans_router) # Admin Plan Designer
router.include_router(pipelines_router) # Processing pipelines
+34
View File
@@ -0,0 +1,34 @@
"""Pipelines view: management UI for processing pipelines."""
import logging
from fastapi import HTTPException, Request, status
from app.views.base import APIRouter, require_login, settings, templates
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/pipelines")
@require_login
async def pipelines_page(request: Request):
"""Processing pipeline management page for the current user.
Regular users manage their own pipelines. Admins additionally have access
to system-level pipelines through the same UI.
"""
try:
return templates.TemplateResponse(
"pipelines.html",
{
"request": request,
"app_version": settings.version,
},
)
except Exception as exc:
logger.error(f"Error loading pipelines page: {exc}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to load pipelines page",
)