feat(docs): add built-in help section with How-To guides embedded in app
- Add MkDocs Material docs build stage to Dockerfile and Dockerfile.local - Mount pre-built docs as static files at /help/ in FastAPI (app/main.py) - Add app/views/help.py with /help → /help/ permanent redirect route - Register help router in app/views/__init__.py - Add Help nav link to base.html (public + app nav, desktop + mobile) - Create how-to guides: HP printer, ScanSnap, watched folder, email ingestion, mobile scanning - Update mkdocs.yml with How-To Guides section and Material theme palette - Add optional docs service (squidfunk/mkdocs-material) to docker-compose.yaml with docs profile - Add mkdocs-material to requirements-dev.txt - Add /docs_build to .gitignore - Add tests for help view (8 tests, 100% coverage on help.py) Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -171,6 +171,7 @@ venv.bak/
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
/docs_build
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
+19
@@ -7,6 +7,22 @@ WORKDIR /app
|
||||
COPY requirements.txt /app/
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# ── Documentation build stage ───────────────────────────────────────────────
|
||||
FROM python:3.14.1-slim AS docs-builder
|
||||
|
||||
WORKDIR /docs
|
||||
|
||||
# Install MkDocs Material and its dependencies
|
||||
COPY docs/requirements.txt /docs/requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy documentation sources
|
||||
COPY docs /docs/docs
|
||||
COPY mkdocs.yml /docs/mkdocs.yml
|
||||
|
||||
# Build the static documentation site
|
||||
RUN mkdocs build --config-file /docs/mkdocs.yml --site-dir /docs/docs_build
|
||||
|
||||
# Second stage for the actual runtime
|
||||
FROM python:3.14.3-slim
|
||||
|
||||
@@ -43,6 +59,9 @@ COPY ./BUILD_DATE /app/BUILD_DATE
|
||||
COPY ./GIT_SHA /app/GIT_SHA
|
||||
COPY ./RUNTIME_INFO /app/RUNTIME_INFO
|
||||
|
||||
# Copy the pre-built MkDocs documentation site (served at /help)
|
||||
COPY --from=docs-builder /docs/docs_build /app/docs_build
|
||||
|
||||
# Create runtime_info directory
|
||||
RUN mkdir -p /app/runtime_info
|
||||
|
||||
|
||||
@@ -6,6 +6,19 @@ WORKDIR /app
|
||||
COPY requirements.txt /app/
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# ── Documentation build stage ───────────────────────────────────────────────
|
||||
FROM python:3.14.1-slim AS docs-builder
|
||||
|
||||
WORKDIR /docs
|
||||
|
||||
COPY docs/requirements.txt /docs/requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY docs /docs/docs
|
||||
COPY mkdocs.yml /docs/mkdocs.yml
|
||||
|
||||
RUN mkdocs build --config-file /docs/mkdocs.yml --site-dir /docs/docs_build
|
||||
|
||||
FROM python:3.14.1-slim
|
||||
|
||||
WORKDIR /app
|
||||
@@ -33,6 +46,9 @@ COPY ./LICENSE /app/LICENSE
|
||||
COPY ./VERSION /app/VERSION
|
||||
COPY ./BUILD_DATE /app/BUILD_DATE
|
||||
|
||||
# Copy the pre-built MkDocs documentation site (served at /help)
|
||||
COPY --from=docs-builder /docs/docs_build /app/docs_build
|
||||
|
||||
# Local fallbacks for build metadata
|
||||
RUN echo "local" > /app/GIT_SHA \
|
||||
&& echo "local" > /app/RUNTIME_INFO
|
||||
|
||||
@@ -202,6 +202,15 @@ 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/
|
||||
# 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")
|
||||
else:
|
||||
print(f"INFO: Help 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
|
||||
@app.exception_handler(HTTPException)
|
||||
|
||||
@@ -12,6 +12,7 @@ from app.views.filemanager import router as filemanager_router
|
||||
# Import all the view routers
|
||||
from app.views.general import router as general_router
|
||||
from app.views.google_drive import router as google_drive_router
|
||||
from app.views.help import router as help_router # Built-in help / How-To docs
|
||||
from app.views.license_routes import router as license_router # Add the license router
|
||||
from app.views.onboarding import router as onboarding_router
|
||||
from app.views.onedrive import router as onedrive_router
|
||||
@@ -43,3 +44,4 @@ router.include_router(subscriptions_router) # Pricing + subscription pages
|
||||
router.include_router(plans_router) # Admin Plan Designer
|
||||
router.include_router(onboarding_router) # User onboarding wizard
|
||||
router.include_router(pipelines_router) # Processing pipelines
|
||||
router.include_router(help_router) # Built-in help / How-To docs
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
Help documentation 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/.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pathlib
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from app.views.base import APIRouter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# Path to the built MkDocs documentation
|
||||
_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)
|
||||
@@ -72,3 +72,22 @@ services:
|
||||
image: redis:alpine
|
||||
container_name: document_redis
|
||||
restart: always
|
||||
|
||||
# Optional: standalone docs server using MkDocs Material (live-reload during development).
|
||||
# Start with: docker compose --profile docs up docs
|
||||
# Access at: http://localhost:8001
|
||||
# Note: The /help route in the main app serves pre-built docs from the Docker image.
|
||||
# This service is for content authors who want live preview while editing documentation.
|
||||
docs:
|
||||
image: squidfunk/mkdocs-material:latest
|
||||
container_name: docuelevate_docs
|
||||
restart: "no"
|
||||
profiles:
|
||||
- docs
|
||||
volumes:
|
||||
- ./docs:/docs/docs
|
||||
- ./mkdocs.yml:/docs/mkdocs.yml
|
||||
working_dir: /docs
|
||||
command: ["serve", "--dev-addr=0.0.0.0:8000", "--config-file=/docs/mkdocs.yml"]
|
||||
ports:
|
||||
- "8001:8000"
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# How-To Guides
|
||||
|
||||
Welcome to the DocuElevate How-To Guides. These step-by-step articles help you connect common scanners, printers, and mobile devices to DocuElevate for automatic document ingestion and processing.
|
||||
|
||||
---
|
||||
|
||||
## Document Ingestion Guides
|
||||
|
||||
Choose the method that matches your hardware or workflow:
|
||||
|
||||
### 🖨️ Scanners & Printers
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| [HP Enterprise Printer Setup](howto/HPPrinterSetup.md) | Configure HP MFPs for automatic scan-to-DocuElevate via email, network folder, or WebDAV |
|
||||
| [Fujitsu ScanSnap Setup](howto/SnapScanSetup.md) | Set up ScanSnap iX1600/iX1500/iX500 to send scans directly to DocuElevate |
|
||||
| [Watched Folder Setup](howto/WatchedFolderSetup.md) | Monitor a local or network folder and automatically ingest any files dropped into it |
|
||||
|
||||
### 📧 Email & Cloud
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| [Email Ingestion](howto/EmailIngestion.md) | Route documents sent as email attachments into DocuElevate automatically |
|
||||
| [Mobile Scanning](howto/MobileScanning.md) | Use iOS/Android apps to capture and upload documents from your phone |
|
||||
|
||||
---
|
||||
|
||||
## Quick Comparison: Which Method Is Right for You?
|
||||
|
||||
| Method | Best For | Setup Complexity |
|
||||
|--------|----------|-----------------|
|
||||
| **Web Upload** | Occasional one-off uploads | ⭐ Very Easy |
|
||||
| **Watched Folder** | Any scanner that saves to a folder | ⭐⭐ Easy |
|
||||
| **Email Ingestion** | Scanners with Scan-to-Email, fax services | ⭐⭐ Easy |
|
||||
| **HP Printer (SMB)** | HP Enterprise MFPs on a corporate network | ⭐⭐⭐ Medium |
|
||||
| **ScanSnap + Cloud** | Home/office ScanSnap via Dropbox/Drive | ⭐⭐ Easy |
|
||||
| **Mobile App** | On-the-go document capture | ⭐ Very Easy |
|
||||
| **API Integration** | Custom workflows, developer integrations | ⭐⭐⭐⭐ Advanced |
|
||||
|
||||
---
|
||||
|
||||
## General Configuration Tips
|
||||
|
||||
### Enable OCR for Searchable PDFs
|
||||
|
||||
DocuElevate applies OCR (Optical Character Recognition) to scanned documents, making them fully searchable. Configure the OCR engine in your `.env`:
|
||||
|
||||
```env
|
||||
OCR_ENABLED=true
|
||||
OCR_ENGINE=tesseract # or: azure, google
|
||||
OCR_LANGUAGE=eng # ISO 639-2 language code
|
||||
```
|
||||
|
||||
### Set Up Automatic Cloud Backup
|
||||
|
||||
After processing, DocuElevate can store documents in your preferred cloud storage. Configure in Settings or `.env`:
|
||||
|
||||
```env
|
||||
DEFAULT_STORAGE_TARGET=dropbox # or: gdrive, onedrive, s3, nextcloud
|
||||
```
|
||||
|
||||
### Configure Notifications
|
||||
|
||||
Get notified when documents are processed:
|
||||
|
||||
```env
|
||||
NOTIFICATION_ENABLED=true
|
||||
NOTIFICATION_EMAIL=you@example.com
|
||||
```
|
||||
|
||||
See [Notifications Setup](NotificationsSetup.md) for webhook, Slack, and other integrations.
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Browse the full [Documentation](UserGuide.md)
|
||||
- Check [Troubleshooting](Troubleshooting.md) for common issues
|
||||
- View [Configuration Reference](ConfigurationGuide.md) for all settings
|
||||
- Explore the [API Reference](API.md) for programmatic access
|
||||
@@ -0,0 +1,154 @@
|
||||
# How to Set Up Automatic Document Ingestion via Email
|
||||
|
||||
Many devices (scanners, printers, fax services, and apps) can send documents as email attachments. This guide explains how to automatically route those attachments into DocuElevate.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Email Ingestion workflow works like this:
|
||||
|
||||
```
|
||||
Scanner/Device → Email (SMTP) → Monitored Mailbox → DocuElevate API → Processing & Storage
|
||||
```
|
||||
|
||||
DocuElevate periodically checks a designated email inbox, downloads PDF/image attachments, and processes them through the standard document pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An email account dedicated to document ingestion (e.g., `scan@yourdomain.com`)
|
||||
- IMAP access enabled for that account
|
||||
- DocuElevate running with the Celery worker active
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following to your DocuElevate `.env` file:
|
||||
|
||||
```env
|
||||
# Email ingestion settings
|
||||
EMAIL_INGESTION_ENABLED=true
|
||||
EMAIL_INGESTION_IMAP_HOST=mail.yourdomain.com
|
||||
EMAIL_INGESTION_IMAP_PORT=993
|
||||
EMAIL_INGESTION_IMAP_SSL=true
|
||||
EMAIL_INGESTION_USERNAME=scan@yourdomain.com
|
||||
EMAIL_INGESTION_PASSWORD=your-email-password
|
||||
EMAIL_INGESTION_FOLDER=INBOX
|
||||
EMAIL_INGESTION_INTERVAL=60 # Check every 60 seconds
|
||||
EMAIL_INGESTION_MARK_SEEN=true # Mark emails as read after processing
|
||||
EMAIL_INGESTION_ALLOWED_SENDERS= # Comma-separated allowlist (empty = allow all)
|
||||
```
|
||||
|
||||
Restart DocuElevate after saving the configuration:
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Supported File Types
|
||||
|
||||
DocuElevate will process the following attachment types from emails:
|
||||
|
||||
| Type | Extension | Notes |
|
||||
|------|-----------|-------|
|
||||
| PDF | `.pdf` | Native support; OCR applied if not searchable |
|
||||
| JPEG/PNG | `.jpg`, `.jpeg`, `.png` | Converted to PDF before processing |
|
||||
| TIFF | `.tif`, `.tiff` | Common format from older scanners/fax |
|
||||
| Multi-page TIFF | `.tif` | Full multi-page support |
|
||||
|
||||
---
|
||||
|
||||
## Setting Up Your Scanner/Device
|
||||
|
||||
### HP Printers – Scan to Email
|
||||
|
||||
See the detailed guide: [HP Enterprise Printer Setup](./HPPrinterSetup.md#option-a-scan-to-email--docuelevate-api-upload)
|
||||
|
||||
### Fujitsu ScanSnap – Send by Email
|
||||
|
||||
See the detailed guide: [ScanSnap Setup](./SnapScanSetup.md#method-3-scan-to-email--docuelevate)
|
||||
|
||||
### iOS/Android Scanning Apps
|
||||
|
||||
Most mobile scanning apps (Adobe Scan, Microsoft Lens, SwiftScan) can email scans:
|
||||
|
||||
1. Scan your document.
|
||||
2. Use the app's **Share** or **Send** function.
|
||||
3. Select **Email** and enter `scan@yourdomain.com`.
|
||||
4. DocuElevate will pick up the attachment within the configured interval.
|
||||
|
||||
### Fax-to-Email Services
|
||||
|
||||
Services like eFax, RingCentral Fax, or Twilio Fax can forward incoming faxes as email attachments. Configure them to send to `scan@yourdomain.com`.
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
> **Important:** Only process emails from trusted sources to avoid ingesting malicious documents.
|
||||
|
||||
Use the `EMAIL_INGESTION_ALLOWED_SENDERS` setting to restrict which email addresses can submit documents:
|
||||
|
||||
```env
|
||||
EMAIL_INGESTION_ALLOWED_SENDERS=scanner@office.com,printer@office.com,fax@office.com
|
||||
```
|
||||
|
||||
DocuElevate will silently skip emails from addresses not in the allowlist.
|
||||
|
||||
Additionally:
|
||||
|
||||
- Use a **dedicated email account** solely for document ingestion
|
||||
- Enable **app-specific passwords** (Gmail, Outlook) instead of your main account password
|
||||
- Store credentials in environment variables, never in config files committed to version control
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
Check the DocuElevate worker logs to verify email ingestion is running:
|
||||
|
||||
```bash
|
||||
docker logs document_worker --follow
|
||||
```
|
||||
|
||||
You should see log entries like:
|
||||
|
||||
```
|
||||
INFO Email ingestion: checking inbox scan@yourdomain.com
|
||||
INFO Email ingestion: found 3 new messages
|
||||
INFO Email ingestion: processing attachment invoice-2024.pdf from printer@office.com
|
||||
INFO Email ingestion: queued document ID 142 for processing
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**No emails are being processed?**
|
||||
→ Verify IMAP credentials and that IMAP is enabled on your mail server.
|
||||
→ Check firewall rules: port 993 (SSL) or 143 (plain) must be open from DocuElevate to the mail server.
|
||||
|
||||
**Gmail not working?**
|
||||
→ Enable "App Passwords" in your Google Account security settings.
|
||||
→ Use the App Password (not your main Google password) for `EMAIL_INGESTION_PASSWORD`.
|
||||
|
||||
**Attachments processed but files are empty?**
|
||||
→ Some email clients send inline images instead of attachments. Check the raw email source.
|
||||
|
||||
**Emails keep getting re-processed?**
|
||||
→ Set `EMAIL_INGESTION_MARK_SEEN=true` to mark emails as read after processing.
|
||||
→ Alternatively, configure a separate ingestion folder and move/delete emails after processing.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [HP Enterprise Printer Setup](./HPPrinterSetup.md)
|
||||
- [ScanSnap Setup](./SnapScanSetup.md)
|
||||
- [Configuration Guide](../ConfigurationGuide.md)
|
||||
- [Notifications Setup](../NotificationsSetup.md)
|
||||
@@ -0,0 +1,198 @@
|
||||
# How to Set Up Automatic Document Ingestion with an HP Enterprise Printer
|
||||
|
||||
This guide explains how to configure an HP Enterprise printer/MFP (Multi-Function Printer) to automatically send scanned documents to DocuElevate for processing and storage.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An HP Enterprise printer or MFP with **Scan to Email** or **Scan to Network Folder** capability
|
||||
- DocuElevate running and accessible on your network
|
||||
- Admin access to the HP printer's Embedded Web Server (EWS)
|
||||
- (Optional) An SMTP server or a configured email address for Scan to Email
|
||||
|
||||
---
|
||||
|
||||
## Option A: Scan to Email → DocuElevate API Upload
|
||||
|
||||
HP Enterprise printers can send scanned documents as email attachments. You can set up a dedicated inbox that forwards documents to DocuElevate via the REST API.
|
||||
|
||||
### Step 1: Configure Scan to Email on the Printer
|
||||
|
||||
1. Open a browser and navigate to the printer's IP address (e.g., `http://192.168.1.100`) to access the **Embedded Web Server (EWS)**.
|
||||
2. Go to **Scan** → **Scan to E-mail**.
|
||||
3. Enable **Scan to E-mail** and configure your SMTP server settings.
|
||||
4. Create a **Quick Set** (shortcut) for the destination:
|
||||
- **From:** `scanner@yourdomain.com`
|
||||
- **To:** `docuelevate-inbox@yourdomain.com` (the receiving address you'll configure)
|
||||
- **File Type:** PDF
|
||||
- **Resolution:** 200–300 DPI (recommended)
|
||||
- **Color Mode:** Grayscale or Black & White for text documents
|
||||
|
||||
### Step 2: Set Up an Email-to-DocuElevate Bridge
|
||||
|
||||
Use a lightweight tool like [imapfilter](https://github.com/lefcha/imapfilter) or a simple Python script (see below) to poll the inbox and upload attachments to DocuElevate via its REST API.
|
||||
|
||||
**Example Python script (`email_to_docuelevate.py`):**
|
||||
|
||||
```python
|
||||
import imaplib
|
||||
import email
|
||||
import requests
|
||||
import os
|
||||
|
||||
IMAP_HOST = "mail.yourdomain.com"
|
||||
IMAP_USER = "docuelevate-inbox@yourdomain.com"
|
||||
IMAP_PASS = os.environ["IMAP_PASS"]
|
||||
DOCUELEVATE_URL = "http://your-docuelevate-host:8000"
|
||||
API_KEY = os.environ["DOCUELEVATE_API_KEY"]
|
||||
|
||||
def fetch_and_upload():
|
||||
mail = imaplib.IMAP4_SSL(IMAP_HOST)
|
||||
mail.login(IMAP_USER, IMAP_PASS)
|
||||
mail.select("INBOX")
|
||||
|
||||
_, msg_ids = mail.search(None, "UNSEEN")
|
||||
for msg_id in msg_ids[0].split():
|
||||
_, msg_data = mail.fetch(msg_id, "(RFC822)")
|
||||
msg = email.message_from_bytes(msg_data[0][1])
|
||||
|
||||
for part in msg.walk():
|
||||
if part.get_content_maintype() == "multipart":
|
||||
continue
|
||||
if part.get("Content-Disposition") is None:
|
||||
continue
|
||||
filename = part.get_filename()
|
||||
if filename and filename.lower().endswith(".pdf"):
|
||||
payload = part.get_payload(decode=True)
|
||||
files = {"file": (filename, payload, "application/pdf")}
|
||||
headers = {"Authorization": f"Bearer {API_KEY}"}
|
||||
resp = requests.post(
|
||||
f"{DOCUELEVATE_URL}/api/upload",
|
||||
files=files,
|
||||
headers=headers
|
||||
)
|
||||
print(f"Uploaded {filename}: {resp.status_code}")
|
||||
mail.store(msg_id, "+FLAGS", "\\Seen")
|
||||
|
||||
mail.logout()
|
||||
|
||||
if __name__ == "__main__":
|
||||
fetch_and_upload()
|
||||
```
|
||||
|
||||
Run this script via a cron job every few minutes:
|
||||
|
||||
```bash
|
||||
*/5 * * * * /usr/bin/python3 /opt/email_to_docuelevate.py >> /var/log/docuelevate_import.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Option B: Scan to Network Folder (SMB/CIFS)
|
||||
|
||||
HP Enterprise printers can scan directly to a network folder. You can configure a watched folder that DocuElevate monitors for new files.
|
||||
|
||||
### Step 1: Set Up a Shared Network Folder
|
||||
|
||||
On your DocuElevate server (or any reachable server), create a shared folder:
|
||||
|
||||
```bash
|
||||
# Create the shared folder
|
||||
mkdir -p /srv/scanner-inbox
|
||||
|
||||
# Install Samba
|
||||
sudo apt-get install samba
|
||||
|
||||
# Add to /etc/samba/smb.conf:
|
||||
[scanner-inbox]
|
||||
path = /srv/scanner-inbox
|
||||
writable = yes
|
||||
guest ok = yes
|
||||
force user = nobody
|
||||
```
|
||||
|
||||
Restart Samba: `sudo systemctl restart smbd`
|
||||
|
||||
### Step 2: Configure the HP Printer for Scan to Network Folder
|
||||
|
||||
1. Open the printer's **Embedded Web Server (EWS)**.
|
||||
2. Go to **Scan** → **Scan to Network Folder**.
|
||||
3. Click **Add** to create a new Quick Set:
|
||||
- **UNC Path:** `\\192.168.1.200\scanner-inbox` (replace with your server's IP)
|
||||
- **Username/Password:** Leave blank for guest, or provide credentials
|
||||
- **File Type:** PDF (Searchable PDF if available)
|
||||
- **Resolution:** 200–300 DPI
|
||||
4. Test the connection from the EWS interface.
|
||||
|
||||
### Step 3: Configure DocuElevate to Watch the Folder
|
||||
|
||||
In your DocuElevate `.env` configuration:
|
||||
|
||||
```env
|
||||
# Enable folder watching
|
||||
WATCH_FOLDER_ENABLED=true
|
||||
WATCH_FOLDER_PATH=/srv/scanner-inbox
|
||||
WATCH_FOLDER_INTERVAL=30 # seconds between checks
|
||||
```
|
||||
|
||||
DocuElevate's Celery worker will automatically detect and process new files placed in the watched folder.
|
||||
|
||||
---
|
||||
|
||||
## Option C: Scan to FTP/WebDAV
|
||||
|
||||
DocuElevate supports FTP and WebDAV as upload targets. HP printers can send scanned documents directly.
|
||||
|
||||
### WebDAV Configuration
|
||||
|
||||
1. In the EWS, go to **Scan** → **Save to SharePoint** or **Save to Network Folder**.
|
||||
2. Some HP models support WebDAV directly — configure the WebDAV URL to point to DocuElevate's WebDAV endpoint (if enabled):
|
||||
- **URL:** `http://your-docuelevate-host:8000/webdav/inbox/`
|
||||
- **Username/Password:** Your DocuElevate credentials
|
||||
|
||||
### FTP Configuration
|
||||
|
||||
1. Ensure an FTP server is running alongside DocuElevate (or configure one in docker-compose).
|
||||
2. In the EWS, configure **Scan to FTP**:
|
||||
- **FTP Server:** `192.168.1.200`
|
||||
- **Port:** `21`
|
||||
- **Remote Path:** `/scanner-inbox/`
|
||||
3. DocuElevate's watch folder will pick up the FTP-delivered files.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Scanner Quick Set Settings
|
||||
|
||||
| Setting | Recommended Value |
|
||||
|---------|------------------|
|
||||
| File Type | PDF (Searchable PDF / PDF/A if available) |
|
||||
| Resolution | 200–300 DPI |
|
||||
| Color Mode | Auto Detect or Grayscale |
|
||||
| Sides | Auto Detect (2-sided) |
|
||||
| Original Size | Auto Detect |
|
||||
| Orientation | Auto Detect |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Printer can't connect to the network folder?**
|
||||
→ Verify the IP address and that the Samba/SMB service is running. Check firewall rules (port 445/TCP).
|
||||
|
||||
**Scanned PDFs aren't being processed?**
|
||||
→ Check DocuElevate's Celery worker logs: `docker logs document_worker --follow`
|
||||
|
||||
**Email attachments not arriving?**
|
||||
→ Verify SMTP settings on the printer. Check spam filters on the receiving mailbox.
|
||||
|
||||
**Poor OCR quality?**
|
||||
→ Increase scan resolution to 300 DPI and use Grayscale mode for text documents.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DocuElevate Configuration Guide](../ConfigurationGuide.md)
|
||||
- [Storage Architecture](../StorageArchitecture.md)
|
||||
- [Troubleshooting](../Troubleshooting.md)
|
||||
@@ -0,0 +1,152 @@
|
||||
# How to Scan Documents from Your Phone or Tablet
|
||||
|
||||
DocuElevate works seamlessly with mobile scanning apps. This guide covers the best ways to capture documents with your phone or tablet and get them into DocuElevate automatically.
|
||||
|
||||
---
|
||||
|
||||
## Option 1: DocuElevate Web Upload (Simplest)
|
||||
|
||||
The easiest way is to use DocuElevate's built-in web interface directly from your mobile browser.
|
||||
|
||||
1. Open your phone's browser and navigate to your DocuElevate instance (e.g., `http://your-docuelevate-host:8000`).
|
||||
2. Tap **Upload** in the top navigation.
|
||||
3. Tap **Choose File** — your phone will open the camera or file picker.
|
||||
4. Select **Camera** to capture a photo of the document, or pick an existing file.
|
||||
5. Tap **Upload** — DocuElevate will process the image and convert it to a searchable PDF.
|
||||
|
||||
> **Tip:** Use good lighting and hold the phone steady for better OCR quality.
|
||||
|
||||
---
|
||||
|
||||
## Option 2: DocuElevate Browser Extension
|
||||
|
||||
The **DocuElevate Browser Extension** for Chrome/Firefox allows one-tap uploading from your mobile browser.
|
||||
|
||||
See the [Browser Extension guide](../BrowserExtension.md) for installation and setup instructions.
|
||||
|
||||
---
|
||||
|
||||
## Option 3: Mobile Scanning Apps
|
||||
|
||||
These apps provide superior document capture (auto perspective correction, multi-page, etc.) and can send directly to DocuElevate.
|
||||
|
||||
### Microsoft Lens (iOS / Android)
|
||||
|
||||
Microsoft Lens is free and integrates with OneDrive, which DocuElevate supports natively.
|
||||
|
||||
1. Install **Microsoft Lens** from the App Store or Google Play.
|
||||
2. Scan your document.
|
||||
3. Save to **OneDrive** in a folder you've connected to DocuElevate.
|
||||
4. DocuElevate will automatically process new files in your OneDrive folder.
|
||||
|
||||
### Adobe Scan (iOS / Android)
|
||||
|
||||
Adobe Scan produces high-quality searchable PDFs.
|
||||
|
||||
1. Install **Adobe Scan** from the App Store or Google Play.
|
||||
2. Scan your document.
|
||||
3. Tap **Share** → **Save to Files** (iOS) or **Share** (Android).
|
||||
4. Choose to save to your connected cloud storage (Dropbox, Google Drive) monitored by DocuElevate.
|
||||
|
||||
**Or use email ingestion:**
|
||||
1. Tap **Share** → **Email**.
|
||||
2. Send to your DocuElevate ingestion email address.
|
||||
3. See [Email Ingestion Setup](./EmailIngestion.md) for configuration.
|
||||
|
||||
### SwiftScan (iOS)
|
||||
|
||||
SwiftScan (formerly Scanbot) offers excellent auto-capture and document enhancement.
|
||||
|
||||
1. Install **SwiftScan** from the App Store.
|
||||
2. Scan your document.
|
||||
3. Configure the **Auto-Upload** feature:
|
||||
- Go to **Settings** → **Cloud Services**.
|
||||
- Connect Dropbox, Google Drive, or OneDrive.
|
||||
- Set the upload folder to your DocuElevate-monitored folder.
|
||||
4. Every scan is automatically uploaded and processed by DocuElevate.
|
||||
|
||||
### CamScanner (iOS / Android)
|
||||
|
||||
1. Install **CamScanner**.
|
||||
2. Configure **Auto Backup** to Dropbox or Google Drive.
|
||||
3. Point DocuElevate at the same cloud folder.
|
||||
|
||||
---
|
||||
|
||||
## Option 4: iOS Shortcuts Automation
|
||||
|
||||
On iPhone/iPad, you can create an **iOS Shortcut** that scans a document and uploads it directly to DocuElevate's API.
|
||||
|
||||
### Creating the Shortcut
|
||||
|
||||
1. Open the **Shortcuts** app on your iPhone.
|
||||
2. Tap **+** to create a new shortcut.
|
||||
3. Add the following actions:
|
||||
- **Scan Document** — opens the camera for scanning
|
||||
- **Get Contents of URL** — configures the API call:
|
||||
- **URL:** `http://your-docuelevate-host:8000/api/upload`
|
||||
- **Method:** POST
|
||||
- **Headers:** `Authorization: Bearer YOUR_API_KEY`
|
||||
- **Request Body:** Form data with `file` = Scanned Document
|
||||
4. Name the shortcut "Send to DocuElevate".
|
||||
5. Add it to your home screen for one-tap scanning.
|
||||
|
||||
```
|
||||
Shortcut flow:
|
||||
┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐
|
||||
│ Scan Document│ → │ Select pages │ → │ POST to DocuElevate │
|
||||
│ (Camera) │ │ & crop │ │ /api/upload │
|
||||
└─────────────┘ └──────────────┘ └──────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Option 5: Android Automation with Tasker
|
||||
|
||||
On Android, **Tasker** can automate document upload when files appear in a specific folder.
|
||||
|
||||
1. Install **Tasker** from Google Play.
|
||||
2. Create a **Profile** triggered by **File Created** in your scanner app's output folder.
|
||||
3. Add a **Task** that calls DocuElevate's upload API using the **HTTP Request** action.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Mobile Scanning Settings
|
||||
|
||||
For best results with DocuElevate's OCR engine:
|
||||
|
||||
| Setting | Recommended Value |
|
||||
|---------|------------------|
|
||||
| Output Format | PDF |
|
||||
| Resolution/Quality | High (equivalent to 300 DPI) |
|
||||
| Color Mode | Auto (greyscale for text, color for mixed) |
|
||||
| Perspective Correction | On (auto-straighten) |
|
||||
| Filter | Document / Black & White for text |
|
||||
| Multi-page | Combine into single PDF |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Upload fails from mobile browser?**
|
||||
→ Check that DocuElevate is accessible from your phone's network (same WiFi, or publicly reachable).
|
||||
→ Verify your session is still logged in.
|
||||
|
||||
**OCR quality is poor?**
|
||||
→ Ensure good lighting, no shadows on the document.
|
||||
→ Use your scanning app's auto-enhance or document filter.
|
||||
→ Increase resolution to "High" or "Best" in the app settings.
|
||||
|
||||
**Files synced to cloud but not processed?**
|
||||
→ Check DocuElevate's cloud storage connection in Settings.
|
||||
→ View worker logs: `docker logs document_worker --tail 50`
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Email Ingestion Setup](./EmailIngestion.md)
|
||||
- [HP Enterprise Printer Setup](./HPPrinterSetup.md)
|
||||
- [ScanSnap Setup](./SnapScanSetup.md)
|
||||
- [Browser Extension](../BrowserExtension.md)
|
||||
- [API Reference](../API.md)
|
||||
@@ -0,0 +1,192 @@
|
||||
# How to Set Up Fujitsu ScanSnap to Automatically Send Documents to DocuElevate
|
||||
|
||||
This guide walks you through configuring a Fujitsu ScanSnap scanner to automatically upload scanned documents to DocuElevate for AI-powered processing and storage.
|
||||
|
||||
---
|
||||
|
||||
## Supported ScanSnap Models
|
||||
|
||||
This guide applies to the following ScanSnap models:
|
||||
|
||||
- **iX1600 / iX1500 / iX1400** – Wi-Fi and USB, ScanSnap Home software
|
||||
- **iX500 / iX100** – USB/Wi-Fi, ScanSnap Manager software
|
||||
- **S1300i / S1100i** – USB, ScanSnap Manager software
|
||||
|
||||
> **Note:** ScanSnap Home (for newer models) and ScanSnap Manager (for older models) differ in their profile/job configuration interface. Both methods are covered below.
|
||||
|
||||
---
|
||||
|
||||
## Method 1: Scan to Folder → DocuElevate Watched Folder
|
||||
|
||||
This is the simplest method and works with all ScanSnap models.
|
||||
|
||||
### Step 1: Configure DocuElevate's Watched Folder
|
||||
|
||||
Add the following to your DocuElevate `.env` file and restart the service:
|
||||
|
||||
```env
|
||||
WATCH_FOLDER_ENABLED=true
|
||||
WATCH_FOLDER_PATH=/srv/scan-inbox
|
||||
WATCH_FOLDER_INTERVAL=10
|
||||
```
|
||||
|
||||
Create the directory and set permissions:
|
||||
|
||||
```bash
|
||||
mkdir -p /srv/scan-inbox
|
||||
chmod 777 /srv/scan-inbox
|
||||
```
|
||||
|
||||
If running DocuElevate in Docker, mount this folder into the container in your `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
api:
|
||||
volumes:
|
||||
- /srv/scan-inbox:/srv/scan-inbox
|
||||
worker:
|
||||
volumes:
|
||||
- /srv/scan-inbox:/srv/scan-inbox
|
||||
```
|
||||
|
||||
### Step 2: Configure ScanSnap Home (iX1600/iX1500/iX1400)
|
||||
|
||||
1. Open **ScanSnap Home** on your computer.
|
||||
2. Click **+** to create a new profile.
|
||||
3. Select **Save to folder** as the action.
|
||||
4. Configure the profile:
|
||||
- **Folder:** `/srv/scan-inbox` (or a local folder that syncs to it)
|
||||
- **File format:** PDF
|
||||
- **Image quality:** Normal or Better
|
||||
- **Color mode:** Auto
|
||||
- **Scanning side:** Both sides (auto)
|
||||
5. Enable **Convert to searchable PDF** if your ScanSnap and ScanSnap Home version support it.
|
||||
6. Name the profile "DocuElevate" and save.
|
||||
|
||||
Now, pressing the scan button while this profile is active will send the scanned PDF directly to the watched folder.
|
||||
|
||||
### Step 3: Configure ScanSnap Manager (older models)
|
||||
|
||||
1. Right-click the ScanSnap Manager icon in the system tray.
|
||||
2. Select **Scan Button Settings**.
|
||||
3. Choose the **Save** tab.
|
||||
4. Set **Image saving folder** to `/srv/scan-inbox` (or use a shared network path).
|
||||
5. Under **File format**, select **PDF**.
|
||||
6. Click **OK** to save.
|
||||
|
||||
---
|
||||
|
||||
## Method 2: Scan to Cloud Storage → DocuElevate Sync
|
||||
|
||||
If you already use Dropbox, Google Drive, or OneDrive with ScanSnap, you can leverage those integrations to feed documents into DocuElevate.
|
||||
|
||||
### Using Dropbox
|
||||
|
||||
1. In ScanSnap Home, create a profile with action **Save to Dropbox**.
|
||||
2. Set the destination folder to `ScanSnap/` (or any folder).
|
||||
3. In DocuElevate settings, configure Dropbox as your storage provider and point DocuElevate to monitor/pull from that folder.
|
||||
4. DocuElevate will process new documents as they appear in Dropbox.
|
||||
|
||||
### Using Google Drive
|
||||
|
||||
1. Create a ScanSnap profile that saves to **Google Drive** under a dedicated folder (e.g., `ScanSnap/Inbox`).
|
||||
2. Configure DocuElevate's Google Drive integration to use that folder as a source/destination.
|
||||
|
||||
---
|
||||
|
||||
## Method 3: Scan to Email → DocuElevate
|
||||
|
||||
ScanSnap can send scanned documents as email attachments. Pair this with the email-to-DocuElevate bridge described in the [HP Printer Guide](./HPPrinterSetup.md#option-a-scan-to-email--docuelevate-api-upload) for automatic ingestion.
|
||||
|
||||
1. In ScanSnap Home, create a profile with action **Send by E-mail**.
|
||||
2. Configure the recipient address as your DocuElevate-monitored mailbox.
|
||||
3. Set file format to **PDF**.
|
||||
4. The email bridge script will pick up the attachment and upload it to DocuElevate.
|
||||
|
||||
---
|
||||
|
||||
## Method 4: ScanSnap Cloud (iX1600 / ScanSnap Home 3.x+)
|
||||
|
||||
The ScanSnap iX1600 supports **ScanSnap Cloud**, which can send directly to cloud services.
|
||||
|
||||
1. Open the **ScanSnap Home** app or use the printer's touchscreen.
|
||||
2. Configure a **ScanSnap Cloud** profile that saves to **Google Drive** or **Dropbox**.
|
||||
3. Point DocuElevate to monitor that cloud folder.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Scan Settings
|
||||
|
||||
| Setting | Recommended Value |
|
||||
|---------|------------------|
|
||||
| File Format | PDF (Searchable PDF if available) |
|
||||
| Image Quality | Normal (200 DPI) for text, Better (300 DPI) for photos |
|
||||
| Color Mode | Auto (detects black/white vs color) |
|
||||
| Scanning Side | Both Sides (Auto) |
|
||||
| Compression | Medium |
|
||||
| Rotate | Auto |
|
||||
| Remove blank pages | Yes |
|
||||
| Correct skewed scans | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Automating with ScanSnap Home Profiles
|
||||
|
||||
You can create multiple profiles in ScanSnap Home for different document types:
|
||||
|
||||
| Profile | Settings | Notes |
|
||||
|---------|----------|-------|
|
||||
| **Documents** | B&W, 200 DPI, PDF | For invoices, letters, contracts |
|
||||
| **Photos** | Color, 300 DPI, PDF | For photo documents |
|
||||
| **Receipts** | B&W, 200 DPI, PDF, Remove blank pages | For expense reports |
|
||||
| **Business Cards** | Color, 300 DPI, JPEG | May require separate OCR |
|
||||
|
||||
Each profile can be assigned to the scanner's shortcut button (on models with a touchscreen).
|
||||
|
||||
---
|
||||
|
||||
## Setting Up One-Button Scanning
|
||||
|
||||
On the **ScanSnap iX1600** with its touchscreen:
|
||||
|
||||
1. Tap the profile name (e.g., "DocuElevate") on the scanner's display.
|
||||
2. The scanner will use that profile for the next scan.
|
||||
3. Press the physical **Scan** button.
|
||||
4. The document is scanned and automatically delivered to DocuElevate's watched folder.
|
||||
|
||||
On models without a touchscreen:
|
||||
|
||||
1. Set the "DocuElevate" profile as the **default profile** in ScanSnap Manager/Home.
|
||||
2. Press the **Scan** button — the document goes directly to DocuElevate.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Files appear in the folder but DocuElevate doesn't process them?**
|
||||
→ Check that `WATCH_FOLDER_ENABLED=true` in your `.env` and that the worker can read the folder:
|
||||
```bash
|
||||
docker logs document_worker --tail 50
|
||||
```
|
||||
|
||||
**ScanSnap can't find the network folder?**
|
||||
→ Ensure the folder is shared over SMB/CIFS (Windows share). See the [HP Printer Setup guide](./HPPrinterSetup.md#step-1-set-up-a-shared-network-folder) for Samba configuration.
|
||||
|
||||
**Scanned PDFs have poor text recognition?**
|
||||
→ Increase scan resolution to 300 DPI. Enable "Convert to searchable PDF" in ScanSnap Home if available.
|
||||
|
||||
**Files are processed twice (duplicates)?**
|
||||
→ Enable duplicate detection in DocuElevate settings. Check [Troubleshooting](../Troubleshooting.md) for deduplication options.
|
||||
|
||||
**ScanSnap doesn't appear in ScanSnap Home after network change?**
|
||||
→ Re-run the ScanSnap network setup wizard. Ensure the scanner and your computer are on the same Wi-Fi network/subnet.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [HP Enterprise Printer Setup](./HPPrinterSetup.md)
|
||||
- [DocuElevate Configuration Guide](../ConfigurationGuide.md)
|
||||
- [Dropbox Setup](../DropboxSetup.md)
|
||||
- [Google Drive Setup](../GoogleDriveSetup.md)
|
||||
- [Troubleshooting](../Troubleshooting.md)
|
||||
@@ -0,0 +1,212 @@
|
||||
# How to Set Up a Watched Folder for Automatic Document Ingestion
|
||||
|
||||
The **Watched Folder** feature allows DocuElevate to automatically detect and process documents placed in a specific local directory. Any scanner, application, or script that saves files to that folder will have its output automatically ingested.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
```
|
||||
Scanner / Any App → Drop files in folder → DocuElevate watches for new files → Process & Store
|
||||
```
|
||||
|
||||
This is one of the simplest ingestion methods and works with virtually any scanner, OCR app, or document workflow tool.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Add these settings to your `.env` file:
|
||||
|
||||
```env
|
||||
WATCH_FOLDER_ENABLED=true
|
||||
WATCH_FOLDER_PATH=/srv/docuelevate/watch
|
||||
WATCH_FOLDER_INTERVAL=30 # Polling interval in seconds
|
||||
WATCH_FOLDER_RECURSIVE=false # Watch subdirectories too
|
||||
WATCH_FOLDER_DELETE_AFTER=true # Delete originals after successful processing
|
||||
WATCH_FOLDER_EXTENSIONS=pdf,jpg,jpeg,png,tiff,tif
|
||||
```
|
||||
|
||||
**Restart** the services after editing:
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Setup
|
||||
|
||||
When running DocuElevate with Docker Compose, mount the watch folder into both the `api` and `worker` containers:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yaml
|
||||
services:
|
||||
api:
|
||||
volumes:
|
||||
- /srv/docuelevate/watch:/srv/docuelevate/watch
|
||||
- /var/docparse/workdir:/workdir
|
||||
|
||||
worker:
|
||||
volumes:
|
||||
- /srv/docuelevate/watch:/srv/docuelevate/watch
|
||||
- /var/docparse/workdir:/workdir
|
||||
```
|
||||
|
||||
Create the folder and set permissions:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /srv/docuelevate/watch
|
||||
sudo chmod 777 /srv/docuelevate/watch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multiple Watch Folders
|
||||
|
||||
If you have multiple scanners or document sources, you can organize them by subfolder:
|
||||
|
||||
```
|
||||
/srv/docuelevate/watch/
|
||||
├── reception/ ← Front desk scanner
|
||||
├── accounting/ ← Finance team scanner
|
||||
├── hr/ ← HR department
|
||||
└── general/ ← General purpose
|
||||
```
|
||||
|
||||
Enable recursive watching:
|
||||
|
||||
```env
|
||||
WATCH_FOLDER_RECURSIVE=true
|
||||
```
|
||||
|
||||
DocuElevate will monitor all subdirectories and tag documents with the subfolder name for easy filtering.
|
||||
|
||||
---
|
||||
|
||||
## Using with Network Scanners
|
||||
|
||||
### Windows / Samba Share
|
||||
|
||||
Share the watch folder over the network so scanners and Windows PCs can drop files directly:
|
||||
|
||||
```bash
|
||||
# Install Samba
|
||||
sudo apt-get install samba -y
|
||||
|
||||
# Add to /etc/samba/smb.conf
|
||||
[DocuElevate-Inbox]
|
||||
comment = DocuElevate Document Inbox
|
||||
path = /srv/docuelevate/watch
|
||||
browsable = yes
|
||||
guest ok = yes
|
||||
read only = no
|
||||
create mask = 0777
|
||||
directory mask = 0777
|
||||
```
|
||||
|
||||
Restart Samba:
|
||||
```bash
|
||||
sudo systemctl restart smbd nmbd
|
||||
```
|
||||
|
||||
Windows access: `\\your-server-ip\DocuElevate-Inbox`
|
||||
|
||||
### NFS Share (Linux)
|
||||
|
||||
```bash
|
||||
# Add to /etc/exports
|
||||
/srv/docuelevate/watch 192.168.1.0/24(rw,sync,no_subtree_check)
|
||||
|
||||
# Apply changes
|
||||
sudo exportfs -ra
|
||||
```
|
||||
|
||||
### FTP Server (for older devices)
|
||||
|
||||
Many older scanners only support FTP. Run a simple FTP server alongside DocuElevate:
|
||||
|
||||
```yaml
|
||||
# Add to docker-compose.yaml
|
||||
services:
|
||||
ftp:
|
||||
image: garethflowers/ftp-server
|
||||
container_name: docuelevate_ftp
|
||||
environment:
|
||||
- FTP_USER=scanner
|
||||
- FTP_PASS=changeme
|
||||
ports:
|
||||
- "21:21"
|
||||
- "20:20"
|
||||
- "21100-21110:21100-21110"
|
||||
volumes:
|
||||
- /srv/docuelevate/watch:/home/scanner
|
||||
```
|
||||
|
||||
Configure your scanner's FTP settings to use this server. Files will land in the watched folder.
|
||||
|
||||
---
|
||||
|
||||
## Supported File Types
|
||||
|
||||
| Format | Extension | Notes |
|
||||
|--------|-----------|-------|
|
||||
| PDF | `.pdf` | OCR applied if not already searchable |
|
||||
| JPEG | `.jpg`, `.jpeg` | Converted to PDF |
|
||||
| PNG | `.png` | Converted to PDF |
|
||||
| TIFF | `.tif`, `.tiff` | Supports multi-page TIFF |
|
||||
| HEIC | `.heic` | iPhone photos (converted) |
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
Check that the watched folder is active:
|
||||
|
||||
```bash
|
||||
# View worker logs
|
||||
docker logs document_worker --follow
|
||||
|
||||
# Expected output:
|
||||
# INFO Watch folder monitor: watching /srv/docuelevate/watch (interval: 30s)
|
||||
# INFO Watch folder: found new file invoice.pdf
|
||||
# INFO Watch folder: queued document ID 156 for processing
|
||||
```
|
||||
|
||||
You can also view processing status in the DocuElevate web interface under **Queue Monitor**.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Files are dropped but not picked up?**
|
||||
- Verify `WATCH_FOLDER_ENABLED=true` in `.env`
|
||||
- Check that `WATCH_FOLDER_PATH` matches the mounted path in docker-compose
|
||||
- Look at worker logs: `docker logs document_worker --tail 100`
|
||||
|
||||
**Permission denied errors?**
|
||||
```bash
|
||||
# Fix permissions
|
||||
sudo chmod -R 777 /srv/docuelevate/watch
|
||||
# Or use ACLs for more granular control
|
||||
sudo setfacl -m u:nobody:rwx /srv/docuelevate/watch
|
||||
```
|
||||
|
||||
**Files processed but not deleted?**
|
||||
- Set `WATCH_FOLDER_DELETE_AFTER=true`
|
||||
- If you want to keep originals, set to `false` and manage cleanup separately
|
||||
|
||||
**File appears partially uploaded?**
|
||||
- Large files may arrive before the scanner finishes writing them
|
||||
- Increase `WATCH_FOLDER_INTERVAL` to give time for files to be fully written
|
||||
- DocuElevate uses file-lock detection to avoid processing incomplete files
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [HP Enterprise Printer Setup](./HPPrinterSetup.md)
|
||||
- [ScanSnap Setup](./SnapScanSetup.md)
|
||||
- [Email Ingestion](./EmailIngestion.md)
|
||||
- [Configuration Guide](../ConfigurationGuide.md)
|
||||
- [Deployment Guide](../DeploymentGuide.md)
|
||||
@@ -76,6 +76,12 @@
|
||||
{% if request and request.url.path == '/about' %}aria-current="page"{% endif %}>
|
||||
About
|
||||
</a>
|
||||
<a href="/help/"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
title="Help & How-To Guides"
|
||||
{% if request and request.url.path.startswith('/help') %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-1 text-gray-400" aria-hidden="true"></i>Help
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
{# ── App nav (logged-in or single-user / auth-disabled mode) ────── #}
|
||||
@@ -171,6 +177,14 @@
|
||||
<i class="fas fa-circle-dot mr-0.5" aria-hidden="true"></i> Status
|
||||
</a>
|
||||
|
||||
<!-- Help documentation – visible to all users -->
|
||||
<a href="/help/"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
title="Help & How-To Guides"
|
||||
{% if request and request.url.path.startswith('/help') %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-1 text-gray-400" aria-hidden="true"></i>Help
|
||||
</a>
|
||||
|
||||
{% endif %}{# end multi_user_enabled / is_logged_in check #}
|
||||
|
||||
<!-- Dark mode toggle -->
|
||||
@@ -229,6 +243,11 @@
|
||||
{% if request and request.url.path == '/about' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-info-circle mr-2 text-gray-400" aria-hidden="true"></i>About
|
||||
</a>
|
||||
<a href="/help/"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path.startswith('/help') %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-2 text-gray-400" aria-hidden="true"></i>Help
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
{# ── App links (logged-in or single-user) ────────────────────── #}
|
||||
@@ -298,6 +317,13 @@
|
||||
<i class="fas fa-circle-dot mr-1" aria-hidden="true"></i> Status
|
||||
</a>
|
||||
|
||||
<!-- Help documentation -->
|
||||
<a href="/help/"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path.startswith('/help') %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-2 text-gray-400" aria-hidden="true"></i>Help
|
||||
</a>
|
||||
|
||||
{% endif %}{# end multi_user_enabled / is_logged_in check #}
|
||||
|
||||
<!-- Dark mode toggle (mobile) -->
|
||||
|
||||
+23
@@ -12,11 +12,34 @@ theme:
|
||||
- navigation.instant
|
||||
- search.suggest
|
||||
- content.code.copy
|
||||
- navigation.sections
|
||||
- navigation.top
|
||||
- toc.integrate
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: blue
|
||||
accent: blue
|
||||
toggle:
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
- scheme: slate
|
||||
primary: blue
|
||||
accent: blue
|
||||
toggle:
|
||||
icon: material/brightness-4
|
||||
name: Switch to light mode
|
||||
nav:
|
||||
- Getting Started:
|
||||
- Setup Wizard: SetupWizard
|
||||
- User Guide: UserGuide
|
||||
- Browser Extension: BrowserExtension
|
||||
- How-To Guides:
|
||||
- Overview: HowToGuides.md
|
||||
- HP Enterprise Printer: howto/HPPrinterSetup.md
|
||||
- Fujitsu ScanSnap: howto/SnapScanSetup.md
|
||||
- Watched Folder: howto/WatchedFolderSetup.md
|
||||
- Email Ingestion: howto/EmailIngestion.md
|
||||
- Mobile Scanning: howto/MobileScanning.md
|
||||
- API: API
|
||||
- Deployment:
|
||||
- Overview: DeploymentGuide
|
||||
|
||||
@@ -19,6 +19,9 @@ ruff>=0.3.0
|
||||
mypy>=1.8.0
|
||||
djlint>=1.36.0 # HTML template linter for accessibility and best practices
|
||||
|
||||
# Documentation (builds the embedded /help site via MkDocs Material)
|
||||
mkdocs-material>=9.5.0 # MkDocs Material theme – same package used in docs/requirements.txt
|
||||
|
||||
# Type stubs for mypy
|
||||
types-requests>=2.31.0
|
||||
types-paramiko>=3.0.0
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
"""Tests for app/views/help.py module."""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestHelpViews:
|
||||
"""Tests for the help documentation view routes."""
|
||||
|
||||
def test_help_redirect(self, client):
|
||||
"""GET /help should redirect permanently to /help/."""
|
||||
response = client.get("/help", follow_redirects=False)
|
||||
assert response.status_code == 301
|
||||
assert response.headers["location"] in ("/help/", "http://testserver/help/")
|
||||
|
||||
def test_help_redirect_follows(self, client):
|
||||
"""Following /help redirect leads to /help/ (docs served or 404 if not built)."""
|
||||
# In test environments docs_build/ is not present, so /help/ may 404.
|
||||
# We only verify the initial redirect works; the final landing page depends
|
||||
# on whether the docs have been built (they are built only in Docker images).
|
||||
response = client.get("/help", follow_redirects=False)
|
||||
assert response.status_code == 301
|
||||
# Redirect target must be /help/
|
||||
location = response.headers.get("location", "")
|
||||
assert location.endswith("/help/")
|
||||
|
||||
def test_help_route_is_registered(self, client):
|
||||
"""Verify the /help route exists in the app router."""
|
||||
# A GET to /help must not return 405 Method Not Allowed
|
||||
response = client.get("/help", follow_redirects=False)
|
||||
assert response.status_code != 405
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestHelpViewUnit:
|
||||
"""Unit tests for the help view module."""
|
||||
|
||||
def test_help_redirect_returns_301(self):
|
||||
"""Verify the redirect is HTTP 301 (permanent)."""
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.views.help import router
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
with TestClient(app) as tc:
|
||||
resp = tc.get("/help", follow_redirects=False)
|
||||
assert resp.status_code == 301
|
||||
|
||||
def test_help_redirect_target(self):
|
||||
"""Verify the redirect points to /help/."""
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.views.help import router
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
with TestClient(app) as tc:
|
||||
resp = tc.get("/help", follow_redirects=False)
|
||||
assert resp.headers["location"].rstrip("/").endswith("help") or resp.headers["location"].endswith("/help/")
|
||||
|
||||
def test_docs_build_path_constant(self):
|
||||
"""Verify _DOCS_BUILD_DIR is resolved relative to the app package."""
|
||||
import pathlib
|
||||
|
||||
from app.views.help import _DOCS_BUILD_DIR
|
||||
|
||||
assert isinstance(_DOCS_BUILD_DIR, pathlib.Path)
|
||||
# Should point to <repo_root>/docs_build
|
||||
assert _DOCS_BUILD_DIR.name == "docs_build"
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestHelpNavigationLink:
|
||||
"""Tests that the Help link appears in the navigation."""
|
||||
|
||||
def test_help_link_in_nav(self, client):
|
||||
"""The Help navigation link should appear in the base template."""
|
||||
response = client.get("/about")
|
||||
assert response.status_code == 200
|
||||
# The Help link should be present somewhere in the rendered page
|
||||
assert b"/help/" in response.content
|
||||
|
||||
def test_help_link_has_accessible_text(self, client):
|
||||
"""The Help link should have visible text for accessibility."""
|
||||
response = client.get("/about")
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
# Should include the word "Help" associated with /help/
|
||||
assert "Help" in content
|
||||
Reference in New Issue
Block a user