From 78c9df4bb08127e33b9ecfab526f8a3304d5f1e4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Mar 2026 17:11:06 +0000
Subject: [PATCH 1/4] Initial plan
From af3eed4040b9513a5331be9c5163a505940dda9d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Mar 2026 17:25:34 +0000
Subject: [PATCH 2/4] feat(help): restructure /help as user-facing Help Center
with Zammad integration
- Replace MkDocs redirect with a branded, SEO-optimised Help Center template
- Add sections: Quick Start, Sources, Destinations, Workflows, FAQ, Support
- Integrate optional Zammad live-chat widget and ticket form
- Add config settings: ZAMMAD_URL, ZAMMAD_CHAT_ENABLED, ZAMMAD_CHAT_ID,
ZAMMAD_FORM_ENABLED, SUPPORT_EMAIL
- Move MkDocs developer docs from /help to /developer-docs
- Move interactive API docs (Swagger/ReDoc) to /admin/api-docs and /admin/api-redoc
- Add API Docs and Developer Docs links to Admin menu (desktop + mobile)
- Update navigation Help link from /help/ to /help
- Update .env.demo with Zammad configuration examples
- Document new settings in docs/ConfigurationGuide.md
- Rewrite tests to cover new Help Center behaviour
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
---
.env.demo | 12 +
app/config.py | 27 ++
app/main.py | 15 +-
app/views/help.py | 33 ++-
docs/ConfigurationGuide.md | 24 ++
frontend/templates/base.html | 27 +-
frontend/templates/help.html | 510 +++++++++++++++++++++++++++++++++++
tests/test_views_help.py | 145 ++++++++--
8 files changed, 744 insertions(+), 49 deletions(-)
create mode 100644 frontend/templates/help.html
diff --git a/.env.demo b/.env.demo
index a2f567b5..f33432a0 100644
--- a/.env.demo
+++ b/.env.demo
@@ -478,3 +478,15 @@ EMBEDDING_MODEL=text-embedding-3-small
# Maximum tokens to send to the embedding model. Set below the model's
# context window (e.g. 8000 for an 8192-token model).
EMBEDDING_MAX_TOKENS=8000
+
+# **Support / Help Center – Zammad Integration**
+# Base URL of your Zammad instance (required for chat and ticket form).
+# ZAMMAD_URL=https://zammad.example.com
+# Show a live-chat widget on the Help Center page (requires an online Zammad agent).
+# ZAMMAD_CHAT_ENABLED=false
+# Zammad chat topic ID (see Zammad → Channels → Chat → Topics).
+# ZAMMAD_CHAT_ID=1
+# Show a "Submit a Ticket" feedback form on the Help Center page.
+# ZAMMAD_FORM_ENABLED=false
+# Support e-mail address displayed on the Help Center page.
+# SUPPORT_EMAIL=support@example.com
diff --git a/app/config.py b/app/config.py
index 8c9b4a9c..68297ed9 100644
--- a/app/config.py
+++ b/app/config.py
@@ -914,6 +914,33 @@ class Settings(BaseSettings):
description="Allowed request headers for CORS. Use ['*'] to allow all headers.",
)
+ # ---------------------------------------------------------------------------
+ # Support / Help Center – Zammad integration
+ # ---------------------------------------------------------------------------
+ zammad_url: Optional[str] = Field(
+ default=None,
+ description=(
+ "Base URL of your Zammad instance (e.g. https://zammad.example.com). "
+ "Required for the chat widget and feedback form on the Help Center page."
+ ),
+ )
+ zammad_chat_enabled: bool = Field(
+ default=False,
+ description="Show the Zammad live-chat widget on the Help Center page.",
+ )
+ zammad_chat_id: int = Field(
+ default=1,
+ description="Zammad chat topic ID to use for the live-chat widget.",
+ )
+ zammad_form_enabled: bool = Field(
+ default=False,
+ description="Show the Zammad feedback / ticket form on the Help Center page.",
+ )
+ support_email: Optional[str] = Field(
+ default=None,
+ description="Support e-mail address displayed on the Help Center page.",
+ )
+
@model_validator(mode="before")
@classmethod
def strip_outer_quotes(cls, data: Any) -> Any:
diff --git a/app/main.py b/app/main.py
index c03cdd1f..71507011 100644
--- a/app/main.py
+++ b/app/main.py
@@ -137,7 +137,12 @@ async def lifespan(app: FastAPI):
notify_shutdown()
-app = FastAPI(title="DocuElevate", lifespan=lifespan)
+app = FastAPI(
+ title="DocuElevate",
+ lifespan=lifespan,
+ docs_url="/admin/api-docs",
+ redoc_url="/admin/api-redoc",
+)
# Initialize rate limiter and attach to app state
limiter = create_limiter(redis_url=settings.redis_url, enabled=settings.rate_limiting_enabled)
@@ -202,14 +207,16 @@ if os.path.exists(static_dir):
else:
print(f"WARNING: Static directory not found at {static_dir}. Static files will not be served.")
-# Mount the built MkDocs documentation site at /help/
+# Mount the built MkDocs developer documentation at /developer-docs/
+# These docs target administrators and developers, not end-users.
+# The user-facing Help Center is served by the /help view instead.
# The docs are pre-built into docs_build/ during the Docker image build.
# When running locally, run `mkdocs build` from the repo root first.
docs_build_dir = pathlib.Path(__file__).parents[1] / "docs_build"
if os.path.exists(docs_build_dir):
- app.mount("/help", StaticFiles(directory=str(docs_build_dir), html=True), name="help_docs")
+ app.mount("/developer-docs", StaticFiles(directory=str(docs_build_dir), html=True), name="developer_docs")
else:
- print(f"INFO: Help docs not found at {docs_build_dir}. Run 'mkdocs build' to generate them.")
+ print(f"INFO: Developer docs not found at {docs_build_dir}. Run 'mkdocs build' to generate them.")
# Custom exception handlers that return JSON for API routes and HTML for frontend routes
diff --git a/app/views/help.py b/app/views/help.py
index 1df1c205..eff08b1b 100644
--- a/app/views/help.py
+++ b/app/views/help.py
@@ -1,27 +1,42 @@
"""
-Help documentation view routes.
+Help Center view routes.
-Serves the built MkDocs documentation site at /help.
-The static site is built during the Docker image build and placed at docs_build/.
+Renders a user-facing, SEO-optimised Help Center page at ``/help``.
+The page is designed for SaaS end-users and includes guidance on
+features, integrations, workflows, and optional Zammad support widgets
+(live-chat and feedback form).
+
+The developer-oriented MkDocs documentation is served separately at
+``/docs`` and is intentionally **not** cross-linked from this page.
"""
import logging
import pathlib
from fastapi import Request
-from fastapi.responses import RedirectResponse
-from app.views.base import APIRouter
+from app.config import settings
+from app.views.base import APIRouter, templates
logger = logging.getLogger(__name__)
router = APIRouter()
-# Path to the built MkDocs documentation
+# Path to the built MkDocs documentation (kept for reference / backwards compat)
_DOCS_BUILD_DIR = pathlib.Path(__file__).parents[2] / "docs_build"
@router.get("/help", include_in_schema=False)
-async def help_redirect(request: Request) -> RedirectResponse:
- """Redirect /help to /help/ so the MkDocs index is served correctly."""
- return RedirectResponse(url="/help/", status_code=301)
+async def help_center(request: Request):
+ """Render the end-user Help Center page."""
+ return templates.TemplateResponse(
+ "help.html",
+ {
+ "request": request,
+ "zammad_url": settings.zammad_url,
+ "zammad_chat_enabled": settings.zammad_chat_enabled,
+ "zammad_chat_id": settings.zammad_chat_id,
+ "zammad_form_enabled": settings.zammad_form_enabled,
+ "support_email": settings.support_email,
+ },
+ )
diff --git a/docs/ConfigurationGuide.md b/docs/ConfigurationGuide.md
index ef52229a..b33a22a8 100644
--- a/docs/ConfigurationGuide.md
+++ b/docs/ConfigurationGuide.md
@@ -1118,6 +1118,30 @@ Administrators can set the **site-wide default** colour scheme that is applied w
UI_DEFAULT_COLOR_SCHEME=dark
```
+### Support / Help Center – Zammad Integration
+
+The Help Center page (`/help`) can optionally integrate with a [Zammad](https://zammad.com/) instance to offer live chat and a ticket-creation form directly within DocuElevate.
+
+| **Variable** | **Description** | **Default** |
+|-------------------------|-------------------------------------------------------------------------------------------------------|-------------|
+| `ZAMMAD_URL` | Base URL of your Zammad instance (e.g. `https://zammad.example.com`). Required for chat and form. | *(unset)* |
+| `ZAMMAD_CHAT_ENABLED` | Show a Zammad live-chat widget on the Help Center page. | `false` |
+| `ZAMMAD_CHAT_ID` | Zammad chat topic ID (see *Channels → Chat → Topics* in Zammad admin). | `1` |
+| `ZAMMAD_FORM_ENABLED` | Show a "Submit a Ticket" feedback form on the Help Center page. | `false` |
+| `SUPPORT_EMAIL` | Support e-mail address displayed on the Help Center page. | *(unset)* |
+
+**Example:**
+
+```dotenv
+ZAMMAD_URL=https://zammad.example.com
+ZAMMAD_CHAT_ENABLED=true
+ZAMMAD_CHAT_ID=1
+ZAMMAD_FORM_ENABLED=true
+SUPPORT_EMAIL=support@example.com
+```
+
+> **Note:** The live-chat widget requires at least one Zammad agent to be online. If no agent is available, the widget will not appear. Enable Zammad's debug mode (`debug: true`) for troubleshooting.
+
## Duplicate Document Detection
DocuElevate detects and flags documents that share the same content, even if they arrive as separate uploads.
diff --git a/frontend/templates/base.html b/frontend/templates/base.html
index 7b0d9d14..ffb7f7c6 100644
--- a/frontend/templates/base.html
+++ b/frontend/templates/base.html
@@ -172,6 +172,13 @@
{% if request and request.url.path == '/status' %}aria-current="page"{% endif %}>
Status
+
+ Everything you need to get the most out of DocuElevate.
+ Browse topics below or search for what you need.
+
+
+
+
+
+
+ Quick Start
+
+
+
+
+
+
+
+
+
+
Upload Documents
+
+
+ Drag & drop files onto the Upload page or click Choose File.
+ DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.
+
+
+
+
+
+
+
+
+
+
Connect Storage
+
+
+ Head to Settings → Integrations and link your cloud accounts.
+ Processed documents are automatically routed to every destination you configure.
+
+
+
+
+
+
+
+
+
+
Automate Workflows
+
+
+ Create Pipelines to define multi-step processing and routing rules.
+ Combine OCR, AI extraction, format conversion, and delivery in a single flow.
+
+
+
+
+
+
+
+
+
+ Sources – Getting Documents In
+
+
+
+
+
Web Upload
+
+ The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest.
+ Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.
+
+
+
+
+
Email Ingestion (IMAP)
+
+ Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts.
+ DocuElevate polls for new messages and processes attachments automatically.
+
+
+
+
+
REST API
+
+ Integrate programmatically by POST-ing files to /api/upload.
+ Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.
+
+
+
+
+
Scanner & Mobile
+
+ Point network scanners (HP, Fujitsu ScanSnap, Brother) at DocuElevate's upload endpoint or
+ use any mobile scanning app that supports custom HTTP destinations.
+
+
+
+
+
+
+
+
+
+ Destinations – Where Documents Go
+
+
+
+
+
+
+
Dropbox
+
OAuth-linked. Files land in your chosen folder.
+
+
+
+
+
+
+
Google Drive
+
Service account or OAuth. Supports shared drives.
+
+
+
+
+
+
+
OneDrive
+
Microsoft Graph API integration.
+
+
+
+
+
+
+
Amazon S3
+
Any S3-compatible bucket (AWS, MinIO, Wasabi).
+
+
+
+
+
+
+
Nextcloud / WebDAV
+
Self-hosted cloud storage via WebDAV.
+
+
+
+
+
+
+
Paperless-ngx
+
Push documents straight into Paperless for archival.
+
+
+
+
+
+
+
SFTP / FTP
+
Secure file transfer to any server.
+
+
+
+
+
+
+
Email Forwarding
+
Processed files sent as SMTP attachments.
+
+
+
+
+
+
+
Webhook
+
POST metadata to any external endpoint.
+
+
+
+
+
+
+
+
+
+ Workflows & Pipelines
+
+
+
+
+
What is a Pipeline?
+
+ A Pipeline is a series of processing steps that run automatically whenever a document is ingested.
+ Each step can transform, enrich, or route the document.
+
+
Typical Steps
+
+
Convert to PDF (Gotenberg)
+
OCR – extract text (Azure, Tesseract, Mistral …)
+
AI metadata extraction (OpenAI, Claude, Gemini …)
+
Deliver to one or more destinations
+
+
+
+
Creating a Pipeline
+
+
Go to Pipelines in the main menu.
+
Click New Pipeline and give it a name.
+
Add the processing steps you need.
+
Choose one or more delivery destinations.
+
Save – new documents will be processed through this pipeline automatically.
+ Use inotifywait (Linux), fswatch (macOS), or any file-watcher script to
+ POST new files as soon as they appear in a local directory.
+
+
+
+
+
Network Scanners
+
+ Configure your HP, Fujitsu ScanSnap, or Brother scanner to use DocuElevate's upload URL as a
+ Scan-to-Network destination. Scans are processed the moment they arrive.
+
+
+
+
+
Mobile Scanning Apps
+
+ Apps like Adobe Scan, Microsoft Lens, or Genius Scan
+ can export to a custom HTTP endpoint. Point them at /api/upload.
+
+
+
+
+
Zapier / n8n / Make
+
+ Connect DocuElevate to thousands of other apps via integration platforms.
+ Use the HTTP/Webhook module to POST files to the upload API.
+
+
+
+
+
+
+
+
+
+ Frequently Asked Questions
+
+
+
+
+
+
+ Navigate to the Upload page, drag-and-drop your files or click Choose File.
+ DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.
+
+
+
+
+
+
+ PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML.
+ Non-PDF files are automatically converted to PDF before processing.
+
+
+
+
+
+
+ Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new
+ messages and process attachments automatically.
+
+
+
+
+
+
+ Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the
+ result to one or more destinations. Create and manage them from the Pipelines page.
+
+
+
+
+
+
+ DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents
+ longer than necessary. See the Privacy Notice for full details.
+
+
+
+
+
+
+
+
+
+ Contact Support
+
+
+
+
+
+
+
+ Can't find what you're looking for? Our support team is here to help.
+