Skip to main content
QFieldCloud is a Django 4.2 application designed to synchronize projects and data between QGIS (with QFieldSync plugin) and QField.

Technology Stack

  • Framework: Django 4.2 with GeoDjango (PostGIS)
  • API: Django REST Framework with drf-spectacular (OpenAPI/Swagger)
  • Database: PostgreSQL 17 + PostGIS 3.5
  • Storage: S3-compatible (MinIO) or WebDAV
  • Authentication: django-allauth (supports OAuth2/OIDC)
  • Background Jobs: Custom worker system with Docker-in-Docker QGIS workers
  • Cache: Memcached (PyMemcache)
  • Web Server: Gunicorn + Nginx

Django Apps Structure

QFieldCloud is organized into the following Django apps:

Core Apps

qfieldcloud.core

The main application containing:
  • Models: User, Organization, Team, Project, Job, Delta, Secret, etc.
  • API Views: REST endpoints for projects, files, jobs, organizations
  • Permissions: Role-based access control (owner, admin, manager, editor, reporter)
  • Middleware:
    • QGISAuthenticationMiddleware: QGIS-specific authentication
    • TimezoneMiddleware: Per-user timezone handling
    • ClientTypeMiddleware: Detects client type (QField, QGIS, web)
  • Management Commands: Custom Django management commands
Key models at docker-app/qfieldcloud/core/models.py:
  • User: Custom user model extending Django’s auth
  • Organization: Account owners (users or organizations)
  • Project: QGIS projects with file storage and collaboration
  • Job: Background processing tasks (package, process_projectfile, delta_apply, etc.)
  • Delta: Change tracking for offline-online sync

qfieldcloud.authentication

Handles authentication and authorization:
  • Custom authentication backends (see settings.py:70-75)
  • Token-based authentication for API clients
  • OAuth2/OIDC integration via django-allauth
  • Authentication adapters for signup control
Configuration in settings.py:
AUTHENTICATION_BACKENDS = [
    "axes.backends.AxesBackend",
    "qfieldcloud.authentication.auth_backends.AuthenticationBackend",
]

qfieldcloud.filestorage

Manages file storage abstraction:
  • Backends:
    • QfcS3Boto3Storage: S3-compatible storage (MinIO, AWS S3)
    • QfcWebDavStorage: WebDAV storage (NextCloud, etc.)
  • Models: File, FileVersion for versioning support
  • Storage routing: Different storages for projects and attachments
Storage configuration in settings.py:301-343:
STORAGES = {
    "default": {
        "BACKEND": "qfieldcloud.filestorage.backend.QfcS3Boto3Storage",
        "OPTIONS": {...}
    }
}

qfieldcloud.subscription

Subscription and quota management:
  • Plan and package management
  • Storage and organization member quotas
  • Trial period handling

qfieldcloud.notifs

Notification system:
  • Email notifications
  • In-app notifications via django-notifications-hq
  • Cron job for sending batched notifications

Installed Apps

Key third-party apps (see settings.py:92-145):
  • rest_framework: REST API framework
  • drf_spectacular: OpenAPI schema generation
  • allauth: Social authentication
  • django_filters: API filtering
  • auditlog: Model change auditing
  • django_cron: Scheduled tasks
  • axes: Brute-force protection
  • debug_toolbar: Development debugging
  • jazzmin: Admin interface theme

Worker System

worker_wrapper

The background job processor at docker-app/worker_wrapper/wrapper.py:
  1. Polls the database for pending jobs
  2. Spawns Docker containers running QGIS workers
  3. Monitors job execution and handles timeouts
  4. Updates job status in the database
Configuration in settings.py:
WORKER_TIMEOUT_S = 600  # From constance
QFIELDCLOUD_QGIS_IMAGE_NAME = os.environ["QFIELDCLOUD_QGIS_IMAGE_NAME"]
QFIELDCLOUD_WORKER_QFIELDCLOUD_URL = os.environ["QFIELDCLOUD_WORKER_QFIELDCLOUD_URL"]
Key features:
  • Docker-in-Docker execution
  • Resource limits (memory, CPU shares)
  • Volume mounting for shared data
  • Network isolation

QGIS Docker Workers

The QGIS workers run in separate containers:
  • Based on a custom QGIS Docker image
  • Execute QGIS processing tasks (packaging, delta application, etc.)
  • Communicate with the main app via REST API
  • Access project files from shared storage
Worker types (Job.Type):
  • PACKAGE: Create QField packages from QGIS projects
  • DELTA_APPLY: Apply deltas (changes) from QField
  • PROCESS_PROJECTFILE: Process and validate QGIS project files

REST API Design

API Versioning

API is versioned at the URL level: /api/v1/

Authentication

Supports multiple authentication methods (see settings.py:370-380):
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "qfieldcloud.authentication.authentication.TokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ],
}

API Documentation

Automatically generated via drf-spectacular:
  • Swagger UI: https://localhost/swagger/
  • ReDoc: https://localhost/redoc/
  • OpenAPI Schema: https://localhost/api/v1/schema/
Configuration in settings.py:929-935.

Permissions

Role-based permissions per project:
  • owner: Full control
  • admin: Manage collaborators and settings
  • manager: Manage content and files
  • editor: Edit data
  • reporter: Read-only access

Database Schema

Core Tables

  • core_user: User accounts
  • core_organization: Organizations
  • core_project: QGIS projects
  • core_job: Background jobs
  • core_delta: Change tracking
  • filestorage_file: File metadata
  • filestorage_fileversion: File versions

Migrations

Django migrations are in docker-app/qfieldcloud/*/migrations/. Run migrations:
docker compose exec app python manage.py migrate

Middleware Stack

Middleware order matters (see settings.py:147-168):
  1. DebugToolbarMiddleware: Development debugging
  2. CorsMiddleware: Cross-origin resource sharing
  3. SecurityMiddleware: Security headers
  4. SessionMiddleware: Session management
  5. LocaleMiddleware: Internationalization
  6. CommonMiddleware: Common processing
  7. CsrfViewMiddleware: CSRF protection
  8. AuthenticationMiddleware: User authentication
  9. RequestIDMiddleware: Request tracking
  10. AuditlogMiddleware: Model change logging
  11. TimezoneMiddleware: User timezone handling
  12. QGISAuthenticationMiddleware: QGIS client auth
  13. ClientTypeMiddleware: Client type detection

Cron Jobs

Scheduled tasks via django-cron (see settings.py:170-176):
  • SendNotificationsJob: Batch notification delivery
  • ResendFailedInvitationsJob: Retry failed invites
  • SetTerminatedWorkersToFinalStatusJob: Clean up worker status
  • DeleteObsoleteProjectPackagesJob: Remove old packages

Static Files & Media

  • Static files (CSS/JS): Served from STATIC_ROOT via nginx
  • Media files: Stored in S3/WebDAV, served via signed URLs
  • Project files: Managed by filestorage app
Configuration in settings.py:273-288.

Logging

JSON-formatted logs via custom formatter (see settings.py:632-656):
docker compose logs nginx app worker_wrapper
Logs include:
  • Request IDs for tracing
  • Structured JSON output
  • Sentry integration for error tracking

Environment Configuration

Key environment variables (see .env.example and settings.py):
  • DEBUG: Enable debug mode
  • ENVIRONMENT: development, staging, test, or production
  • QFIELDCLOUD_HOST: Main hostname
  • SECRET_KEY: Django secret key
  • POSTGRES_*: Database connection
  • STORAGES: Storage backend configuration
  • QFIELDCLOUD_QGIS_IMAGE_NAME: QGIS worker image

Security Features

  • Rate limiting: Via django-axes (5 failed login attempts)
  • CSRF protection: Django’s CSRF middleware
  • SQL injection: Django ORM parameterized queries
  • XSS protection: Django template auto-escaping
  • Encrypted fields: Via django-fernet-encrypted-fields
  • SSL/TLS: Nginx with Let’s Encrypt or self-signed certs
  • Audit logging: Via django-auditlog for model changes

Next Steps

Build docs developers (and LLMs) love