← all work
client work 2026

joe produce

Complete rebuild of the produce industry's flagship job board. CMS architecture, member portal, automated job approval workflow, internal staff dashboard, and a 75,000-contact newsletter pipeline.

Stack
Webflow Memberstack Make.com Brevo Cloudflare Workers DigitalOcean Google Workspace Google Business Profile

The situation

Joe Produce ran on Drupal 7 for over a decade. By early 2026 the platform was years past Drupal’s end of life, the admin was fragmented across half a dozen modules nobody fully understood anymore, and basic operations like posting a job required staff to walk customers through a clunky multi-step backend flow. Mobile was effectively broken. The member dashboards were desktop-only tables that didn’t render usefully on a phone, and a meaningful chunk of the audience (produce industry hiring managers, recruiters, candidates) was on mobile.

Job approval was entirely manual. Every new posting hit a queue that staff worked through by hand, copying details between systems, sending confirmation emails one at a time, and tracking expiration dates in their heads or on sticky notes. Expired jobs stayed live until someone noticed. Applications landed in inboxes with no central record. Companies couldn’t see who had applied to their own listings without staff intervention.

The recruiting division (Joe Produce Search) had no integration with the ATS the recruiters actually used (CATSone), so candidate data lived in two places that never spoke to each other. SEO had drifted. The job alerts newsletter, the single biggest traffic driver back to the site, was sent from a separate ClickFunnels account against a 75,000-contact list with no live connection to the job data on the site. Every send required someone to manually pull featured jobs, paste them into a template, and hope the formatting held.

What we built

A full rebuild on Webflow for the frontend and CMS, Memberstack for auth and member data, and Make.com as the automation layer between them. A DigitalOcean droplet runs the ops tooling that doesn’t belong in a no-code stack.

CMS architecture. Webflow collections for Jobs, Companies, Applicants, Applications, Job Fields, and Banners, with reference fields wired so a single job carries its company, category, region, and application history without duplication. Status is a CMS option field with stable IDs for Active and Expired so automations can filter reliably without string matching. Page-prefixed CSS classes (cd-* for company dashboard, ad-* for applicant, jd-* for job detail, rc-* for recruiting) keep styles isolated so changes to one section can’t leak into another.

Member portal. Memberstack handles auth, with two member types (company and applicant) gating different dashboards. Application data is stored as JSON on the member record itself (company_apps on the company side, applicant_apps on the applicant side), with short keys to keep payloads small. Dashboards read straight from Memberstack on page load, so a hiring manager sees their applicants instantly without a CMS query. Mobile layouts are real layouts, not desktop tables shoved into a smaller viewport.

Make.com scenarios. The core automation graph runs five scenarios:

  • JP - Post/Edit/Close Job handles the full job lifecycle from the company dashboard, including approval routing and the ping to the Google Indexing API on publish.
  • JP - Job Application fires on every application form submission, creates the Applications CMS item, merges the entry into both the company’s and the applicant’s Memberstack JSON, and sends the notification emails.
  • JP - Add New User and JP - Update Members keep Memberstack and the CMS in sync on signup and profile edits.
  • JP - Janitor runs daily at midnight Pacific, finds every job past its expiration date, flips status to Expired, and sends the expired notice. Two weeks out from expiration it sends a warning email so companies can renew before listings drop off.

Staff dashboard. A custom /staff page that surfaces what staff actually need: pending approvals, expiring jobs, a company filter, daily stats, and one-click triggers for the server-side CMS sync. Built with Finsweet Attributes for filtering and sorting, plus a thin layer of custom JavaScript that calls Make webhooks for the heavier operations. Approving a job is one button click instead of a multi-step backend ritual.

Newsletter rebuild. The full job alerts pipeline moved from ClickFunnels to Brevo, with around 75,000 contacts migrated across. The list was cleaned and re-segmented during the import (the ClickFunnels export was a mess of duplicates, soft bounces, and stale tags accumulated over years). On the technical side, a Cloudflare Worker at /brevofeed exposes a JSON data feed of current jobs that Brevo pulls on every send, so the newsletter always reflects what’s actually live on the site at send time. No more pulling featured jobs by hand, no more pasting them into a template.

The Brevo template is custom HTML with conditional styling per job type (Fresh Picks get the green treatment, Confidential listings get hidden company names and a different layout, resolved via the job-to-company reference at feed time). New CMS fields drive what gets included: an include-in-newsletter switch on Jobs, a matching switch on the Banners collection, and a newsletter-banner image field sized for the template slot. The Confidential toggle lives on the Companies collection so a single company flag cascades to every job they post.

The cutover ran on a seven-day deliverability ramp so Brevo’s sending reputation built cleanly from a cold IP rather than dumping 75,000 sends on day one and getting flagged. Transactional email (application notifications, expiration warnings, password resets) stays on Gmail SMTP through the droplet, separate from the marketing list, so deliverability issues on one side never affect the other.

Ops layer. The droplet runs jp-tools.mjs (an interactive menu for archiving, indexing, CMS sync, backups, health checks, CSV exports, single-job test mode) and jp-api.mjs (a small token-authed HTTP server on port 3847 that lets Make trigger server-side jobs without exposing credentials). Cron handles the daily archiver, Google indexing, full Webflow plus Memberstack backups with seven-day retention, a morning health check with email alerts, and CMS sync every ten minutes during business hours.

What changed

Job approval went from a manual queue worked by hand to one-click approval from the staff dashboard. Expired jobs now disappear automatically the night they expire, instead of sitting live until someone noticed. Companies and applicants both have functional mobile dashboards. Application data writes to four places (Webflow CMS, the company’s Memberstack JSON, the applicant’s Memberstack JSON, and notification emails) in one webhook trigger, with no staff involvement.

The newsletter went from a manual weekly assembly job to a scheduled send that builds itself from live CMS data. Staff toggle the include-in-newsletter switch on the jobs they want featured, pick the banner, and the rest is automatic. Confidential listings handle themselves through the company-level flag. The 75,000-contact migration landed cleanly on the new sender reputation, and the list is now segmentable in ways the old ClickFunnels setup never allowed.

The daily archiver and the warning email pipeline alone replaced what used to be hours of manual list-checking per week. Backups run unattended every night with retention. The Google Indexing API integration means new jobs are submitted to Google within hours of posting rather than waiting on the next crawl. Staff can pull a CSV of any slice of the data in seconds instead of asking a developer.

The platform now runs on infrastructure the team can reason about. When something breaks (and things break), the logs are in one place, the scenarios are named, and the fix is usually a single deploy or a Make filter rather than a Drupal module dig.

Stack details

Webflow over a headless CMS plus framework rebuild because the team needed to edit content directly without a developer in the loop, and the design system was going to live in the Webflow Designer either way. Memberstack over rolling auth on top of the CMS because gated content, member metadata, and the JSON field for application data were already solved problems there. Make.com over writing a queue worker on the droplet because most of the automations are linear webhook pipelines that benefit from being inspectable in a UI when something fails at 2am.

Brevo over Mailchimp or Klaviyo for the newsletter side because the pricing on a 75,000-contact list was sustainable, the data feed feature meant the live-job pull could be built without a custom integration, and the deliverability infrastructure was solid enough to handle a cold-start migration off ClickFunnels. The droplet exists for the things that genuinely don’t belong in a no-code tool: cron, file I/O, the Google Indexing API service account, the Cloudflare Worker development loop, and bulk operations that exceed Make’s payload limits.