Privacy notice
What GardenOps knows about you.
Draft · Last updated 30 September 2026 · Applies to gardenops.co.za
This is a draft, and it is not legal advice.
It was written by reading the GardenOps database and source code, so that everything on this page is true of the software as it stands today. It has not been reviewed by a lawyer. Where the honest answer is “this is not settled yet”, this page says so instead of filling the gap with a reassuring sentence.
GardenOps is in private testing. The South African law that applies is the Protection of Personal Information Act (POPIA). This notice is written towards POPIA. It does not claim that GardenOps complies with it.
Two different people are described here
GardenOps has one kind of user and one kind of person it holds records about, and they are not the same person.
The homeowner signs up, signs in, and adds everything else. They chose to use GardenOps.
The gardener does not have an account.There is no gardener login, no gardener screen, and nothing a gardener can tick. A homeowner typed the gardener’s name and mobile number into GardenOps, and from that point GardenOps sends the gardener messages on WhatsApp and keeps what they send back.
This asymmetry is the most important fact on this page. A gardener never agreed to anything inside GardenOps, because there is nowhere inside GardenOps for them to agree. What GardenOps stores instead is the homeowner’s own statement that they spoke to the gardener away from the product and that the gardener agreed — three columns on the gardener’s record: when the homeowner recorded it, the exact words they agreed to, and that the source was the homeowner rather than the gardener.
Those columns are named “recorded” rather than “consented” throughout the code, deliberately, so that they are never later read as evidence of something they did not capture.gardeners.consent_recorded_at, consent_wording, consent_source · src/domain/gardener-consent.ts
The very first message a gardener receives about GardenOps is not sent by GardenOps at all. It leaves the homeowner’s own phone, in the homeowner’s own WhatsApp, using words the product composed for them to send.src/domain/gardener-invitation.ts
What GardenOps stores about a homeowner
- Your email address and password
- Held by Supabase Auth, which runs the sign-in. GardenOps never sees your password.auth.users · src/validation/auth.ts
- Your name, phone number, time zone and photo
- First and last name and time zone are required. A phone number and a profile photo are optional and only stored if you add them.profiles.first_name, last_name, phone_number, preferred_timezone, photo_path
- Your properties, including their street addresses
- Address line 1 and 2, suburb, city, province, postal code and country, plus a time zone, an optional photo, and — when you place a property on the map — its latitude and longitude and a geofence radius in metres. The coordinates are what later decides whether a gardener was at the property.properties.address_line_1 … latitude, longitude, geofence_radius_metres
- Everything you plan
- Task templates, schedules, equipment, break dates, and which gardener is allocated to which property.
- A record of the changes you make
- Each change writes one entry saying what you changed, what it was before, and when. This log is append-only in the database itself: there is no update policy and no delete policy on the table, so it cannot be quietly edited from inside the product, by you or by anyone else.change_log_entries · supabase/migrations/20260827120000_change_log.sql
- What you agreed to be emailed about
- Two separate choices — the founder newsletter, and product updates — each stored as the moment you opted in, or nothing at all if you did not. The exact wording you were shown is copied onto your record at the time, so changing that wording later cannot rewrite what you agreed to. Both are unticked until you tick them, and you can change either at any time in Settings. Email about your account is not one of these choices. Your invitation, a password reset, or a message telling you something has gone wrong with your gardener’s messages is sent because you have an account and needs no permission — asking for permission we would override would make the asking dishonest.profiles.newsletter_opted_in_at, product_updates_opted_in_at, marketing_consent_wording, marketing_consent_recorded_at · src/domain/marketing-consent.ts
What GardenOps stores about a gardener
- Name, mobile number, preferred language and start date
- All typed in by the homeowner. The mobile number is the address every message is sent to.gardeners.full_name, mobile_number, preferred_language, start_date
- A free-text note, and an optional photograph
- The homeowner may write up to 2 000 characters of notes about a gardener, and may upload a photograph of them. Photographs are kept in a private storage bucket and are never served from a public address. Every uploaded photograph is re-encoded in the browser before it is sent, which strips its EXIF metadata — including the GPS coordinates a phone camera writes into a photo taken at a property.gardeners.notes, photo_path · src/lib/media/normalise-image.ts · supabase/migrations/20260814120000_entity_photos.sql
- The messages GardenOps sends
- The full text of every message, the number it was sent to, when it was queued and sent, and whether it failed. The messages name the gardener and the property, and list the work planned for the day or the week. A second copy is kept alongside the gardener’s replies, so that the conversation can be read in order as a conversation.delivery_messages.body, recipient, payload, sent_at · gardener_outbound_messages.body, recipient, kind, queued_at, sent_at · src/domain/delivery-composition.ts
- The messages a gardener sends back
- The text of every reply, the sender’s number exactly as WhatsApp supplied it, when it arrived, and whether the homeowner has read it. If a gardener sends a photo, a voice note or any other attachment, GardenOps never downloads or stores the file itself, but it does keep a record of it: a reference number that points at the file on WhatsApp, the kind of file it is, its filename, any caption the gardener typed with it, and whether it was a voice note. The file itself stays on WhatsApp’s systems, where it expires after about thirty days — after which the reference GardenOps holds no longer retrieves anything. If a gardener sends a WhatsApp location pin, the stored message is its latitude and longitude as text.gardener_inbound_messages.body, wa_id, message_kind, media_id, media_mime_type, media_filename, media_caption, media_voice · src/domain/delivery-inbound.ts describeInboundMedia
- Attendance, shifts and no-shows
- When a shift started and ended, whether the gardener left early and the reason they gave, when each task was started and finished, whether work was recorded as done, partly done or not done and the reason given when it was not, and any day recorded as a no-show with its reason.gardener_shift_starts, gardener_task_events, task_occurrence_attendance, task_occurrence_outcomes, gardener_no_shows
- Messages that could not be matched to anybody
- If a number messages the GardenOps WhatsApp line and matches no gardener on any account, the message and the number are still stored. Because ownership is inherited from the gardener record, a message that matches nobody belongs to no account and is visible to no homeowner.gardener_inbound_messages.resolution = ‘unknown’ · supabase/migrations/20260821090000_gardener_inbound_messages.sql
Location
This deserves its own section, because it is the most sensitive thing GardenOps holds and because the answer is not tidy.
A gardener starts and ends a shift by sending a location pin over WhatsApp. GardenOps stores the latitude and longitude of that pin, how far it was from the property in metres, and whether that put the gardener inside the property’s geofence — separately for the start of the shift and the end of it.gardener_shift_starts.start_latitude, start_longitude, start_distance_metres, start_within_geofence, and the four matching end_ columns
A pin that the geofence refuses is also kept. Every refused attempt is stored with its coordinates, its distance, and why it was refused — too far away, no location supplied, or the property has no pin of its own. Repeated attempts are kept as repeated rows on purpose.gardener_geofence_attempts
GardenOps does not receive an accuracy figure with a WhatsApp location, so although the database has columns for it, nothing is ever written into them. GardenOps does not track a gardener continuously or in the background: it only ever sees a position at the moment the gardener chooses to send a pin.src/db/gardener-geofence-attempts.ts, src/db/gardener-shift-starts.ts — accuracy is written as null
Open question: what the gardener was actually told
The wording a homeowner agrees to when they record a gardener’s consent says nothing about location. That is deliberate — it was written before the location features existed, and a placeholder that claimed to cover location would have been exactly the kind of false record it exists to avoid.
So today, the recorded consent covers being messaged and having replies kept. It does not cover position data. That gap is real and it has not been closed yet. Until it is, a homeowner using GardenOps should tell their gardener, in person, that sending a pin to start a shift records where they were.src/domain/gardener-consent.ts — “It deliberately says nothing about location.”
Figures about a gardener’s work
GardenOps turns the records above into four figures, and shows them to the homeowner on their dashboard and on each property’s own page:
- how often gardeners arrived on time,
- how often they clocked out on time,
- how many of the scheduled tasks were finished,
- how many tasks were finished inside the time allowed for them.
“On time” means no more than fifteen minutes late, measured against the hours the homeowner recorded for that gardener at that property. Arriving early is never counted as late, and a day with no recorded hours is left out entirely because there is nothing to be late for. Each figure covers the last 30 days, ending yesterday, and no percentage is shown until there are at least ten things to count — below ten the screen shows the counts instead. Shifts GardenOps closed by itself, because nobody clocked out, are left out of the clock-out figure, and the screen says so where it happens.src/domain/dashboard-metrics.ts — METRICS_WINDOW_DAYS, METRICS_FLOOR, ON_TIME_MINUTES
These figures are worked out each time the page is opened. No table holds them, so deleting a gardener’s records deletes the figures with them.src/domain/dashboard-metrics.ts · verified absent: any table storing a computed figure
Each figure is a rate for one property, or for the whole account — it is not a score beside a gardener’s name, and GardenOps does not rank gardeners against each other. At a property worked by one gardener it is nonetheless a figure about that person, and it should be read that way.
GardenOps does not act on these figures. Nothing is sent to a gardener because of them, and nothing in the product changes by itself because of them. What a homeowner does with them is up to the homeowner.
A gardener cannot see their own figures, because gardeners have no login. If you are a gardener and think a figure is wrong — a clock-in that never registered, say — speak to the homeowner, or write to the address at the bottom of this page and ask what is held about you.
Who else this data reaches
GardenOps does not sell anyone’s data and does not share it for advertising. It reaches these companies because the product cannot work without them.
- Meta (WhatsApp Business Platform)
- Every message to and from a gardener travels through Meta. Meta therefore receives the gardener’s mobile number and the full text of each message, including the gardener’s name and the property name that GardenOps writes into them. What Meta does with that is governed by Meta’s own terms and privacy policy, not by this one.src/integrations/meta-provider.ts · src/integrations/meta-webhook.ts
- Supabase
- The database, the sign-in system and the private photo storage. The GardenOps production database is hosted in Ireland (eu-west-1), which means personal information about South African homeowners and gardeners is stored outside South Africa.docs/ARCHITECT_HANDOFF.md — production project region, recorded 21 August 2026
- Vercel
- Runs the website and the server code, and therefore handles every request. Server logs are written as structured lines that Vercel keeps. Where a gardener’s number has to appear in a log, only the last four digits are written.src/lib/logger.ts · redactNumber in src/domain/delivery-inbound.ts
- OpenStreetMap Foundation
- Map tiles are fetched directly by a homeowner’s browser from tile.openstreetmap.org, so that service sees the browser’s IP address and which part of the map is being looked at. When a homeowner clicks “find on map”, the address they typed is sent from the GardenOps server to nominatim.openstreetmap.org to be turned into coordinates.src/lib/maps/provider-config.ts · src/app/api/geocode/route.ts
- Google Forms
- The early-access and pilot-feedback links on the GardenOps site open Google Forms. Anything typed into those forms goes to Google, not into GardenOps.src/lib/operational-links.ts
- Resend, on Amazon SES
- Account email — your invitation, a password reset, a note that your password or email address changed — is sent by Supabase through Resend, which delivers over Amazon SES. It arrives from no-reply@updates.gardenops.co.za. Resend therefore handles your email address and the contents of those messages. No gardener ever receives email — everything sent to a gardener goes over WhatsApp.Supabase project SMTP settings · supabase/templates/
- Odoo (Odoo SA)
- PracWorth keeps its customer records and sends its email from Odoo. When you accept a GardenOps invitation, your name, email address, the dates of your invitation, your answer about whether you manage your own property or gardens for clients, and your email choices are copied into it, so that PracWorth can help you set the product up and, if you asked for them, send you product updates. Nothing about a gardener or a property is sent.
Odoo stores this on Google Cloud servers in Mumbai, India, and keeps backups in France, the Netherlands and Canada. The region is not something a customer can choose. That puts the information outside South Africa, and what makes that lawful is the data processing agreement in Odoo’s subscription terms, which binds Odoo to protect it — not Indian law, which is still being phased in and does not yet carry it.Odoo hosting confirmed 29 September 2026 · India’s DPDP rollout completes 13 May 2027
Cookies
GardenOps sets cookies for one purpose: keeping a signed-in homeowner signed in. There is no analytics, no tracking pixel and no advertising code anywhere in the product — the site loads no third-party script at all.src/lib/supabase/server.ts · verified absent: analytics, PostHog, gtag, Vercel Analytics
How long it is kept
Everything above is kept indefinitely. That is not a hedge, it is the accurate description: nothing in GardenOps deletes old data. There is no retention period, no scheduled purge, and no job anywhere in the product that removes messages, shifts, location pins or attendance records once they are a certain age.
The change log is kept permanently by design — a log that expires cannot answer “what did this used to say?” weeks later, which is the only reason it exists.docs/briefs/CHANGE_LOG_DESIGN.md — “Retention is permanent.”
This includes the refused clock-ins. Every time a gardener’s pin put them somewhere the geofence would not accept, that fact and those coordinates stay on file indefinitely. GardenOps’ own internal notes record that nobody has yet decided what that record is for or how long it should live.docs/briefs/ARCHITECT_BRIEF_LEGAL_AND_COMPLIANCE.md §3.4 — “the decision that was parked”
What is copied into PracWorth’s customer records is kept for as long as you have a GardenOps account, and afterwards for as long as PracWorth needs it to answer questions about that account. You can ask for it to be deleted at admin@pracworth.com.
Data is removed when somebody removes it, and in no other way. How that works is the next section.
Getting your data deleted
You should know what the product can do for itself today, and what still has to be asked for.
What the product does on its own
A homeowner can mark a gardener as inactive and can archive a property. Neither of these deletes anything. An inactive gardener stops receiving messages; the record, the number, the notes, the message history and the location pins all remain. An archived property is hidden from the working views and its address remains stored.src/db/gardeners.ts sets is_active · src/db/properties.ts sets archived_at
Archiving is the step before deleting, and deleting is offered only after it. Once a gardener is archived, the homeowner can delete them from that gardener’s own page, and the same applies to an archived property. Deleting a gardener removes their record and, in the same step, their messages, their replies, their shifts and location pins, their refused clock-ins, their attendance, the task records they sent in, their no-shows and their consent record. The homeowner is shown the real counts before they confirm. Deleting a property removes its address and coordinates and everything recorded there; the gardeners who worked it belong to the account and stay.src/components/gardeners/delete-gardener-button.tsx · src/components/properties/delete-property-button.tsx · src/domain/record-deletion.ts · supabase/migrations/20260901100000_delete_after_archive.sql
The change log keeps one line saying the gardener was deleted, with their name, and keeps the entries about a deleted property under that property’s name. A log that forgot what happened would not be doing its job, so this is on purpose and it is the one thing a delete leaves behind.supabase/migrations/20260903100000_change_log_whose_work_changed.sql · supabase/migrations/20260901093000_change_log_survives_property_delete.sql
A homeowner can remove a photograph, and that does delete the image file from storage. There is no “close my account” button.src/lib/media/storage.ts · verified absent: any delete of a profile or an account from inside the product
How to actually have data deleted
Anything you cannot delete yourself — and any request from a gardener, who has no login to delete anything with — is done by hand, by the person who runs GardenOps. Ask, and say which of these you want:
- A gardener’s record. Deleting the gardener row also deletes, automatically and in the same step, every message sent to them, every reply they sent, every shift and location pin, every refused geofence attempt, their attendance records and their no-show records. The database enforces that itself, so nothing survives because somebody forgot a table.
- A property. Deleting a property removes its address and coordinates along with the schedules, shifts, geofence attempts and attendance attached to it.
- A whole homeowner account. Deleting the account cascades through the profile, the properties, the gardeners and everything reached from them, including the change log.
Two things this cannot reach. Messages that already travelled through WhatsApp still exist on Meta’s systems and on the phones they were delivered to; deleting a GardenOps record does not reach either. And server logs held by Vercel age out on Vercel’s own schedule, not on request.
If you are a gardener
You can ask for your data to be deleted even though you have no account and never signed up. You do not need to go through the homeowner who added you, and you do not need to give a reason. Use the contact route below, and give the mobile number that receives the GardenOps messages so the right record can be found. Deleting your record stops the messages.
Contacting GardenOps about your data
Write to admin@pracworth.com. That address reaches the person who runs GardenOps. Ask what is held about you, ask for it to be corrected, or ask for it to be deleted — you do not need an account and you do not need to give a reason. If you are a gardener, include the mobile number that receives the GardenOps messages, so the right record can be found.
Under POPIA you can ask what personal information is held about you, ask for it to be corrected, ask for it to be deleted, and object to it being used. If you are not satisfied with the response you get, you can complain to the Information Regulator of South Africa.
- Who is responsible for this
- GardenOps is a product of PracWorth (Pty) Ltd, registration number 2026/764595/07, which is the responsible party for the personal information described here.
Until 23 September 2026 GardenOps was run by Jason de Kock personally. The company now holds that role. Nothing about the information itself changed when it did — the same data, held for the same reasons, by a company instead of a person. - The Information Officer
- Under POPIA the head of a private body is its Information Officer. For PracWorth that is Jason de Kock, and that is who a request reaches.
RedBerry Farm, Geelhoutboom Road, George, Western Cape, 6531, South Africa
admin@pracworth.com
Registration with the Information Regulator is outstanding, and this notice will say so until it is done. - The Information Regulator
- JD House, 27 Stiemens Street, Braamfontein, Johannesburg, 2001 — inforeg@inforegulator.org.za. You can complain to them directly; you do not have to come here first.
- Asking for a record rather than your own data
- The PAIA manual sets out what records GardenOps holds and how to request one. The terms of use cover what the product does and does not promise.
One more thing worth saying plainly: POPIA distinguishes the party who decides what happens to personal information from the party who merely processes it on their behalf. Whether that first party is GardenOps or the homeowner has not been settled here yet. The homeowner chooses the gardener and the work; GardenOps stores the records and sends the messages; and the first message to a gardener goes out from the homeowner’s own phone. Until that is settled, a request made to GardenOps will be dealt with rather than handed back to the homeowner.docs/briefs/ARCHITECT_BRIEF_LEGAL_AND_COMPLIANCE.md §3.1 — referred to a South African attorney, unresolved
Changes to this notice
The date at the top changes whenever the words do. Because GardenOps is still being built, expect this page to change — particularly the open questions above, which are the parts most likely to be answered next.