Merge branch 'main' into copilot/add-conditional-routing
Resolve conflicts in app/api/__init__.py and app/models.py. Renumber migration 027_add_routing_rules → 035_add_routing_rules. Fix migration chain: down_revision → 034_add_user_profile_settings. Add PipelineRoutingRule to migrations/env.py.
This commit is contained in:
+188
@@ -2217,3 +2217,191 @@ print(response.json())
|
||||
## Further Assistance
|
||||
|
||||
For additional help with the API, please contact our support team or refer to the [Development Guide](../CONTRIBUTING.md).
|
||||
|
||||
## Mobile App API
|
||||
|
||||
The mobile API provides endpoints used by the native iOS and Android app. All endpoints require authentication (Bearer token or active session cookie).
|
||||
|
||||
For full mobile app documentation see [MobileApp.md](./MobileApp.md).
|
||||
|
||||
### POST /api/mobile/generate-token
|
||||
|
||||
Exchange an active web session for a long-lived API token scoped to the mobile app.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{ "device_name": "John's iPhone" }
|
||||
```
|
||||
|
||||
**Response (201 Created):**
|
||||
```json
|
||||
{
|
||||
"token": "de_AbCdEfGhIjKl...",
|
||||
"token_id": 42,
|
||||
"name": "Mobile App – John's iPhone",
|
||||
"created_at": "2026-03-10T09:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
> The `token` is shown **once only**.
|
||||
|
||||
### POST /api/mobile/register-device
|
||||
|
||||
Register an Expo push token to receive push notifications.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"push_token": "ExponentPushToken[xxxxxx]",
|
||||
"device_name": "John's iPhone",
|
||||
"platform": "ios"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (201 Created):** Device record with `id`, `platform`, `is_active`, `created_at`.
|
||||
|
||||
### GET /api/mobile/devices
|
||||
|
||||
List all registered push-notification devices for the current user.
|
||||
|
||||
**Response (200 OK):** Array of device records.
|
||||
|
||||
### DELETE /api/mobile/devices/{device_id}
|
||||
|
||||
Deactivate a push-notification device. The device will no longer receive push notifications.
|
||||
|
||||
**Response (204 No Content)**
|
||||
|
||||
### GET /api/mobile/whoami
|
||||
|
||||
Return basic profile information for the authenticated user.
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"owner_id": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/...",
|
||||
"is_admin": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GraphQL API
|
||||
|
||||
DocuElevate exposes a GraphQL API at `/graphql` alongside the REST API. It
|
||||
supports flexible queries with field selection, making it ideal for dashboards
|
||||
and integrations that only need a subset of the available data.
|
||||
|
||||
### Endpoint
|
||||
|
||||
| Method | URL | Description |
|
||||
|--------|-----|-------------|
|
||||
| `POST` | `/graphql` | Execute a GraphQL query or mutation |
|
||||
| `GET` | `/graphql` | Open the GraphiQL interactive playground |
|
||||
|
||||
### Authentication
|
||||
|
||||
The GraphQL endpoint honours the same authentication rules as the REST API:
|
||||
|
||||
- **`AUTH_ENABLED=False`** (default, single-user mode): all queries are
|
||||
allowed without credentials.
|
||||
- **`AUTH_ENABLED=True`** (multi-user mode): a valid session cookie **or**
|
||||
an `Authorization: Bearer <token>` API token is required. Admin-only
|
||||
queries (settings, users) additionally require the `is_admin` flag.
|
||||
|
||||
### Available Queries
|
||||
|
||||
| Field | Returns | Notes |
|
||||
|-------|---------|-------|
|
||||
| `documents(ownerId, limit, offset)` | `[DocumentType]` | Paginated list of documents |
|
||||
| `document(id)` | `DocumentType` | Single document by primary key |
|
||||
| `pipelines(ownerId, limit, offset)` | `[PipelineType]` | Paginated list of pipelines with steps |
|
||||
| `pipeline(id)` | `PipelineType` | Single pipeline by primary key |
|
||||
| `settings(limit, offset)` | `[SettingType]` | Non-sensitive app settings (**admin only**) |
|
||||
| `users(limit, offset)` | `[UserType]` | User profiles (**admin only**) |
|
||||
| `user(userId)` | `UserType` | Single user profile (**admin only**) |
|
||||
|
||||
> **Note:** Sensitive configuration keys (API secrets, passwords, tokens) are
|
||||
> automatically excluded from the `settings` query regardless of the caller's
|
||||
> privilege level.
|
||||
|
||||
### GraphiQL Playground
|
||||
|
||||
Navigate to `http://<your-instance>/graphql` in a browser to open the
|
||||
interactive GraphiQL IDE, which provides schema documentation, auto-complete,
|
||||
and the ability to run queries directly.
|
||||
|
||||
### Example Queries
|
||||
|
||||
**List recent documents:**
|
||||
```graphql
|
||||
{
|
||||
documents(limit: 5) {
|
||||
id
|
||||
originalFilename
|
||||
mimeType
|
||||
fileSize
|
||||
documentTitle
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Fetch a pipeline with its steps:**
|
||||
```graphql
|
||||
{
|
||||
pipeline(id: 1) {
|
||||
id
|
||||
name
|
||||
description
|
||||
isDefault
|
||||
isActive
|
||||
steps {
|
||||
position
|
||||
stepType
|
||||
label
|
||||
enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**List application settings (admin only):**
|
||||
```graphql
|
||||
{
|
||||
settings {
|
||||
key
|
||||
value
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**List user profiles (admin only):**
|
||||
```graphql
|
||||
{
|
||||
users(limit: 10) {
|
||||
userId
|
||||
displayName
|
||||
subscriptionTier
|
||||
isBlocked
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Using variables:**
|
||||
```graphql
|
||||
query GetDocument($id: Int!) {
|
||||
document(id: $id) {
|
||||
id
|
||||
originalFilename
|
||||
documentTitle
|
||||
isDuplicate
|
||||
ocrQualityScore
|
||||
}
|
||||
}
|
||||
```
|
||||
Variables: `{ "id": 42 }`
|
||||
|
||||
@@ -20,10 +20,11 @@ For a complete list of configuration options, see the [Configuration Guide](Conf
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
DocuElevate supports two primary authentication methods:
|
||||
DocuElevate supports multiple authentication methods that can be used independently or together:
|
||||
|
||||
1. **Simple Authentication** - Basic username/password authentication managed by DocuElevate
|
||||
2. **OpenID Connect** - Integration with identity providers like Authentik, Keycloak, or Auth0
|
||||
3. **Social Login** - Sign in with Google, Microsoft, Apple, or Dropbox accounts (see [Social Login Setup Guide](SocialLoginSetup.md))
|
||||
|
||||
## Session Security
|
||||
|
||||
@@ -189,3 +190,11 @@ If you encounter issues with authentication:
|
||||
- For most providers, you can visit the `/.well-known/openid-configuration` endpoint to verify their settings
|
||||
|
||||
For more general configuration issues, see the [Configuration Troubleshooting Guide](ConfigurationTroubleshooting.md).
|
||||
|
||||
## Social Login
|
||||
|
||||
DocuElevate supports social login with Google, Microsoft, Apple, and Dropbox. Social login allows users to authenticate using their existing accounts with these providers, without needing a separate DocuElevate password.
|
||||
|
||||
Social login can be used alongside any other authentication method (simple auth, OIDC, local signup). Each social provider is independently configured.
|
||||
|
||||
For detailed setup instructions, prerequisites, and provider-specific configuration, see the **[Social Login Setup Guide](SocialLoginSetup.md)**.
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
# Compliance Templates Guide
|
||||
|
||||
DocuElevate includes pre-built compliance templates for **GDPR**, **HIPAA**, and **SOC 2** that help you configure your instance to meet regulatory requirements. This guide covers how to use the compliance dashboard, apply templates, and monitor your compliance status.
|
||||
|
||||
## Overview
|
||||
|
||||
The compliance templates feature provides:
|
||||
|
||||
- **Pre-built configurations** for GDPR, HIPAA, and SOC 2
|
||||
- **One-click apply** to configure all required settings at once
|
||||
- **Compliance status dashboard** to monitor your regulatory posture
|
||||
- **Individual check results** showing which settings are compliant and which need attention
|
||||
|
||||
## Accessing the Dashboard
|
||||
|
||||
The compliance dashboard is available to **admin users only**.
|
||||
|
||||
1. Log in as an administrator
|
||||
2. Click **Admin** in the navigation bar
|
||||
3. Select **Compliance** from the dropdown menu
|
||||
|
||||
Or navigate directly to: `/admin/compliance`
|
||||
|
||||
## Available Templates
|
||||
|
||||
### GDPR (General Data Protection Regulation)
|
||||
|
||||
The European Union regulation for data protection and privacy. The GDPR template enforces:
|
||||
|
||||
| Setting | Value | Purpose |
|
||||
|---------|-------|---------|
|
||||
| `AUTH_ENABLED` | `True` | Controls access to personal data |
|
||||
| `SENTRY_SEND_DEFAULT_PII` | `False` | Prevents PII leaking to external services |
|
||||
| `SECURITY_HEADERS_ENABLED` | `True` | Protects against common web vulnerabilities |
|
||||
| `SECURITY_HEADER_HSTS_ENABLED` | `True` | Ensures encrypted connections |
|
||||
| `SECURITY_HEADER_CSP_ENABLED` | `True` | Prevents XSS and injection attacks |
|
||||
| `SECURITY_HEADER_X_FRAME_OPTIONS_ENABLED` | `True` | Prevents clickjacking |
|
||||
| `ENABLE_DEDUPLICATION` | `True` | Data minimisation — avoids duplicate storage |
|
||||
|
||||
### HIPAA (Health Insurance Portability and Accountability Act)
|
||||
|
||||
United States regulation for protecting health information. The HIPAA template includes all GDPR settings plus:
|
||||
|
||||
| Setting | Value | Purpose |
|
||||
|---------|-------|---------|
|
||||
| `MULTI_USER_ENABLED` | `True` | Individual accounts for access accountability |
|
||||
|
||||
### SOC 2 (Service Organization Control 2)
|
||||
|
||||
Trust Service Criteria framework for service organisations. The SOC 2 template includes the same settings as HIPAA, mapped to SOC 2 Trust Service Criteria (CC6.x, PI1.x).
|
||||
|
||||
## Applying a Template
|
||||
|
||||
1. Navigate to the **Compliance** dashboard (`/admin/compliance`)
|
||||
2. Find the template you want to apply (GDPR, HIPAA, or SOC 2)
|
||||
3. Click **Apply Template**
|
||||
4. Confirm the action in the dialog
|
||||
5. The template settings are written to the database immediately
|
||||
|
||||
> **Note:** Applying a template writes configuration values to the database. Some settings (e.g., security headers) may require a restart to take effect. Check the Settings page for restart indicators.
|
||||
|
||||
## Understanding Compliance Status
|
||||
|
||||
Each template shows one of four statuses:
|
||||
|
||||
| Status | Badge | Meaning |
|
||||
|--------|-------|---------|
|
||||
| **Compliant** | Green | All checks are passing |
|
||||
| **Partial** | Yellow | Some checks are passing, others are not |
|
||||
| **Non-Compliant** | Red | No checks are passing |
|
||||
| **Not Applied** | Grey | Template has never been applied |
|
||||
|
||||
### Individual Checks
|
||||
|
||||
Click **Show Details** on any template card to see individual check results:
|
||||
|
||||
- ✅ **Passing** — The setting matches the expected compliance value
|
||||
- ❌ **Failing** — The setting does not match; the current and expected values are shown
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The compliance feature exposes the following API endpoints under `/api/compliance/`:
|
||||
|
||||
### List Templates
|
||||
|
||||
```bash
|
||||
GET /api/compliance/templates
|
||||
```
|
||||
|
||||
Returns all compliance templates with their current status.
|
||||
|
||||
### Get Single Template
|
||||
|
||||
```bash
|
||||
GET /api/compliance/templates/{name}
|
||||
```
|
||||
|
||||
Returns a single template by name (`gdpr`, `hipaa`, or `soc2`).
|
||||
|
||||
### Apply Template
|
||||
|
||||
```bash
|
||||
POST /api/compliance/templates/{name}/apply
|
||||
```
|
||||
|
||||
Applies a compliance template, writing all its settings to the database.
|
||||
|
||||
### Get Template Status
|
||||
|
||||
```bash
|
||||
GET /api/compliance/templates/{name}/status
|
||||
```
|
||||
|
||||
Evaluates the live compliance status of a template against current settings.
|
||||
|
||||
**Response example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "partial",
|
||||
"total": 7,
|
||||
"passed": 5,
|
||||
"failed": 2,
|
||||
"check_results": [
|
||||
{
|
||||
"key": "auth_enabled",
|
||||
"label": "Authentication enabled",
|
||||
"description": "User authentication must be enabled to control access to personal data.",
|
||||
"expected": "True",
|
||||
"actual": "True",
|
||||
"passing": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Compliance Summary
|
||||
|
||||
```bash
|
||||
GET /api/compliance/summary
|
||||
```
|
||||
|
||||
Returns an overall compliance summary across all templates.
|
||||
|
||||
**Response example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"overall_status": "partial",
|
||||
"total_checks": 22,
|
||||
"total_passed": 18,
|
||||
"total_failed": 4,
|
||||
"templates": [
|
||||
{
|
||||
"name": "gdpr",
|
||||
"display_name": "GDPR (General Data Protection Regulation)",
|
||||
"enabled": true,
|
||||
"status": "compliant",
|
||||
"total": 7,
|
||||
"passed": 7,
|
||||
"failed": 0,
|
||||
"applied_at": "2026-03-09T12:00:00+00:00",
|
||||
"applied_by": "admin@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** All API endpoints require admin authentication.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `COMPLIANCE_ENABLED` | `True` | Enable the compliance templates dashboard. Set to `False` to hide the feature. |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Apply templates before going live** — Set up compliance before processing real documents
|
||||
2. **Monitor status regularly** — Check the compliance dashboard after configuration changes
|
||||
3. **Use the refresh button** — After changing settings elsewhere, refresh the compliance page to see updated status
|
||||
4. **Combine templates** — You can apply multiple templates; settings overlap is handled automatically
|
||||
5. **Review after updates** — After upgrading DocuElevate, review your compliance status as new checks may be added
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Configuration Guide](./ConfigurationGuide.md) — Full list of configuration options
|
||||
- [Privacy & Compliance Guide](./PrivacyCompliance.md) — Privacy notice and GDPR compliance details
|
||||
- [Deployment Guide](./DeploymentGuide.md) — Production deployment with security best practices
|
||||
- [Security Audit](../SECURITY_AUDIT.md) — Security findings and mitigations
|
||||
@@ -16,6 +16,7 @@ Configuration is primarily done through environment variables specified in a `.e
|
||||
| `GOTENBERG_URL` | Gotenberg PDF processing URL. | `http://gotenberg:3000` |
|
||||
| `EXTERNAL_HOSTNAME` | The external hostname for the application. | `docuelevate.example.com` |
|
||||
| `ALLOW_FILE_DELETE` | Enable file deletion in the web interface (`true`/`false`). | `true` |
|
||||
| `COMPLIANCE_ENABLED` | Enable the compliance templates dashboard (GDPR, HIPAA, SOC 2). | `true` |
|
||||
|
||||
### Batch Processing Settings
|
||||
|
||||
@@ -303,6 +304,42 @@ DocuElevate can automatically pull document attachments from IMAP mailboxes —
|
||||
| `IMAP1_SSL` | Use SSL (`true`/`false`). | `true` |
|
||||
| `IMAP1_POLL_INTERVAL_MINUTES` | Frequency in minutes to poll for new mail. | `5` |
|
||||
| `IMAP_READONLY_MODE` | When `true`, fetches and processes attachments but does **not** modify the mailbox (no starring, labeling, deleting, or flag changes). Use for pre-production instances sharing a mailbox with production. Default: `false`. | `false` |
|
||||
| `IMAP_ATTACHMENT_FILTER` | System-wide fallback for which attachment types are ingested when no ingestion profile is assigned to a mailbox. `documents_only` (default) ingests PDFs and office files only — images are skipped. `all` ingests every supported file type including images. Individual IMAP accounts can override this using ingestion profiles. | `documents_only` |
|
||||
|
||||
#### IMAP Ingestion Profiles
|
||||
|
||||
For fine-grained control, DocuElevate supports **Ingestion Profiles** — named configurations that let you choose exactly which file-type categories to accept from each mailbox.
|
||||
|
||||
Each profile contains a list of enabled **categories**:
|
||||
|
||||
| Category | Description |
|
||||
|----------|-------------|
|
||||
| `pdf` | PDF documents (`.pdf`) |
|
||||
| `office` | Microsoft Office files (Word, Excel, PowerPoint — `.docx`, `.xlsx`, `.pptx`, …) |
|
||||
| `opendocument` | LibreOffice/OpenOffice files (`.odt`, `.ods`, `.odp`, …) |
|
||||
| `text` | Plain text, CSV and RTF files (`.txt`, `.csv`, `.rtf`) |
|
||||
| `web` | HTML and Markdown files (`.html`, `.htm`, `.md`, `.markdown`) |
|
||||
| `images` | Image files (`.jpg`, `.png`, `.gif`, `.bmp`, `.tiff`, `.webp`, `.svg`) |
|
||||
|
||||
Two built-in system profiles are seeded automatically:
|
||||
|
||||
| Profile | Categories |
|
||||
|---------|------------|
|
||||
| **Documents Only** | pdf, office, opendocument, text, web (no images) |
|
||||
| **All Files** | All categories, including images |
|
||||
|
||||
Users can create their own custom profiles via the **Email Ingestion** dashboard (`/imap-accounts`) by clicking the **Manage profiles** link or the **+** button next to the profile dropdown. Custom profiles are private to the creating user and can be freely edited or deleted.
|
||||
|
||||
**API endpoints for ingestion profiles:**
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/imap-profiles/` | List all visible profiles (system + user's own) |
|
||||
| `POST` | `/api/imap-profiles/` | Create a new profile |
|
||||
| `GET` | `/api/imap-profiles/categories` | List available file-type categories |
|
||||
| `GET` | `/api/imap-profiles/{id}` | Get a single profile |
|
||||
| `PUT` | `/api/imap-profiles/{id}` | Update a profile (not built-in) |
|
||||
| `DELETE` | `/api/imap-profiles/{id}` | Delete a profile (not built-in) |
|
||||
|
||||
#### Per-User IMAP Integrations
|
||||
|
||||
@@ -335,6 +372,28 @@ Credentials are encrypted at rest using Fernet encryption.
|
||||
| `AUTHENTIK_CONFIG_URL` | Configuration URL for Authentik OpenID Connect. |
|
||||
| `OAUTH_PROVIDER_NAME` | Display name for the OAuth provider button. |
|
||||
|
||||
### Social Login Providers
|
||||
|
||||
Social login lets users sign in with their existing Google, Microsoft, Apple, or Dropbox accounts. Each provider is independently enabled and configured. For detailed setup instructions see the [Social Login Setup Guide](SocialLoginSetup.md).
|
||||
|
||||
| **Variable** | **Description** | **Default** |
|
||||
|---|---|---|
|
||||
| `SOCIAL_AUTH_GOOGLE_ENABLED` | Enable Google Sign-In. | `false` |
|
||||
| `SOCIAL_AUTH_GOOGLE_CLIENT_ID` | Google OAuth2 client ID from the Google Cloud Console. | *(empty)* |
|
||||
| `SOCIAL_AUTH_GOOGLE_CLIENT_SECRET` | Google OAuth2 client secret. | *(empty)* |
|
||||
| `SOCIAL_AUTH_MICROSOFT_ENABLED` | Enable Microsoft Sign-In (Azure AD / Microsoft Entra ID). | `false` |
|
||||
| `SOCIAL_AUTH_MICROSOFT_CLIENT_ID` | Microsoft application (client) ID from Azure App Registrations. | *(empty)* |
|
||||
| `SOCIAL_AUTH_MICROSOFT_CLIENT_SECRET` | Microsoft client secret. | *(empty)* |
|
||||
| `SOCIAL_AUTH_MICROSOFT_TENANT` | Azure AD tenant: `common`, `organizations`, `consumers`, or a tenant GUID. | `common` |
|
||||
| `SOCIAL_AUTH_APPLE_ENABLED` | Enable Sign in with Apple. | `false` |
|
||||
| `SOCIAL_AUTH_APPLE_CLIENT_ID` | Apple Services ID (e.g. `com.example.docuelevate`). | *(empty)* |
|
||||
| `SOCIAL_AUTH_APPLE_TEAM_ID` | Apple Developer Team ID. | *(empty)* |
|
||||
| `SOCIAL_AUTH_APPLE_KEY_ID` | Apple Sign-In private key ID. | *(empty)* |
|
||||
| `SOCIAL_AUTH_APPLE_PRIVATE_KEY` | Apple Sign-In private key (PEM format). | *(empty)* |
|
||||
| `SOCIAL_AUTH_DROPBOX_ENABLED` | Enable Dropbox Sign-In. | `false` |
|
||||
| `SOCIAL_AUTH_DROPBOX_CLIENT_ID` | Dropbox OAuth2 App Key. | *(empty)* |
|
||||
| `SOCIAL_AUTH_DROPBOX_CLIENT_SECRET` | Dropbox OAuth2 App Secret. | *(empty)* |
|
||||
|
||||
### Multi-User Mode
|
||||
|
||||
When multi-user mode is enabled, each authenticated user gets their own isolated document space.
|
||||
@@ -398,6 +457,61 @@ default overage buffer applied across all plans.
|
||||
|
||||
DocuElevate supports HTTP security headers to improve browser-side security. **These headers are disabled by default** since most deployments use a reverse proxy (Traefik, Nginx, etc.) that already adds them. Enable only if deploying directly without a reverse proxy. See [Deployment Guide - Security Headers](DeploymentGuide.md#security-headers) for detailed configuration examples.
|
||||
|
||||
### Audit Logging
|
||||
|
||||
DocuElevate provides comprehensive audit logging that records significant actions (logins, document CRUD, settings changes) to an append-only database table. Every entry captures the timestamp, user, action, resource, client IP, and optional JSON details.
|
||||
|
||||
| **Variable** | **Description** | **Default** |
|
||||
|--------------------------------|---------------------------------------------------------------------------------------------------|-------------|
|
||||
| `AUDIT_LOGGING_ENABLED` | Enable the HTTP request audit-logging middleware. | `true` |
|
||||
| `AUDIT_LOG_INCLUDE_CLIENT_IP` | Include the client IP address in audit log entries. Disable for GDPR-sensitive deployments. | `true` |
|
||||
|
||||
#### SIEM Integration
|
||||
|
||||
Audit events can be forwarded in real time to external SIEM systems for centralised monitoring, alerting, and long-term retention. Two transports are supported:
|
||||
|
||||
* **Syslog** – RFC 5424 structured-data messages over UDP or TCP. Works with rsyslog, syslog-ng, Graylog, Datadog, etc.
|
||||
* **HTTP** – JSON POST payloads compatible with Splunk HEC, Logstash HTTP input, Grafana Loki push API, and any generic webhook.
|
||||
|
||||
| **Variable** | **Description** | **Default** |
|
||||
|-------------------------------------|---------------------------------------------------------------------------------------------------|---------------|
|
||||
| `AUDIT_SIEM_ENABLED` | Enable forwarding of audit events to an external SIEM system. | `false` |
|
||||
| `AUDIT_SIEM_TRANSPORT` | Transport: `syslog` or `http`. | `syslog` |
|
||||
| `AUDIT_SIEM_SYSLOG_HOST` | Hostname or IP of the syslog receiver. | `localhost` |
|
||||
| `AUDIT_SIEM_SYSLOG_PORT` | Port of the syslog receiver. | `514` |
|
||||
| `AUDIT_SIEM_SYSLOG_PROTOCOL` | Protocol for syslog: `udp` or `tcp`. | `udp` |
|
||||
| `AUDIT_SIEM_HTTP_URL` | HTTP endpoint URL for SIEM delivery (e.g. Splunk HEC, Logstash, Loki). | *(empty)* |
|
||||
| `AUDIT_SIEM_HTTP_TOKEN` | Bearer / HEC token for the SIEM HTTP endpoint. | *(empty)* |
|
||||
| `AUDIT_SIEM_HTTP_CUSTOM_HEADERS` | Comma-separated `Key:Value` extra headers for SIEM HTTP requests. | *(empty)* |
|
||||
|
||||
**Example – Syslog to rsyslog:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=syslog
|
||||
AUDIT_SIEM_SYSLOG_HOST=syslog.internal.example.com
|
||||
AUDIT_SIEM_SYSLOG_PORT=514
|
||||
AUDIT_SIEM_SYSLOG_PROTOCOL=udp
|
||||
```
|
||||
|
||||
**Example – Splunk HEC:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=http
|
||||
AUDIT_SIEM_HTTP_URL=https://splunk.example.com:8088/services/collector/event
|
||||
AUDIT_SIEM_HTTP_TOKEN=your-hec-token
|
||||
```
|
||||
|
||||
**Example – Logstash HTTP input:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=http
|
||||
AUDIT_SIEM_HTTP_URL=https://logstash.example.com:8080
|
||||
AUDIT_SIEM_HTTP_TOKEN=
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
DocuElevate implements rate limiting to protect against DoS attacks and API abuse. **Rate limiting is enabled by default** and uses Redis for distributed rate limiting across multiple workers.
|
||||
@@ -887,6 +1001,7 @@ TESSERACT_LANGUAGE=eng+deu
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|-------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| `PAPERLESS_ENABLED` | Set to `false` to disable Paperless-ngx uploads without removing credentials. Default: `true` |
|
||||
| `PAPERLESS_NGX_API_TOKEN` | API token for Paperless NGX. |
|
||||
| `PAPERLESS_HOST` | Root URL for Paperless NGX (e.g. `https://paperless.example.com`). |
|
||||
| `PAPERLESS_CUSTOM_FIELD_ABSENDER` | (Optional, Legacy) Name of the custom field in Paperless-ngx to store the sender ("absender") information. If set, the extracted sender will be automatically set as a custom field after document upload. Example: `Absender` or `Sender` |
|
||||
@@ -929,6 +1044,7 @@ PAPERLESS_CUSTOM_FIELDS_MAPPING='{"absender": "Sender", "empfaenger": "Recipient
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|-------------------------|--------------------------------------------------|
|
||||
| `DROPBOX_ENABLED` | Set to `false` to disable Dropbox uploads without removing credentials. Default: `true` |
|
||||
| `DROPBOX_APP_KEY` | Dropbox API app key. |
|
||||
| `DROPBOX_APP_SECRET` | Dropbox API app secret. |
|
||||
| `DROPBOX_REFRESH_TOKEN` | OAuth2 refresh token for Dropbox. |
|
||||
@@ -940,6 +1056,7 @@ For detailed setup instructions, see the [Dropbox Setup Guide](DropboxSetup.md).
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|-------------------------|---------------------------------------------------------------|
|
||||
| `NEXTCLOUD_ENABLED` | Set to `false` to disable Nextcloud uploads without removing credentials. Default: `true` |
|
||||
| `NEXTCLOUD_UPLOAD_URL` | Nextcloud WebDAV URL (e.g. `https://nc.example.com/remote.php/dav/files/<USERNAME>`). |
|
||||
| `NEXTCLOUD_USERNAME` | Nextcloud login username. |
|
||||
| `NEXTCLOUD_PASSWORD` | Nextcloud login password. |
|
||||
@@ -949,6 +1066,7 @@ For detailed setup instructions, see the [Dropbox Setup Guide](DropboxSetup.md).
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|---------------------------------|-------------------------------------------------------|
|
||||
| `GOOGLE_DRIVE_ENABLED` | Set to `false` to disable Google Drive uploads without removing credentials. Default: `true` |
|
||||
| `GOOGLE_DRIVE_USE_OAUTH` | Set to `true` to use OAuth flow (recommended) |
|
||||
| `GOOGLE_DRIVE_CLIENT_ID` | OAuth Client ID (required if using OAuth flow) |
|
||||
| `GOOGLE_DRIVE_CLIENT_SECRET` | OAuth Client Secret (required if using OAuth flow) |
|
||||
@@ -965,6 +1083,7 @@ For detailed setup instructions, see the [Google Drive Setup Guide](GoogleDriveS
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|-------------------------|---------------------------------------------------------------|
|
||||
| `WEBDAV_ENABLED` | Set to `false` to disable WebDAV uploads without removing credentials. Default: `true` |
|
||||
| `WEBDAV_URL` | WebDAV server URL (e.g. `https://webdav.example.com/path`). |
|
||||
| `WEBDAV_USERNAME` | WebDAV authentication username. |
|
||||
| `WEBDAV_PASSWORD` | WebDAV authentication password. |
|
||||
@@ -975,6 +1094,7 @@ For detailed setup instructions, see the [Google Drive Setup Guide](GoogleDriveS
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|-------------------------|---------------------------------------------------------------|
|
||||
| `FTP_ENABLED` | Set to `false` to disable FTP uploads without removing credentials. Default: `true` |
|
||||
| `FTP_HOST` | FTP server hostname or IP address. |
|
||||
| `FTP_PORT` | FTP port (default: `21`). |
|
||||
| `FTP_USERNAME` | FTP authentication username. |
|
||||
@@ -987,6 +1107,7 @@ For detailed setup instructions, see the [Google Drive Setup Guide](GoogleDriveS
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|------------------------------|-------------------------------------------------------|
|
||||
| `SFTP_ENABLED` | Set to `false` to disable SFTP uploads without removing credentials. Default: `true` |
|
||||
| `SFTP_HOST` | SFTP server hostname or IP address. |
|
||||
| `SFTP_PORT` | SFTP port (default: `22`). |
|
||||
| `SFTP_USERNAME` | SFTP authentication username. |
|
||||
@@ -1018,6 +1139,7 @@ For detailed setup instructions, see the [Google Drive Setup Guide](GoogleDriveS
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|----------------------------------|---------------------------------------------------------------------|
|
||||
| `DEST_EMAIL_ENABLED` | Set to `false` to disable email delivery without removing credentials. Default: `true` |
|
||||
| `DEST_EMAIL_HOST` | SMTP server hostname for document delivery. |
|
||||
| `DEST_EMAIL_PORT` | SMTP port for document delivery (default: `587`). |
|
||||
| `DEST_EMAIL_USERNAME` | SMTP authentication username for document delivery. |
|
||||
@@ -1030,6 +1152,7 @@ For detailed setup instructions, see the [Google Drive Setup Guide](GoogleDriveS
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|---------------------------------|-------------------------------------------------------|
|
||||
| `ONEDRIVE_ENABLED` | Set to `false` to disable OneDrive uploads without removing credentials. Default: `true` |
|
||||
| `ONEDRIVE_CLIENT_ID` | Azure AD application client ID |
|
||||
| `ONEDRIVE_CLIENT_SECRET` | Azure AD application client secret |
|
||||
| `ONEDRIVE_TENANT_ID` | Azure AD tenant ID: use "common" for personal accounts or your tenant ID for corporate accounts |
|
||||
@@ -1042,6 +1165,7 @@ For detailed setup instructions, see the [OneDrive Setup Guide](OneDriveSetup.md
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|---------------------------------|-------------------------------------------------------|
|
||||
| `S3_ENABLED` | Set to `false` to disable S3 uploads without removing credentials. Default: `true` |
|
||||
| `AWS_ACCESS_KEY_ID` | AWS IAM access key ID |
|
||||
| `AWS_SECRET_ACCESS_KEY` | AWS IAM secret access key |
|
||||
| `AWS_REGION` | AWS region where your S3 bucket is located (default: `us-east-1`) |
|
||||
@@ -1052,6 +1176,23 @@ For detailed setup instructions, see the [OneDrive Setup Guide](OneDriveSetup.md
|
||||
|
||||
For detailed setup instructions, see the [Amazon S3 Setup Guide](AmazonS3Setup.md).
|
||||
|
||||
### iCloud Drive (Apple)
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|---------------------------------|-------------------------------------------------------|
|
||||
| `ICLOUD_ENABLED` | Set to `false` to disable iCloud uploads without removing credentials. Default: `true` |
|
||||
| `ICLOUD_USERNAME` | Apple ID email address |
|
||||
| `ICLOUD_PASSWORD` | App-specific password (generate at [appleid.apple.com](https://appleid.apple.com/account/manage)) |
|
||||
| `ICLOUD_FOLDER` | Target folder path in iCloud Drive (e.g. `Documents/Uploads`) |
|
||||
| `ICLOUD_COOKIE_DIRECTORY` | Optional directory for session cookie persistence (default: `~/.pyicloud`) |
|
||||
|
||||
> **Note:** Apple does not provide a public REST API for iCloud Drive. This
|
||||
> integration uses the [pyicloud](https://github.com/picklepete/pyicloud)
|
||||
> library which relies on an unofficial, reverse-engineered protocol. Because
|
||||
> most Apple IDs have two-factor authentication enabled, you **must** generate
|
||||
> an [app-specific password](https://support.apple.com/en-us/102654) and use
|
||||
> it as `ICLOUD_PASSWORD`.
|
||||
|
||||
### Notification System
|
||||
|
||||
| **Variable** | **Description** |
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
# Internationalization (i18n) & Localization (l10n) Guide
|
||||
|
||||
DocuElevate supports **10 languages** for its web UI, with automatic browser
|
||||
language detection, user-preference persistence, and an AI-powered fallback
|
||||
translator for strings that haven't been manually translated yet.
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Code | Language | Native Name | Priority |
|
||||
|------|------------|-------------|----------|
|
||||
| `en` | English | English | Tier 1 |
|
||||
| `de` | German | Deutsch | Tier 1 |
|
||||
| `fr` | French | Français | Tier 1 |
|
||||
| `es` | Spanish | Español | Tier 1 |
|
||||
| `it` | Italian | Italiano | Tier 1 |
|
||||
| `pt` | Portuguese | Português | Tier 1 |
|
||||
| `nl` | Dutch | Nederlands | Tier 2 |
|
||||
| `pl` | Polish | Polski | Tier 2 |
|
||||
| `zh` | Chinese | 中文 | Tier 2 |
|
||||
| `ru` | Russian | Русский | Tier 2 |
|
||||
|
||||
> **Tier 1** languages (European priority) have complete, manually-reviewed
|
||||
> translations. **Tier 2** languages have complete translations but may
|
||||
> receive less frequent updates.
|
||||
|
||||
## How Language Is Detected
|
||||
|
||||
DocuElevate resolves the display language in the following priority order:
|
||||
|
||||
1. **User profile preference** — stored in the database (`UserProfile.preferred_language`)
|
||||
and loaded into the session on login
|
||||
2. **Cookie** — `docuelevate_lang` cookie (30-day expiry, set when user selects a language)
|
||||
3. **Browser `Accept-Language` header** — the highest-priority match among supported languages
|
||||
4. **Default** — English (`en`)
|
||||
|
||||
## Selecting Your Language
|
||||
|
||||
### Via the Navigation Bar
|
||||
|
||||
Click the 🌐 **globe icon** in the top navigation bar. A dropdown menu shows all
|
||||
available languages with their native names and flag emoji. The current language
|
||||
is highlighted with a blue checkmark.
|
||||
|
||||
### Via the API
|
||||
|
||||
```bash
|
||||
# Set language to German
|
||||
curl -X POST http://localhost:8000/api/i18n/language \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"language": "de"}'
|
||||
|
||||
# List all available languages
|
||||
curl http://localhost:8000/api/i18n/languages
|
||||
```
|
||||
|
||||
### Via Cookie (Programmatic)
|
||||
|
||||
Set the `docuelevate_lang` cookie to any supported language code:
|
||||
|
||||
```javascript
|
||||
document.cookie = "docuelevate_lang=fr; max-age=2592000; path=/";
|
||||
location.reload();
|
||||
```
|
||||
|
||||
## For Developers
|
||||
|
||||
### Translation File Structure
|
||||
|
||||
Translations are stored as flat JSON files in `frontend/translations/`:
|
||||
|
||||
```
|
||||
frontend/translations/
|
||||
├── en.json # English (base / reference)
|
||||
├── de.json # German
|
||||
├── fr.json # French
|
||||
├── es.json # Spanish
|
||||
├── it.json # Italian
|
||||
├── pt.json # Portuguese
|
||||
├── nl.json # Dutch
|
||||
├── pl.json # Polish
|
||||
├── zh.json # Chinese
|
||||
└── ru.json # Russian
|
||||
```
|
||||
|
||||
Each file is a flat key-value dictionary with dot-notation namespacing:
|
||||
|
||||
```json
|
||||
{
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.upload": "Upload",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"footer.copyright": "DocuElevate {year}"
|
||||
}
|
||||
```
|
||||
|
||||
### Using Translations in Templates
|
||||
|
||||
The `_()` function is available globally in all Jinja2 templates:
|
||||
|
||||
```jinja2
|
||||
{# Simple translation #}
|
||||
<h1>{{ _("dashboard.title") }}</h1>
|
||||
|
||||
{# Translation with placeholders #}
|
||||
<p>{{ _("upload.max_size", size="50 MB") }}</p>
|
||||
|
||||
{# Translation in attributes #}
|
||||
<button aria-label="{{ _('common.save') }}">{{ _("common.save") }}</button>
|
||||
```
|
||||
|
||||
### Using Translations in Python
|
||||
|
||||
```python
|
||||
from app.utils.i18n import translate
|
||||
|
||||
# Basic translation
|
||||
text = translate("nav.dashboard", "de") # → "Übersicht"
|
||||
|
||||
# With placeholders
|
||||
text = translate("footer.copyright", "fr", year="2025") # → "DocuElevate 2025"
|
||||
```
|
||||
|
||||
### Localization Helpers
|
||||
|
||||
Format dates, times, and numbers according to locale conventions:
|
||||
|
||||
```jinja2
|
||||
{# In templates — locale is automatically detected #}
|
||||
<span>{{ format_date_l10n(document.created_at) }}</span>
|
||||
<span>{{ format_number_l10n(file_count) }}</span>
|
||||
```
|
||||
|
||||
```python
|
||||
# In Python
|
||||
from app.utils.i18n import format_date, format_number
|
||||
|
||||
format_date(date(2025, 3, 15), "de") # → "15. March 2025"
|
||||
format_date(date(2025, 3, 15), "de", short=True) # → "15.03.2025"
|
||||
format_number(1234567, "de") # → "1.234.567"
|
||||
format_number(1234.56, "en") # → "1,234.56"
|
||||
```
|
||||
|
||||
### Adding a New Translation Key
|
||||
|
||||
1. Add the key and English text to `frontend/translations/en.json`
|
||||
2. Add translations for all other languages in their respective files
|
||||
3. Use `{{ _("your.new.key") }}` in templates
|
||||
|
||||
### AI Fallback Translation
|
||||
|
||||
When a translation key exists in English but not in the target language,
|
||||
DocuElevate can use the configured AI provider (OpenAI, Anthropic, etc.)
|
||||
to translate the string on-the-fly:
|
||||
|
||||
```python
|
||||
from app.utils.i18n import translate_with_ai_fallback
|
||||
|
||||
# Falls back to AI if no manual translation exists
|
||||
translated = translate_with_ai_fallback("Welcome to our platform", "de")
|
||||
```
|
||||
|
||||
The AI fallback:
|
||||
- Uses the `AI_MODEL` or `OPENAI_MODEL` setting
|
||||
- Caches results in memory for the process lifetime
|
||||
- Returns the original English text if the AI call fails
|
||||
- Is designed for graceful degradation — the UI never breaks
|
||||
|
||||
### Adding a New Language
|
||||
|
||||
1. Create a new JSON file in `frontend/translations/` (e.g., `ja.json`)
|
||||
2. Copy the structure from `en.json` and translate all values
|
||||
3. Add the language to `SUPPORTED_LANGUAGES` in `app/utils/i18n.py`:
|
||||
```python
|
||||
{"code": "ja", "name": "Japanese", "native": "日本語", "flag": "🇯🇵"},
|
||||
```
|
||||
4. Add locale formatting rules to `_LOCALE_FORMATS` in the same file
|
||||
5. Create a database migration if needed (the `preferred_language` column
|
||||
already accepts any string up to 10 characters)
|
||||
|
||||
### Database Migration
|
||||
|
||||
Migration `027_add_user_language_preference` adds a `preferred_language`
|
||||
column to the `user_profiles` table. This column stores the user's chosen
|
||||
UI language as an ISO 639-1 code (e.g., `"de"`, `"fr"`). A `NULL` value
|
||||
means "auto-detect from browser settings."
|
||||
|
||||
### API Reference
|
||||
|
||||
#### `GET /api/i18n/languages`
|
||||
|
||||
Returns all supported languages and the current active language.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"languages": [
|
||||
{"code": "en", "name": "English", "native": "English", "flag": "🇬🇧"},
|
||||
{"code": "de", "name": "German", "native": "Deutsch", "flag": "🇩🇪"}
|
||||
],
|
||||
"current": "en",
|
||||
"default": "en"
|
||||
}
|
||||
```
|
||||
|
||||
#### `POST /api/i18n/language`
|
||||
|
||||
Set the preferred UI language. Persists in session, cookie, and database.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{"language": "de"}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"language": "de",
|
||||
"message": "Language changed to Deutsch"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
No additional configuration is required. The i18n system works out of the box
|
||||
with the default English language and automatically detects browser preferences.
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| Browser `Accept-Language` | Auto-detected | Used when no explicit preference is set |
|
||||
| `docuelevate_lang` cookie | Not set | Set when user selects a language via the UI |
|
||||
| `UserProfile.preferred_language` | `NULL` | Stored in DB for authenticated users |
|
||||
@@ -0,0 +1,252 @@
|
||||
# Mobile App
|
||||
|
||||
DocuElevate includes a native mobile application for iOS and Android built with **React Native** and **Expo**. The app allows users to capture documents with the device camera, pick files from the device storage, and receive push notifications when documents finish processing.
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | iOS | Android |
|
||||
|---------|-----|---------|
|
||||
| SSO login (OAuth2) | ✅ | ✅ |
|
||||
| Local / basic auth login | ✅ | ✅ |
|
||||
| Auto-generated API token | ✅ | ✅ |
|
||||
| Camera capture → upload | ✅ | ✅ |
|
||||
| File picker upload | ✅ | ✅ |
|
||||
| Share Sheet / Share Intent | ✅ | ✅ |
|
||||
| Push notifications | ✅ | ✅ |
|
||||
| Document list | ✅ | ✅ |
|
||||
| Dark mode | ✅ | ✅ |
|
||||
|
||||
## Getting Started (Development)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18 or later
|
||||
- [Expo CLI](https://docs.expo.dev/get-started/installation/): `npm install -g @expo/cli`
|
||||
- [Expo Go](https://expo.dev/client) app on your iOS or Android device (for development)
|
||||
- A running DocuElevate server reachable from your device
|
||||
|
||||
### Run in development mode
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
npm install
|
||||
npx expo start
|
||||
```
|
||||
|
||||
Scan the QR code with **Expo Go** on your device. On iOS you can also use the Camera app.
|
||||
|
||||
## Building for Production
|
||||
|
||||
DocuElevate uses **Expo Application Services (EAS)** to produce App Store / Play Store binaries.
|
||||
|
||||
```bash
|
||||
# Install EAS CLI globally
|
||||
npm install -g eas-cli
|
||||
|
||||
# Authenticate with Expo
|
||||
eas login
|
||||
|
||||
# Build for iOS (requires Apple Developer account)
|
||||
eas build --platform ios
|
||||
|
||||
# Build for Android
|
||||
eas build --platform android
|
||||
```
|
||||
|
||||
See the [EAS Build documentation](https://docs.expo.dev/build/introduction/) for full setup instructions.
|
||||
|
||||
## Authentication
|
||||
|
||||
### SSO Login Flow
|
||||
|
||||
The mobile app uses the server's existing OAuth2/SSO setup:
|
||||
|
||||
1. User enters the DocuElevate server URL on the login screen.
|
||||
2. The app opens `<server>/login?mobile=1&redirect_uri=docuelevate://callback` in the **system browser** (Safari / Chrome).
|
||||
3. The user authenticates via SSO or local credentials.
|
||||
4. The server redirects back to `docuelevate://callback`.
|
||||
5. The app calls `POST /api/mobile/generate-token` to exchange the session for a **long-lived API token**.
|
||||
6. The token is stored securely in the device's keychain (`expo-secure-store`).
|
||||
|
||||
### Auto-generated Mobile Token
|
||||
|
||||
When the mobile app completes login it automatically creates a named API token (`"Mobile App – <device name>"`) via `POST /api/mobile/generate-token`. This token:
|
||||
|
||||
- Works identically to tokens created manually in the web UI.
|
||||
- Is shown in the **API Tokens** page (`/api-tokens`) and can be revoked there.
|
||||
- Is stored in the device's secure keychain, never in plain storage.
|
||||
|
||||
## Push Notifications
|
||||
|
||||
Push notifications are delivered via the **Expo Push Notification** service, which routes through Apple Push Notification service (APNs) for iOS and Firebase Cloud Messaging (FCM) for Android.
|
||||
|
||||
**No server-side APNs/FCM credentials are required** – Expo's servers handle the provider integration.
|
||||
|
||||
### How it works
|
||||
|
||||
1. After login, the app requests notification permission from the operating system.
|
||||
2. If granted, the app obtains an **Expo Push Token** (`ExponentPushToken[…]`).
|
||||
3. The token is registered with the backend via `POST /api/mobile/register-device`.
|
||||
4. When a document finishes processing, the server sends a push notification to all registered devices for that user.
|
||||
|
||||
### Managing registered devices
|
||||
|
||||
Users can see and remove their registered devices from the **Profile** tab in the app, or via the API:
|
||||
|
||||
```bash
|
||||
# List registered devices
|
||||
curl -H "Authorization: Bearer <token>" https://your-server/api/mobile/devices
|
||||
|
||||
# Remove a device
|
||||
curl -X DELETE -H "Authorization: Bearer <token>" https://your-server/api/mobile/devices/<id>
|
||||
```
|
||||
|
||||
## Uploading Documents
|
||||
|
||||
### Camera Capture
|
||||
|
||||
1. Open the **Upload** tab.
|
||||
2. Tap **Camera**.
|
||||
3. Point the camera at the document and take a photo.
|
||||
4. The image is immediately uploaded and queued for processing.
|
||||
|
||||
### File Picker
|
||||
|
||||
1. Open the **Upload** tab.
|
||||
2. Tap **File Picker**.
|
||||
3. Browse to and select one or more files (PDF, DOCX, images, etc.).
|
||||
4. Files are uploaded and queued for processing.
|
||||
|
||||
### Share Sheet (iOS) / Share Intent (Android)
|
||||
|
||||
The app registers itself as a share target so any file can be sent directly to DocuElevate from another app:
|
||||
|
||||
1. Open a file in Files, Mail, Safari, or any other app.
|
||||
2. Tap the **Share** button (iOS) or **Share** (Android).
|
||||
3. Find and tap **DocuElevate** in the share sheet.
|
||||
4. The file is immediately uploaded.
|
||||
|
||||
> **Note:** The app must be installed on the device for it to appear in the share sheet.
|
||||
|
||||
## Mobile API Endpoints
|
||||
|
||||
The backend exposes a dedicated `/api/mobile/` namespace:
|
||||
|
||||
| Method | Endpoint | Auth | Description |
|
||||
|--------|----------|------|-------------|
|
||||
| `POST` | `/api/mobile/generate-token` | Session | Exchange SSO session for API token |
|
||||
| `POST` | `/api/mobile/register-device` | Bearer | Register Expo push token |
|
||||
| `GET` | `/api/mobile/devices` | Bearer | List registered devices |
|
||||
| `DELETE` | `/api/mobile/devices/{id}` | Bearer | Deactivate a device |
|
||||
| `GET` | `/api/mobile/whoami` | Bearer | Get current user profile |
|
||||
|
||||
All other API endpoints (file upload, file listing, etc.) work with Bearer token authentication.
|
||||
|
||||
### POST /api/mobile/generate-token
|
||||
|
||||
Exchanges an active web session (cookie) for a permanent API token suitable for use in the mobile app.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{ "device_name": "John's iPhone" }
|
||||
```
|
||||
|
||||
**Response (201):**
|
||||
```json
|
||||
{
|
||||
"token": "de_AbCdEfGhIjKl...",
|
||||
"token_id": 42,
|
||||
"name": "Mobile App – John's iPhone",
|
||||
"created_at": "2026-03-10T09:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ The `token` value is returned **once only**. Store it in the device's secure keychain immediately.
|
||||
|
||||
### POST /api/mobile/register-device
|
||||
|
||||
Registers an Expo push token for the authenticated user.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"push_token": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
|
||||
"device_name": "John's iPhone",
|
||||
"platform": "ios"
|
||||
}
|
||||
```
|
||||
|
||||
Supported platforms: `ios`, `android`, `web`.
|
||||
|
||||
Re-registering the same token is safe (idempotent).
|
||||
|
||||
### GET /api/mobile/whoami
|
||||
|
||||
Returns the current user's profile.
|
||||
|
||||
**Response (200):**
|
||||
```json
|
||||
{
|
||||
"owner_id": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/...",
|
||||
"is_admin": false
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
No server-side configuration is required to enable the mobile app. The Expo push notification routing does not need FCM or APNs credentials on the server.
|
||||
|
||||
If you wish to use **direct FCM/APNs** without Expo's relay, replace the `send_expo_push_notification` function in `app/utils/push_notification.py` with your own implementation.
|
||||
|
||||
## Project Structure (mobile/)
|
||||
|
||||
```
|
||||
mobile/
|
||||
├── App.tsx # Root component
|
||||
├── app.json # Expo/EAS configuration
|
||||
├── eas.json # EAS Build profiles
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── src/
|
||||
├── context/
|
||||
│ └── AuthContext.tsx # Auth state + SSO login flow
|
||||
├── hooks/
|
||||
│ └── usePushNotifications.ts # Push token registration
|
||||
├── screens/
|
||||
│ ├── LoginScreen.tsx # Server URL + SSO button
|
||||
│ ├── UploadScreen.tsx # Camera capture + file picker
|
||||
│ ├── FilesScreen.tsx # Processed document list
|
||||
│ └── ProfileScreen.tsx # User profile + sign out
|
||||
└── services/
|
||||
└── api.ts # DocuElevate REST API client
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Authentication was cancelled or failed"
|
||||
|
||||
- Ensure the server URL is correct (including `https://`).
|
||||
- Verify the server is reachable from your device's network.
|
||||
- Confirm that `AUTH_ENABLED=True` on the server.
|
||||
|
||||
### Push notifications not arriving
|
||||
|
||||
1. Check that the app has notification permission (Settings → DocuElevate → Notifications).
|
||||
2. Verify the device is registered: `GET /api/mobile/devices`.
|
||||
3. Ensure the server can reach `https://exp.host` (outbound HTTPS on port 443).
|
||||
4. On Android, add `google-services.json` to the `mobile/` directory if you are building your own binary.
|
||||
|
||||
### "Connection refused" or timeout
|
||||
|
||||
- Verify that the DocuElevate server is running and accessible.
|
||||
- Ensure the server's `EXTERNAL_HOSTNAME` or reverse proxy is configured correctly.
|
||||
- Check that the server accepts CORS requests from `docuelevate://`.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Documentation](./API.md)
|
||||
- [Configuration Guide](./ConfigurationGuide.md)
|
||||
- [Deployment Guide](./DeploymentGuide.md)
|
||||
@@ -0,0 +1,375 @@
|
||||
# Social Login Setup Guide
|
||||
|
||||
This guide explains how to configure social login providers (Google, Microsoft, Apple, Dropbox) for DocuElevate. Social login lets your users sign in with their existing accounts, reducing friction and eliminating the need for separate passwords.
|
||||
|
||||
## Overview
|
||||
|
||||
DocuElevate supports four social login providers:
|
||||
|
||||
| Provider | Protocol | Best For |
|
||||
|----------|----------|----------|
|
||||
| **Google** | OAuth2 / OpenID Connect | Consumers and Google Workspace organizations |
|
||||
| **Microsoft** | OAuth2 / OpenID Connect | Microsoft 365 / Azure AD organizations and personal Microsoft accounts |
|
||||
| **Apple** | OAuth2 / OpenID Connect | iOS/macOS users, privacy-focused users |
|
||||
| **Dropbox** | OAuth2 | Teams already using Dropbox as a storage destination |
|
||||
|
||||
Each provider is **independently enabled** — you can use one, several, or all of them at the same time. Social login works alongside any other DocuElevate authentication method (simple auth, OIDC/Authentik, local signup).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before configuring any social login provider, ensure:
|
||||
|
||||
1. **Authentication is enabled**: `AUTH_ENABLED=true` in your `.env` file
|
||||
2. **Session secret is set**: `SESSION_SECRET` must be a random string of at least 32 characters
|
||||
3. **HTTPS is configured**: All social login providers require HTTPS redirect URIs in production. Use a reverse proxy (Traefik, Nginx, Caddy) with a valid TLS certificate
|
||||
4. **External hostname is set**: `EXTERNAL_HOSTNAME` must match your public domain (e.g., `docuelevate.example.com`)
|
||||
|
||||
> **Note:** Social login users are regular (non-admin) users by default. To grant admin access, use the Admin Panel (**Settings → User Management**) after the user's first login, or configure admin groups via Authentik/OIDC.
|
||||
|
||||
## Callback URLs
|
||||
|
||||
Each social login provider uses a callback URL to redirect users back to DocuElevate after authentication. The callback URL pattern is:
|
||||
|
||||
```
|
||||
https://<EXTERNAL_HOSTNAME>/social-callback/<provider>
|
||||
```
|
||||
|
||||
For example, if your DocuElevate instance is at `https://docuelevate.example.com`:
|
||||
|
||||
| Provider | Callback URL |
|
||||
|----------|-------------|
|
||||
| Google | `https://docuelevate.example.com/social-callback/google` |
|
||||
| Microsoft | `https://docuelevate.example.com/social-callback/microsoft` |
|
||||
| Apple | `https://docuelevate.example.com/social-callback/apple` |
|
||||
| Dropbox | `https://docuelevate.example.com/social-callback/dropbox` |
|
||||
|
||||
---
|
||||
|
||||
## Google Sign-In
|
||||
|
||||
### 1. Create OAuth Credentials in Google Cloud Console
|
||||
|
||||
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project (or select an existing one)
|
||||
3. Navigate to **APIs & Services → Credentials**
|
||||
4. Click **Create Credentials → OAuth client ID**
|
||||
5. If prompted, configure the **OAuth consent screen** first:
|
||||
- **User Type**: External (or Internal for Google Workspace)
|
||||
- **App name**: DocuElevate
|
||||
- **User support email**: Your email
|
||||
- **Authorized domains**: Your domain (e.g., `example.com`)
|
||||
- **Scopes**: Add `email`, `profile`, and `openid`
|
||||
6. Back on the Credentials page, create an **OAuth 2.0 Client ID**:
|
||||
- **Application type**: Web application
|
||||
- **Name**: DocuElevate
|
||||
- **Authorized redirect URIs**: `https://docuelevate.example.com/social-callback/google`
|
||||
7. Note the **Client ID** and **Client Secret**
|
||||
|
||||
### 2. Configure DocuElevate
|
||||
|
||||
Add to your `.env` file:
|
||||
|
||||
```bash
|
||||
SOCIAL_AUTH_GOOGLE_ENABLED=true
|
||||
SOCIAL_AUTH_GOOGLE_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com
|
||||
SOCIAL_AUTH_GOOGLE_CLIENT_SECRET=GOCSPX-your-secret-here
|
||||
```
|
||||
|
||||
### 3. Restart DocuElevate
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
### Google-Specific Notes
|
||||
|
||||
- **Google Workspace**: If you want to restrict sign-in to users in your Google Workspace organization, set the OAuth consent screen to "Internal"
|
||||
- **Verification**: Google may require app verification if you're using External user type and requesting sensitive scopes. For small teams (<100 users), you can add test users instead
|
||||
- **Unified Auth**: If you also use Google Drive as a storage destination, users who sign in with Google will already be authenticated with a Google identity — simplifying the Google Drive integration experience
|
||||
|
||||
---
|
||||
|
||||
## Microsoft Sign-In (Azure AD / Microsoft Entra ID)
|
||||
|
||||
### 1. Register an Application in Azure
|
||||
|
||||
1. Go to the [Azure Portal](https://portal.azure.com/)
|
||||
2. Navigate to **Microsoft Entra ID → App registrations**
|
||||
3. Click **New registration**
|
||||
4. Fill in:
|
||||
- **Name**: DocuElevate
|
||||
- **Supported account types**: Choose based on your needs:
|
||||
- *Accounts in this organizational directory only* — single-tenant (your org only)
|
||||
- *Accounts in any organizational directory* — multi-tenant
|
||||
- *Accounts in any organizational directory and personal Microsoft accounts* — broadest reach
|
||||
- **Redirect URI**: Select **Web** and enter `https://docuelevate.example.com/social-callback/microsoft`
|
||||
5. Click **Register**
|
||||
6. Note the **Application (client) ID**
|
||||
7. Navigate to **Certificates & secrets → New client secret**
|
||||
8. Add a description and expiration, then click **Add**
|
||||
9. Note the **Value** (this is your client secret — it's only shown once!)
|
||||
|
||||
### 2. Configure API Permissions
|
||||
|
||||
1. In your app registration, go to **API permissions**
|
||||
2. Ensure these permissions are present (they're usually added by default):
|
||||
- `openid`
|
||||
- `profile`
|
||||
- `email`
|
||||
3. Click **Grant admin consent** if you're a tenant admin
|
||||
|
||||
### 3. Configure DocuElevate
|
||||
|
||||
Add to your `.env` file:
|
||||
|
||||
```bash
|
||||
SOCIAL_AUTH_MICROSOFT_ENABLED=true
|
||||
SOCIAL_AUTH_MICROSOFT_CLIENT_ID=12345678-abcd-efgh-ijkl-123456789012
|
||||
SOCIAL_AUTH_MICROSOFT_CLIENT_SECRET=your~client~secret~value
|
||||
SOCIAL_AUTH_MICROSOFT_TENANT=common
|
||||
```
|
||||
|
||||
**Tenant options:**
|
||||
|
||||
| Value | Who Can Sign In |
|
||||
|-------|----------------|
|
||||
| `common` | Any Microsoft account (personal + any Azure AD organization) |
|
||||
| `organizations` | Any Azure AD organization (work/school accounts only) |
|
||||
| `consumers` | Personal Microsoft accounts only (outlook.com, hotmail.com, etc.) |
|
||||
| `<tenant-id>` | Only users in a specific Azure AD tenant (use the GUID from Azure Portal) |
|
||||
|
||||
### 4. Restart DocuElevate
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
### Microsoft-Specific Notes
|
||||
|
||||
- **Client secret expiration**: Azure AD client secrets expire (max 2 years). Set a calendar reminder to rotate them before they expire
|
||||
- **Conditional Access**: If your organization uses Azure AD Conditional Access policies, social login will respect them
|
||||
- **Unified Auth**: If you also use OneDrive as a storage destination, users who sign in with Microsoft will already have a Microsoft identity — potentially simplifying OneDrive integration
|
||||
|
||||
---
|
||||
|
||||
## Apple Sign-In
|
||||
|
||||
Apple Sign-In requires an Apple Developer account ($99/year) and more setup than other providers.
|
||||
|
||||
### 1. Configure in Apple Developer Portal
|
||||
|
||||
1. Go to the [Apple Developer Portal](https://developer.apple.com/account/)
|
||||
2. Navigate to **Certificates, Identifiers & Profiles → Identifiers**
|
||||
3. Click **+** and select **App IDs** → Register an App ID:
|
||||
- **Description**: DocuElevate
|
||||
- **Bundle ID**: e.g., `com.example.docuelevate`
|
||||
- Enable **Sign In with Apple** capability
|
||||
4. Click **+** again and select **Services IDs**:
|
||||
- **Description**: DocuElevate Web
|
||||
- **Identifier**: e.g., `com.example.docuelevate.web` (this is your Client ID)
|
||||
- Enable **Sign In with Apple**
|
||||
- Click **Configure** next to Sign In with Apple:
|
||||
- **Primary App ID**: Select the App ID created above
|
||||
- **Domains**: `docuelevate.example.com`
|
||||
- **Return URLs**: `https://docuelevate.example.com/social-callback/apple`
|
||||
5. Click **Save** and **Continue** → **Register**
|
||||
6. Navigate to **Keys** → Click **+** to create a new key:
|
||||
- **Key Name**: DocuElevate Sign-In
|
||||
- Enable **Sign In with Apple**
|
||||
- Click **Configure** and select the App ID created above
|
||||
- Click **Continue** → **Register**
|
||||
- **Download the private key file** (`.p8`) — you can only download it once!
|
||||
- Note the **Key ID**
|
||||
7. Note your **Team ID** (shown in the top-right corner of the Developer Portal)
|
||||
|
||||
### 2. Configure DocuElevate
|
||||
|
||||
Add to your `.env` file:
|
||||
|
||||
```bash
|
||||
SOCIAL_AUTH_APPLE_ENABLED=true
|
||||
SOCIAL_AUTH_APPLE_CLIENT_ID=com.example.docuelevate.web
|
||||
SOCIAL_AUTH_APPLE_TEAM_ID=ABCDE12345
|
||||
SOCIAL_AUTH_APPLE_KEY_ID=FGHIJ67890
|
||||
SOCIAL_AUTH_APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
|
||||
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg...
|
||||
...your key content here...
|
||||
-----END PRIVATE KEY-----"
|
||||
```
|
||||
|
||||
> **Tip:** You can also store the private key as a single line with `\n` for line breaks:
|
||||
> ```bash
|
||||
> SOCIAL_AUTH_APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMG...\n-----END PRIVATE KEY-----"
|
||||
> ```
|
||||
|
||||
### 3. Restart DocuElevate
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
### Apple-Specific Notes
|
||||
|
||||
- **Email relay**: Apple offers a "Hide My Email" feature that provides a relay email address (e.g., `abc123@privaterelay.appleid.com`). DocuElevate accepts these addresses
|
||||
- **First login only**: Apple sends the user's name only on the very first authorization. If the user revokes and re-authorizes, their name may not be sent again
|
||||
- **Developer account required**: You need an Apple Developer account ($99/year) to use Sign In with Apple
|
||||
- **Key rotation**: Apple private keys don't expire, but if you suspect compromise, revoke the key in the Developer Portal and create a new one
|
||||
|
||||
---
|
||||
|
||||
## Dropbox Sign-In
|
||||
|
||||
### 1. Create a Dropbox App
|
||||
|
||||
1. Go to the [Dropbox App Console](https://www.dropbox.com/developers/apps)
|
||||
2. Click **Create app**
|
||||
3. Choose:
|
||||
- **API**: Scoped access
|
||||
- **Access type**: Full Dropbox (or App folder, depending on your needs)
|
||||
- **Name**: DocuElevate Auth (or reuse your existing Dropbox storage app)
|
||||
4. In the app settings, go to the **OAuth 2** section:
|
||||
- Add **Redirect URI**: `https://docuelevate.example.com/social-callback/dropbox`
|
||||
5. Note the **App key** (this is your Client ID) and **App secret** (this is your Client Secret)
|
||||
|
||||
> **Tip:** If you already have a Dropbox app configured for DocuElevate's storage integration, you can reuse the same app — just add the social login redirect URI. Alternatively, create a separate app for authentication to keep concerns separated.
|
||||
|
||||
### 2. Configure DocuElevate
|
||||
|
||||
Add to your `.env` file:
|
||||
|
||||
```bash
|
||||
SOCIAL_AUTH_DROPBOX_ENABLED=true
|
||||
SOCIAL_AUTH_DROPBOX_CLIENT_ID=your_dropbox_app_key
|
||||
SOCIAL_AUTH_DROPBOX_CLIENT_SECRET=your_dropbox_app_secret
|
||||
```
|
||||
|
||||
### 3. Restart DocuElevate
|
||||
|
||||
```bash
|
||||
docker compose restart api worker
|
||||
```
|
||||
|
||||
### Dropbox-Specific Notes
|
||||
|
||||
- **Unified Auth**: If you also use Dropbox as a storage destination, authenticating via Dropbox establishes the user's Dropbox identity — making it easier to manage Dropbox storage integration
|
||||
- **App review**: Dropbox may require app review for production apps with more than 50 users. See [Dropbox App Review](https://www.dropbox.com/developers/reference/developer-guide#app-review)
|
||||
- **Personal vs. Business**: The same app works for both personal Dropbox and Dropbox Business accounts
|
||||
|
||||
---
|
||||
|
||||
## Unified Authentication and Storage
|
||||
|
||||
One of the key advantages of social login in DocuElevate is the potential for **unified authentication** — using the same identity for both signing in and accessing cloud storage destinations:
|
||||
|
||||
| Social Login Provider | Related Storage Destination | Benefit |
|
||||
|---|---|---|
|
||||
| Google | Google Drive | User already has a Google identity for Drive integration |
|
||||
| Microsoft | OneDrive | User already has a Microsoft identity for OneDrive integration |
|
||||
| Dropbox | Dropbox | User already has a Dropbox identity for Dropbox integration |
|
||||
| Apple | *(none)* | Provides a familiar, privacy-respecting login option |
|
||||
|
||||
When a user signs in with a social provider that matches a configured storage destination, the administrator can leverage the same OAuth credentials or simplify the integration setup. Note that the storage integration credentials are configured separately in the admin settings — social login establishes the user's identity, not their storage permissions.
|
||||
|
||||
## Combining Multiple Auth Methods
|
||||
|
||||
DocuElevate supports running multiple authentication methods simultaneously:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Login Page │
|
||||
├──────────────────────────────────────────────────┤
|
||||
│ Username / Password form (always shown) │
|
||||
│ │
|
||||
│ ─── Or continue with ─── │
|
||||
│ │
|
||||
│ [Authentik SSO] (if OIDC configured) │
|
||||
│ [Sign in with Google] (if Google enabled) │
|
||||
│ [Sign in with Microsoft] (if Microsoft enabled) │
|
||||
│ [Sign in with Apple] (if Apple enabled) │
|
||||
│ [Sign in with Dropbox] (if Dropbox enabled) │
|
||||
│ │
|
||||
│ [Create account] (if local signup enabled) │
|
||||
└──────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
All methods create or update the same `UserProfile` record, so a user is consistently identified regardless of how they sign in.
|
||||
|
||||
## Admin Management
|
||||
|
||||
Social login users appear in the **Admin → User Management** panel like any other user. Admins can:
|
||||
|
||||
- View which provider a user authenticated with
|
||||
- Block or unblock social login users
|
||||
- Set upload limits and subscription tiers
|
||||
- Grant admin privileges (social login users are never automatically admin)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **HTTPS is required**: All social login providers require HTTPS callback URLs in production
|
||||
2. **Credentials are sensitive**: Store client secrets securely — use environment variables, never commit them to source control
|
||||
3. **Least privilege**: Only request the scopes you need (DocuElevate requests `openid`, `profile`, and `email`)
|
||||
4. **Rotate secrets**: Set calendar reminders to rotate OAuth client secrets before they expire (especially Microsoft, which has a max 2-year expiration)
|
||||
5. **Monitor logins**: Check the DocuElevate audit log for unusual login patterns
|
||||
6. **Social login users are not admins**: Admin access must be explicitly granted by an existing admin
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **"Unknown social provider" error**
|
||||
- The provider is not enabled or credentials are missing
|
||||
- Check that `SOCIAL_AUTH_<PROVIDER>_ENABLED=true` is set
|
||||
- Verify client ID and secret are configured
|
||||
|
||||
2. **"Could not retrieve email from provider" error**
|
||||
- The provider didn't return an email address
|
||||
- For Google: Ensure `email` scope is included (it is by default)
|
||||
- For Apple: User may have chosen "Hide My Email" — this is expected and should still work
|
||||
- For Dropbox: Ensure the app has permission to read the user's email
|
||||
|
||||
3. **Redirect URI mismatch**
|
||||
- The callback URL registered with the provider must exactly match what DocuElevate generates
|
||||
- Check your `EXTERNAL_HOSTNAME` setting
|
||||
- Ensure you're using HTTPS in production
|
||||
- The callback URL format is: `https://<EXTERNAL_HOSTNAME>/social-callback/<provider>`
|
||||
|
||||
4. **"Social login failed" error**
|
||||
- Check DocuElevate logs (`docker compose logs api`) for detailed error messages
|
||||
- Verify the provider's OAuth app is not suspended or in development mode
|
||||
- For Google: Check if the OAuth consent screen needs verification
|
||||
- For Microsoft: Ensure admin consent was granted for the required permissions
|
||||
|
||||
5. **User can't log in after changing provider settings**
|
||||
- After changing social login configuration, restart DocuElevate: `docker compose restart api worker`
|
||||
- Social login settings require a restart to take effect (`restart_required: true`)
|
||||
|
||||
### Debug Checklist
|
||||
|
||||
- [ ] `AUTH_ENABLED=true` is set
|
||||
- [ ] `SESSION_SECRET` is at least 32 characters
|
||||
- [ ] `EXTERNAL_HOSTNAME` matches your public domain
|
||||
- [ ] Provider-specific `_ENABLED=true` is set
|
||||
- [ ] Client ID and secret are correctly configured (no extra spaces)
|
||||
- [ ] Callback URL is registered with the provider
|
||||
- [ ] HTTPS is working on your domain
|
||||
- [ ] DocuElevate has been restarted after configuration changes
|
||||
|
||||
## Environment Variable Reference
|
||||
|
||||
| Variable | Required | Description |
|
||||
|---|---|---|
|
||||
| `SOCIAL_AUTH_GOOGLE_ENABLED` | No | Enable Google Sign-In (`true`/`false`). Default: `false` |
|
||||
| `SOCIAL_AUTH_GOOGLE_CLIENT_ID` | When Google enabled | Google OAuth2 client ID |
|
||||
| `SOCIAL_AUTH_GOOGLE_CLIENT_SECRET` | When Google enabled | Google OAuth2 client secret |
|
||||
| `SOCIAL_AUTH_MICROSOFT_ENABLED` | No | Enable Microsoft Sign-In (`true`/`false`). Default: `false` |
|
||||
| `SOCIAL_AUTH_MICROSOFT_CLIENT_ID` | When Microsoft enabled | Azure AD application (client) ID |
|
||||
| `SOCIAL_AUTH_MICROSOFT_CLIENT_SECRET` | When Microsoft enabled | Azure AD client secret |
|
||||
| `SOCIAL_AUTH_MICROSOFT_TENANT` | No | Azure AD tenant. Default: `common` |
|
||||
| `SOCIAL_AUTH_APPLE_ENABLED` | No | Enable Apple Sign-In (`true`/`false`). Default: `false` |
|
||||
| `SOCIAL_AUTH_APPLE_CLIENT_ID` | When Apple enabled | Apple Services ID |
|
||||
| `SOCIAL_AUTH_APPLE_TEAM_ID` | When Apple enabled | Apple Developer Team ID |
|
||||
| `SOCIAL_AUTH_APPLE_KEY_ID` | When Apple enabled | Apple Sign-In key ID |
|
||||
| `SOCIAL_AUTH_APPLE_PRIVATE_KEY` | When Apple enabled | Apple Sign-In private key (PEM) |
|
||||
| `SOCIAL_AUTH_DROPBOX_ENABLED` | No | Enable Dropbox Sign-In (`true`/`false`). Default: `false` |
|
||||
| `SOCIAL_AUTH_DROPBOX_CLIENT_ID` | When Dropbox enabled | Dropbox App Key |
|
||||
| `SOCIAL_AUTH_DROPBOX_CLIENT_SECRET` | When Dropbox enabled | Dropbox App Secret |
|
||||
@@ -348,6 +348,7 @@ in task messages or logs.
|
||||
| `PAPERLESS` | Paperless-ngx REST API, API token |
|
||||
| `EMAIL` | SMTP/STARTTLS, file as attachment |
|
||||
| `RCLONE` | `rclone copyto` subprocess, per-user rclone config |
|
||||
| `ICLOUD` | pyicloud library, Apple ID + app-specific password |
|
||||
|
||||
### Multiple Destinations
|
||||
|
||||
|
||||
@@ -63,6 +63,54 @@ DocuElevate will process the following attachment types from emails:
|
||||
| TIFF | `.tif`, `.tiff` | Common format from older scanners/fax |
|
||||
| Multi-page TIFF | `.tif` | Full multi-page support |
|
||||
|
||||
### Controlling Which Attachment Types Are Ingested
|
||||
|
||||
By default, DocuElevate only ingests **document** attachments (PDFs, Word, Excel, PowerPoint, OpenDocument, RTF, TXT, CSV, HTML, Markdown). Images are **not** ingested by default — this prevents cluttering your document archive with inline images or unrelated photo attachments.
|
||||
|
||||
#### Global Default (Admin Setting)
|
||||
|
||||
Set the `IMAP_ATTACHMENT_FILTER` environment variable to control the system-wide fallback when no ingestion profile is assigned to a mailbox:
|
||||
|
||||
| Value | Behaviour |
|
||||
|-------|-----------|
|
||||
| `documents_only` | **(Default)** Only PDFs and office/document files. Images are skipped. |
|
||||
| `all` | All supported file types, including images. |
|
||||
|
||||
```env
|
||||
IMAP_ATTACHMENT_FILTER=documents_only
|
||||
```
|
||||
|
||||
#### Ingestion Profiles (Fine-Grained Per-Mailbox Control)
|
||||
|
||||
For precise control, you can create **Ingestion Profiles** that let you pick exactly which file-type categories to accept from each mailbox. This is more powerful than the binary global toggle and works independently per mailbox.
|
||||
|
||||
**Available categories:**
|
||||
|
||||
| Category | File types included |
|
||||
|----------|---------------------|
|
||||
| PDF | `.pdf` |
|
||||
| Microsoft Office | `.doc`, `.docx`, `.xls`, `.xlsx`, `.ppt`, `.pptx`, and macro-enabled variants |
|
||||
| OpenDocument | `.odt`, `.ods`, `.odp`, `.odg`, `.odf` (LibreOffice / OpenOffice) |
|
||||
| Text & Data | `.txt`, `.csv`, `.rtf` |
|
||||
| Web & Markup | `.html`, `.htm`, `.md`, `.markdown` |
|
||||
| Images | `.jpg`, `.png`, `.gif`, `.bmp`, `.tiff`, `.webp`, `.svg` |
|
||||
|
||||
**Managing profiles:**
|
||||
|
||||
1. Go to **Email Ingestion** (`/imap-accounts`)
|
||||
2. Click **Manage profiles** (or the **+** icon next to the profile dropdown)
|
||||
3. Create a new profile, give it a name, and tick the categories you want
|
||||
4. When adding or editing a mailbox, select your profile from the dropdown
|
||||
|
||||
Two built-in profiles are always available and cannot be deleted:
|
||||
|
||||
- **Documents Only** — PDF, Office, OpenDocument, Text, Web (no images)
|
||||
- **All Files** — all categories including images
|
||||
|
||||
Users can also create unlimited **custom profiles** to mix and match exactly the categories they need per mailbox (e.g. a scanner mailbox that only accepts PDFs, or a finance mailbox that accepts Office and CSV but not images).
|
||||
|
||||
Custom profiles are created via the UI or the `/api/imap-profiles/` API.
|
||||
|
||||
---
|
||||
|
||||
## Setting Up Your Scanner/Device
|
||||
|
||||
Reference in New Issue
Block a user