Architecture¶
GeoSync is a server-rendered PHP control plane around PostgreSQL metadata and host-managed synchronization workers. It is not a single self-contained service: normal operation depends on systemd, filesystem configuration, Python/CLI tools, and optional sibling services.
Component view¶
flowchart LR
B[Browser] --> W[Apache + PHP GeoSync]
W --> M[(GeoSync PostgreSQL)]
W --> C[(Central metadata DB)]
W --> F[FIFO backend]
F --> S[systemd]
S --> Q[QField worker]
S --> D[Mergin DB Sync]
S --> A[ArcGIS worker]
Q & D & A --> P[(Target PostGIS)]
Q & D & A --> FS[Project files]
PHP pages under admin/ render views; admin/action/*.php accept form requests, perform session/ownership checks, update metadata/configuration, and write backend commands. Domain classes use the procedural PostgreSQL extension directly; there is no framework, router, ORM, migration runner, or dependency-injection layer.
Request flow¶
sequenceDiagram
participant U as Browser
participant A as Auth prepend
participant P as PHP page/action
participant DB as GeoSync DB
participant B as Backend FIFO
U->>A: HTTP request + session cookie
A->>A: Resolve mode and authorize
A->>P: Hydrated legacy session
P->>DB: Read/write records
opt service operation
P->>B: op type project-id
B-->>P: FIFO write completes
end
P-->>U: HTML, JSON, or file
The proxy endpoint api/proxy.php additionally validates an exact service/method/path allow-list, handles selected analysis operations in PHP, or forwards JSON with X-User-ID. The generic analysis and FormBuilder proxies require a recognized session but do not forward all request headers/methods.
Authentication and authorization¶
flowchart TD
R[Request] --> M{Auth mode}
M -->|central| K[Read acugis_session]
K --> D{Central DSN works?}
D -->|yes| L[Hash token and query sessions/users/groups]
D -->|no or no match| API[GET Central /api/me]
L & API --> ADM{Platform admin?}
ADM -->|yes| H[Hydrate synthetic GeoSync Admin]
ADM -->|no| X[403]
M -->|local| LS[Legacy PHP session]
M -->|keycloak| O[Legacy OIDC session/roles]
H & LS & O --> APP[Page/action checks]
Current Central integration is administrator-only. A service ACL helper and bridge/JIT-provisioning implementation exist, but the main prepend does not call them. Public Central paths are limited to login/logout/signup and legacy login/signup/verification actions.
Database model¶
erDiagram
USER ||--o{ SERVER : owns
USER ||--o{ PGLINK : owns
USER ||--o{ PROJECT : owns
USER ||--o{ RSYNC : owns
USER ||--o{ GEONODE : owns
USER ||--o{ GROUP : owns
USER ||--o{ GSTORE : owns
SERVER ||--o{ PROJECT : hosts
PGLINK ||--o{ PROJECT : targets
PROJECT ||--o{ PROJECT_RSYNC : uses
RSYNC ||--o| PROJECT_RSYNC : attached
PROJECT ||--o{ GSTORE : publishes
PROJECT o|--o{ RSYNC : local_target
USER ||--o| GEOSYNC_USER_BRIDGE : maps
The base schema also has signup. Optional publish columns live on project. The bridge table and user.enabled/auth_source are optional SQL. sync_secrets is referenced by PHP but has no supplied DDL. Central tables (dashboard_sessions, dashboard_users, auth groups, resources, permissions) belong to the sibling platform database.
Worker flow¶
flowchart TD
UI[Admin action] --> CFG[Write project INI/YAML]
UI --> FIFO[Write backend FIFO]
FIFO --> SD[systemctl template instance]
SD --> T{Project type}
T -->|qf| Q[Poll/download QField files]
T -->|gdb| G[Download GDB and ogr2ogr to GPKG]
T -->|db| D[Patched Mergin DB Sync]
Q & G --> GD[geodiff copy/diff/apply]
GD & D --> PG[(Target PostGIS)]
Q & D --> IMG[Copy image files]
Q & D --> RS[Run attached rsync scripts]
Workers log to /var/log/qz_sync<id>.log; the backend logs to /var/log/qz_sync_backend.log in supplied units. single_run, sleep_time, initialization flags, and QField retention are configuration-driven.
There are no cron jobs, systemd timer units, or separate queue workers in the repository. Recurring synchronization is implemented inside the long-running QField/ArcGIS loops with sleep_time, and inside the external Mergin DB Sync daemon. Optional rsync work runs after a synchronization cycle; it is not independently scheduled.
Cache and storage¶
flowchart LR
S[PHP session] --> PS[PHP session handler]
C[Generated config] --> QC[/etc/quartz-sync.d]
W[Worker data] --> QD[QZ_DATA]
QD --> GP[Current and retained GeoPackages]
QC --> RL[Rsync scripts/logs/PIDs/excludes]
QD --> TMP[Diffs and temporary downloads]
PUB[QGIS publishing] --> PR[PROJECTS_ROOT]
No Redis, Memcached, application cache abstraction, or explicit HTTP response cache exists. The effective cache is filesystem state: downloaded projects, retained QField snapshots, metadata files, and PHP sessions. Analysis static overrides are sent with Cache-Control: no-cache.
Storage locations vary by worker:
- QField/ArcGIS:
QZ_HOME/data/<project-id>; defaultQZ_HOME/dataequalsQZ_DATA. - Mergin DB Sync: external worker paths under
QZ_DATA/dbsync; source contains both project-name andproj_<id>assumptions, so verify the installed DB Sync patch/version. - Rsync support:
QZ_CONF/rsync.d. - Published QGIS projects:
QGIS_PUBLISH_PROJECTS_ROOT/<publisher-id>.
Integrations¶
flowchart LR
GS[GeoSync] --> QF[QFieldCloud API/CLI]
GS --> MM[Mergin Maps CLI/DB Sync]
GS --> AG[ArcGIS API]
GS --> GE[GeoServer]
GS --> SSH[SSH/rsync targets]
GS --> QP[qgis-publish-service]
GS --> FB[FormBuilder upstream]
GS --> AN[Analysis upstream]
GS --> CT[Central auth]
QF & MM & AG --> PG[(PostGIS)]
QGIS publishing zips the synchronized directory, requires a .qgs or .qgz, POSTs database credentials and the bundle to /api/geosync-publish, and stores returned publisher ID/viewer URL. The client currently disables TLS peer/host verification; keep the upstream on trusted loopback/private networking until that is fixed.
Scaling and consistency¶
The architecture assumes one control-plane host with one named pipe and host-level systemd. Multiple PHP workers can share the metadata database, but FIFO writes, mutable config files, project work directories, and service control are not coordinated for multiple GeoSync hosts. Horizontal scaling is unsupported without shared storage, a distributed command queue/lock strategy, and worker placement. PostgreSQL and worker services may be scaled independently according to their own products.