DEV Community

Cover image for Designing a One-Way Farm Sync Architecture (Nextcloud Django DRF)
Rahim Ranxx
Rahim Ranxx

Posted on

Designing a One-Way Farm Sync Architecture (Nextcloud Django DRF)

From Nextcloud to Django: Designing a Farm Sync Architecture with DRF

Modern applications rarely live in a single system. As projects grow, different components begin to specialize: one system handles identity and user workflows, while another focuses on computation and domain logic.

This week I explored a small but interesting distributed architecture problem: how to synchronize farm data between a Nextcloud application and a Django REST API backend.

The goal was simple in theory:

  • Nextcloud provides the user interface.
  • Django performs geospatial computation (NDVI, raster processing).
  • Farm data must stay consistent between the two systems.

But as any engineer knows, “simple in theory” is where architecture decisions start to matter.


The Initial Problem

In the system I’m building, users manage farms from a Nextcloud application while a Django service handles geospatial workloads.

The challenge was deciding where farm data should live and how it should propagate between systems.

Three architectural questions emerged:

  1. Which system is the source of truth?
  2. How do we synchronize data between services?
  3. How do we avoid identity conflicts between systems?

These are classic distributed systems questions, even in relatively small projects.


Option 1: Bidirectional Sync (The Dangerous Path)

One tempting solution is letting both systems create farms and then syncing them.

Nextcloud <--> Django
Enter fullscreen mode Exit fullscreen mode

At first glance this feels flexible. In practice it creates difficult problems:

  • conflicting updates
  • race conditions
  • reconciliation logic
  • versioning requirements

Large distributed databases solve this with vector clocks and conflict resolution strategies. For most applications, that complexity is unnecessary.

So I rejected bidirectional replication early.


Option 2: API-First Architecture

Instead of replicating farms between databases, Nextcloud simply delegates creation to the Django API.

When a user creates a farm in Nextcloud:

User
  ↓
Nextcloud UI
  ↓
Nextcloud Controller
  ↓
POST /api/v1/farms/ (Django REST Framework)
  ↓
Django database
Enter fullscreen mode Exit fullscreen mode

Django becomes the source of truth for farm data, while Nextcloud acts as the interface layer.

This pattern has several advantages.

Immediate Consistency

Since farms are created directly in Django, the backend always has the latest data.

There is no delayed replication.

Clear Ownership

Each system has a defined responsibility:

  • Nextcloud – user interface, identity, workflow
  • Django – domain logic, geospatial processing, data storage

Clear boundaries reduce architectural complexity.

Extensibility

Once Django exposes a clean API, other systems can integrate easily:

  • mobile apps
  • data pipelines
  • satellite processing services
  • analytics dashboards

Everything interacts with the same API.


Solving the Cross-System Identity Problem

Once multiple systems talk about the same object, a subtle problem appears:

identity consistency.

If each system generated its own farm IDs, synchronization would become fragile:

Nextcloud Farm ID = 12
Django Farm ID = 47
Enter fullscreen mode Exit fullscreen mode

Now every integration requires mapping tables.

Instead, the architecture introduces a stable external identifier.

Nextcloud generates a UUID called:

external_farm_id
Enter fullscreen mode Exit fullscreen mode

That UUID is sent to Django whenever a farm is synchronized.

Conceptually the model looks like this:

Farm
 ├─ id (internal database id)
 └─ external_farm_id (shared UUID)
Enter fullscreen mode Exit fullscreen mode

Now both systems reference the farm using the same identifier.

When Nextcloud syncs a farm:

POST /api/v1/farms/sync
Enter fullscreen mode Exit fullscreen mode

Payload example:

{
  "external_farm_id": "uuid",
  "external_user_id": "nextcloud_uid",
  "name": "Demo Farm",
  "bbox": "...",
  "centroid": "..."
}
Enter fullscreen mode Exit fullscreen mode

This approach provides several benefits.

No ID Collisions

UUIDs are globally unique, preventing conflicts between systems.

Clean Synchronization

Updates and raster requests can reference farms using the same external identifier.

/api/v1/farms/{external_farm_id}
Enter fullscreen mode Exit fullscreen mode

Future Integration

If other services appear later (mobile apps, analytics pipelines, satellite processors), they can all reference farms using the same UUID.

This pattern is common in distributed systems and prevents a large class of synchronization bugs.


Identity Translation Between Systems

Another challenge is mapping users between Nextcloud and Django.

Nextcloud users authenticate normally and then communicate with Django using an integration token.

Conceptually:

Nextcloud User
      ↓
Integration Token
      ↓
Django API
      ↓
Farm Sync
Enter fullscreen mode Exit fullscreen mode

The Django service stores farms under a service user while still preserving the original external_user_id from Nextcloud.

This keeps authentication simple while preserving user ownership information.


Measuring the Integration Layer

During development I analyzed the Nextcloud app using cloc to understand the size of the integration layer.

The results showed roughly 11,000 lines of code, split mainly between PHP backend logic and JavaScript UI.

Around this size, architecture decisions begin to matter more than raw implementation.

Systems become complex enough that clear service boundaries become essential.


Lessons Learned

Several practical lessons emerged from this integration work.

1. Avoid bidirectional replication

Two systems writing to the same domain model creates unnecessary complexity.

2. Establish a clear source of truth

In this architecture, Django owns farm data while Nextcloud orchestrates the workflow.

3. Use stable external identifiers

UUIDs dramatically simplify synchronization across systems.

4. Prefer API-first architectures

APIs make it easier to expand systems and integrate future services.

5. Keep compute close to the data

Since Django handles geospatial processing, storing farms there keeps the compute layer efficient.


Final Thoughts

What started as a simple integration between Nextcloud and Django turned into a useful exercise in distributed system design.

Even relatively small systems benefit from clear service boundaries and stable identity strategies.

By combining:

  • an API-first architecture
  • external UUID identifiers
  • and clear ownership of farm data

the system stays simple today while remaining extensible for future services like satellite analytics or mobile farming applications.

Sometimes good architecture isn’t about complexity at all — it’s about clarity of responsibility between systems.

Top comments (0)