Architecture Overview

System Overview

Questbee has three client surfaces — a web dashboard, a mobile app, and a headless API — all backed by a single FastAPI service and a PostgreSQL database, packaged as a Docker Compose stack that runs entirely on your own server.

┌────────────────────────────────────────────────────────────────────┐
│                         CLIENT SURFACES                            │
├─────────────────┬──────────────────────┬───────────────────────────┤
│  Web Dashboard  │    Mobile App        │    Headless API / IoT     │
│  (Next.js)      │    (React Native)    │    (API key auth)         │
│  Browser        │    iOS + Android     │    External systems       │
└────────┬────────┴──────────┬───────────┴───────────┬───────────────┘
         │                   │                        │
         │         HTTPS / REST API (FastAPI)         │
         └───────────────────┼────────────────────────┘
                             │
         ┌───────────────────▼────────────────────────┐
         │              FastAPI Backend               │
         │  • Forms & versioned schemas               │
         │  • Offline sync engine                     │
         │  • Auth: JWT + API keys + device tokens    │
         │  • Role-based access control               │
         │  • Media file storage                      │
         │  • Data export (CSV, GeoJSON, GPX, ZIP)    │
         └───────────────────┬────────────────────────┘
                             │
         ┌───────────────────▼────────────────────────┐
         │              PostgreSQL                    │
         │  • Forms, submissions (JSONB)              │
         │  • Users, tenants, projects                │
         │  • API keys, media files, device tokens    │
         └────────────────────────────────────────────┘

All containers run inside a Docker Compose stack on your own infrastructure. No data is sent to Questbee servers.


Components

Web Dashboard (Next.js)

Browser-based interface for program managers and administrators.

  • Build and publish forms with a visual form builder
  • Manage users and assign roles (Admin, Manager, Field Worker)
  • Browse, search, and review submissions with media preview
  • Export data as CSV, GeoJSON, GPX, or media ZIP
  • Generate pairing QR codes and manage connected devices
  • Manage API keys for headless integrations

Mobile App (React Native / Expo)

Offline-first data collection app for field workers.

  • Pairs with the server via QR code — no separate login required
  • Downloads assigned form schemas to the device
  • Collects data with no internet connection — data saved locally in SQLite
  • Automatically syncs pending submissions and media files when back online
  • Supports GPS, photos, audio, signatures, barcodes, and more

Distribution: Android APK available as a free download. iOS available on paid plans. White-label compilation is available on paid plans.

Backend API (FastAPI)

The central service. All three client surfaces communicate through it.

AreaDescription
FormsCRUD for form schemas; immutable versioning on publish
SubmissionsAccept from mobile (JWT) and headless API (API key); idempotent bulk sync
MediaFile upload and authenticated retrieval; stored on the server filesystem
SyncBulk submission endpoint with device-UUID deduplication
AuthJWT for dashboard users; API keys for IoT/headless; device tokens for mobile
RBACRole enforcement: Admin > Manager > Field Worker
ExportCSV (flat + repeat groups), GeoJSON, GPX, media ZIP, full package
SettingsMobile pairing tokens, connected device management, server URL config
WebhooksPer-form HTTP webhooks triggered on new submissions

Database (PostgreSQL)

All persistent data lives here.

Core tables: tenants, projects, forms, form_versions, submissions, users, api_keys, media_files, device_tokens, pairing_tokens

Form schemas and submission data are stored as JSONB — flexible enough to support any combination of field types without a schema migration per form change.


Tech Stack

LayerTechnology
BackendFastAPI (Python 3.11+)
Web dashboardNext.js 14 + TypeScript + Tailwind CSS
Mobile appReact Native / Expo (TypeScript)
Mobile local DBSQLite (via Expo SQLite)
Server DBPostgreSQL 15
ContainersDocker + Docker Compose v2

Minimum server requirements: 2 CPU cores, 4 GB RAM, 50 GB disk, Ubuntu 22.04 or equivalent.


Data Flow: Offline Mobile Sync

Field worker fills form — no internet
        │
        ▼
Saved to SQLite on device (status: pending)
Media files (photos, audio) stored on device
        │
Device reconnects
        │
        ▼
Sync engine: POST /api/v1/submissions/bulk
Each submission carries a device-generated UUID — retries never create duplicates
        │
        ├─ 200 OK  → submission marked as synced
        └─ error   → retried with exponential backoff

Media uploads: POST /api/v1/media/upload (per file, after submission sync)

Device Pairing Flow

Admin generates pairing token in dashboard
        │
        ▼
QR code encodes: server URL + one-time token + user identity
        │
Field worker scans QR code with mobile app
        │
        ▼
POST /api/v1/mobile/pair
  - token validated and consumed
  - device_token issued and stored securely on device
  - forms downloaded automatically
        │
        ▼
Subsequent requests: Authorization: Bearer <device_token>

No separate login step is required on the device — the QR code embeds the user identity.


Multi-Tenancy

A single Questbee instance serves multiple independent organizations. Each tenant has its own users, projects, forms, and submissions — isolated at the database query level by tenant_id.


Security

  • JWT for web dashboard sessions (short-lived access tokens + refresh tokens)
  • API keys for headless/IoT integrations (hashed in the database, scoped to projects)
  • Device tokens for mobile app pairing (per-device, revocable from the dashboard)
  • RBAC enforced at the API layer on every request
  • Multi-tenant isolation — all queries are scoped to tenant_id
  • No external dependencies — no calls to third-party services for core functionality

See Also