Skip Navigation

Maryland's Agricultural Reporting Tool

ESRGC · November 2023 - Present

A reporting and farm-management application that helps Maryland agricultural producers organize crop, nutrient, harvest, and yield data.

Tech Used
ReactNext.jstRPCbetter-authArcGIS Web SDKTailwindCSSDrizzlePostgreSQLDockerDigitalOcean
Screenshot of MART

Background

The Maryland Agriculture Reporting Tool (MART) was developed by the ESRGC to make annual agricultural reporting easier for producers across Maryland. The project brought together the University of Maryland Extension Office, Maryland's regional councils, and the Rural Maryland Council through the Rural Maryland Prosperity Investment Fund.

Before MART, producers preparing an Annual Implementation Report (AIR) had to manage their records independently, often copying formulas between spreadsheets and manually organizing crop and nutrient data. MART gives that information a consistent home and presents it in a table structured like the AIR, reducing the work required to prepare the final report.

How it evolved

The first version focused on AIR preparation. It introduced authentication and site roles, farm profiles with member and moderator permissions, invitations for collaborators, and a reporting workspace for crop and nutrient records. Users could review the same information in both data-table and AIR formats, then export their crop data as CSV files. Because the underlying records connect farms, fields, crops, fertilizers, and nutrients, the forms also needed to support deeply related data and efficient bulk entry.

The application later expanded beyond nutrient reporting to include harvest and yield tracking. Producers can enter grain-elevator ticket information and use it to monitor yield alongside their crop records. This phase extended the same nested and bulk-entry patterns to another interconnected part of farm operations.

Before launch, I added administration tools and dashboards for crop and harvest data at both the farm and operation levels. Since one user may manage several farms, the dashboards support viewing a single farm or comparing information across multiple farms. MART grew from a focused reporting aid into a broader workspace for organizing the records behind those reports.

Technical approach

MART has used Next.js, tRPC, Tailwind CSS, shadcn/ui, Drizzle ORM, and PostgreSQL from the beginning. Together, they provide a type-safe path from the database through the API to the interface, which is especially valuable for a system with many relationships among users, farms, fields, crops, fertilizers, nutrients, harvest records, and tickets.

The application's forms are a central part of that architecture. They need to support nested relationships and bulk creation without making already detailed agricultural records harder to enter. I initially used React Hook Form, which handled the highly dynamic workflows well. After TanStack Form reached a stable release, I migrated to it because its API addressed several smaller pain points I had encountered. The migration went smoothly, and TanStack Form has since become my preferred form library.

I made a similar update to authentication. Auth.js was a practical initial choice because I already knew it and it met the project's early needs. As Better Auth matured and provided a clear migration path, I replaced Auth.js with it. Better Auth's admin plugin also allowed me to remove several custom administration functions, reducing application-specific code while expanding the available account-management capabilities.

Challenges and lessons

The largest challenge was adapting to requirements that continued to change while features were already in development. New reporting, harvest, administration, and dashboard needs affected both the interface and an interconnected data model, so seemingly isolated requests could influence several workflows at once.

The project reinforced the importance of building around stable domain relationships while keeping individual features flexible. The original stack provided enough continuity for the product to grow, while targeted migrations let me improve forms and authentication without rewriting the application around each new library. That balance helped me respond to evolving partner priorities while keeping the system maintainable.

MART also strengthened my judgment about when replacing a dependency is worthwhile. Neither React Hook Form nor Auth.js had failed; each migration was driven by a concrete improvement in the project's day-to-day development or maintenance. Evaluating those changes against their actual benefits, rather than adopting new tools for their own sake, allowed the application to evolve without unnecessary disruption.