Farm Flow is a system for team management and crop planning developed by Matthew Fitzgerald and Fitzgerald Organics. Originally designed as a physical whiteboard, the Farm Flow app is a digital adaptation of the Farm Flow whiteboard system, built in collaboration with Runrig. The primary aim is to make bring the benefits of this methodology to more farms and to put realtime data and visualizations at the fingertips of every member of the team.
If you're interested in using Farm Flow or have questions about its development, feel free to open up a new topic in the Runrig Discussions forum. You can also view the roadmap and kanban we're using for collective project management. More documentation on how to use Farm Flow will be forthcoming as we prepare to launch the first pilot. So stay tuned!
For now, a demo is available at https://farm-flow-board.pages.dev. You will need
to import a data file to get started, which can be downloaded as JSON from the
project's GitHub repository:
crop-2023.json
.
This demo should considered experimental and highly unstable; it will not be
provided with ongoing support.
See CONTRIBUTING.md for full instructions on how to setup the local development environment.
The Farm Flow board has been developed in accordance to several of Runrig's design principles, most notably:
- Identify the core competency of the application that will most immediately add value to the user's existing workflow, without reproducing functionality that already exists in other applications.
- Adapt the application to function as a middleware or "glue service" that can augment existing FOSS applications and services, while still remaining relatively independent and agnostic of the host application's service architecture.
- Maintain data independence and separate the domain model from the service architecture as much as possible. Ensure that data portability is a first-order feature from the very first iteration.
The application uses TypeScript for its versatility in browser, server, and desktop environments. This first pilot is implemented as a single-page application (SPA) that can be deployed to any CDN service, such as those provided by Vercel, Netlify or Cloudflare. Browser-based persistence is provided by IndexedDB and fully offline-first functionality could be introduced easily by dropping in a "zero-config" plugin.
Vue was chosen as the frontend framework, along with Vite for tooling, partly out of preference and familiarity, but also because it provides first-class support for both consuming and generating web components. This affords an easy escape hatch to port Farm Flow to other applications as a component library without the need to manually port the Vue components and reactive state to other frameworks, such as React or Svelte.
The core rendering logic for the board itself has been implemented with the browser's native Canvas API, without the use of Vue components or reactive state whenever possible. This is again to make it easier to port this core rendering logic to other JavaScript frameworks, such as React or Svelte. Because the Canvas API is part of the greater WebGL API, which itself conforms closely to OpenGL, there is also the possibility of porting this logic to other languages that support native desktop SDKs and other environments.
In the interest of promoting data portability and interoperability with other existing services, Farm Flow has loosely adopted the farmOS Data Model to structure its internal state and on-devise database (IndexedDB). Adoption of the farmOS Data Model has been taking hold in more and more projects beyond the farmOS ecosystem itself, particularly with its adoption by members of the OpenTEAM community.
The farmOS Data Model extends Drupal's Entity-Relationship Model, which includes
a two-tiered inheritance model of entities and bundles. Entities are the
higher, functional tier of classification, including assets, logs, users,
etc. Bundles are lower, categorical tier, with land, products, animals,
equipment being examples in the asset family of entities. Accordingly, they
"bundle" together relevant fields such as the manufacturer and serial number
in the case of equipment, or birthdate and sex in the case of animals. All
resources must be classified by both entity and bundle. The combination of
entity and bundled is considered that resource's type, and is represented
as a JSON string by the entity name (singular) followed by two dashes ("--"
)
then the bundle name – for example, "asset--equipment"
, "log--harvest"
, or
"taxonomy_term--season"
.
For the time being, Farm Flow only employs a small subset of the entities and bundles that come with a standard farmOS installation, which are listed below. Non-standard entities, which have not been implemented as farmOS modules but otherwise conform to specifications, are denoted with asterisks (*).
- Assets
- Land (aka, location)
- Plant (a specific planting or succession)
- Logs
- Activity
- Harvest
- Input
- Seeding
- Plans
- Farm Flow Board*
- Taxonomy Terms
- Plant (crop or varietal)
- Standard Operation Procedures*
All of these resources must have at least two fields: an id
string represented
by a UUID (v4), and a type
, which is a JSON string structured in the
"{type}--{bundle}"
format. On their own, the id
and type
fields form a
compete identifier that can be used to indicate a relationship to another
resource.
We're ignoring many of the other fields included in each of these bundles by default, since they're not needed in this application and can be derived from defaults at a later time, if at some point full integration with a farmOS-compliant system becomes desireable. Their equivalent type definitions in TypeScript are provide below.
interface LocationResource {
id: UUID;
type: 'asset--land';
name: string;
}
interface PlantResource {
id: UUID;
type: 'asset--plant';
crop: CropIdentifier | null;
location: LocationIdentifier | null;
}
interface LogResource {
id: UUID;
type: |
'log--activity' |
'log--harvest' |
'log--input' |
'log--seeding';
name: string;
date: Date,
location: LocationIdentifier | null,
operation: OperationIdentifier | null,
plant: PlantIdentifier | null,
notes: string,
}
interface BoardInfo {
id: UUID;
type: 'plan--farm_flow_board';
name: string;
dateRange: [Date, Date],
crops: PlantIdentifier[],
}
interface CropTerm {
id: UUID;
type: 'taxonomy_term--plant';
name: string;
}
interface OperationTerm {
id: UUID;
type: 'taxonomy_term--standard_operating_procedure';
name: string;
}
Current maintainers:
- Jamie Gaehring, Runrig
This project has been sponsored by:
- Matthew Fitzgerald, Fitzgerald Organics
- Mad Agriculture
This work is licensed under a GNU Affero General Public License, Version 3 (AGPLv3).
Farm Flow is a registered trademark of Matthew Fitzgerald.