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 authenticationTimezoneMiddleware: Per-user timezone handlingClientTypeMiddleware: Detects client type (QField, QGIS, web)
- Management Commands: Custom Django management commands
docker-app/qfieldcloud/core/models.py:
User: Custom user model extending Django’s authOrganization: Account owners (users or organizations)Project: QGIS projects with file storage and collaborationJob: 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
settings.py:
qfieldcloud.filestorage
Manages file storage abstraction:
- Backends:
QfcS3Boto3Storage: S3-compatible storage (MinIO, AWS S3)QfcWebDavStorage: WebDAV storage (NextCloud, etc.)
- Models:
File,FileVersionfor versioning support - Storage routing: Different storages for projects and attachments
settings.py:301-343:
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 (seesettings.py:92-145):
rest_framework: REST API frameworkdrf_spectacular: OpenAPI schema generationallauth: Social authenticationdjango_filters: API filteringauditlog: Model change auditingdjango_cron: Scheduled tasksaxes: Brute-force protectiondebug_toolbar: Development debuggingjazzmin: Admin interface theme
Worker System
worker_wrapper
The background job processor atdocker-app/worker_wrapper/wrapper.py:
- Polls the database for pending jobs
- Spawns Docker containers running QGIS workers
- Monitors job execution and handles timeouts
- Updates job status in the database
settings.py:
- 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
PACKAGE: Create QField packages from QGIS projectsDELTA_APPLY: Apply deltas (changes) from QFieldPROCESS_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 (seesettings.py:370-380):
API Documentation
Automatically generated viadrf-spectacular:
- Swagger UI:
https://localhost/swagger/ - ReDoc:
https://localhost/redoc/ - OpenAPI Schema:
https://localhost/api/v1/schema/
settings.py:929-935.
Permissions
Role-based permissions per project:owner: Full controladmin: Manage collaborators and settingsmanager: Manage content and fileseditor: Edit datareporter: Read-only access
Database Schema
Core Tables
core_user: User accountscore_organization: Organizationscore_project: QGIS projectscore_job: Background jobscore_delta: Change trackingfilestorage_file: File metadatafilestorage_fileversion: File versions
Migrations
Django migrations are indocker-app/qfieldcloud/*/migrations/.
Run migrations:
Middleware Stack
Middleware order matters (seesettings.py:147-168):
DebugToolbarMiddleware: Development debuggingCorsMiddleware: Cross-origin resource sharingSecurityMiddleware: Security headersSessionMiddleware: Session managementLocaleMiddleware: InternationalizationCommonMiddleware: Common processingCsrfViewMiddleware: CSRF protectionAuthenticationMiddleware: User authenticationRequestIDMiddleware: Request trackingAuditlogMiddleware: Model change loggingTimezoneMiddleware: User timezone handlingQGISAuthenticationMiddleware: QGIS client authClientTypeMiddleware: Client type detection
Cron Jobs
Scheduled tasks via django-cron (seesettings.py:170-176):
SendNotificationsJob: Batch notification deliveryResendFailedInvitationsJob: Retry failed invitesSetTerminatedWorkersToFinalStatusJob: Clean up worker statusDeleteObsoleteProjectPackagesJob: Remove old packages
Static Files & Media
- Static files (CSS/JS): Served from
STATIC_ROOTvia nginx - Media files: Stored in S3/WebDAV, served via signed URLs
- Project files: Managed by
filestorageapp
settings.py:273-288.
Logging
JSON-formatted logs via custom formatter (seesettings.py:632-656):
- 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 modeENVIRONMENT:development,staging,test, orproductionQFIELDCLOUD_HOST: Main hostnameSECRET_KEY: Django secret keyPOSTGRES_*: Database connectionSTORAGES: Storage backend configurationQFIELDCLOUD_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
- Local Setup - Set up your development environment
- Testing - Run and write tests
- Debugging - Debug the application