What's changed in Upkeep, newest first. Major releases bump the first number; substantial features bump the second; polish and small fixes bump the third. The dates are when the change went live on upkeep.softwerks.pro.
Livestock + vet + medications with withdrawal periodsv3.132026-05-24feature
- New Animals screen in the user menu — visible to any signed-in user. Helpers see animals they created or are assigned to; admins see all. Filterable by status (active herd / sold / deceased / culled / butchered) and species. Cards show breed · age · current location · vet count · med count, with red withdrawal chips for any animal whose meat or milk clock is still running.
- Animal detail screen — open any card to see the full record. A red withdrawal banner at the top calls out exactly which drugs are restricting what (meat / milk) and when each clears. Vet visits and medications are listed below with quick-action buttons to log more.
- Animals model: species (13 options + 'other'), breed, name, ear tag (NOT unique — tags get reused after exit), sex, DOB, sire_id + dam_id (nullable pedigree links), location, status, intake date, exit date + reason, assignee. Setting status to anything other than 'active' reveals the exit-date + exit-reason fields in the modal.
- Vet records: per-animal log with visit date, vet name (free text) + optional link to a vendor in your Keys list, reason, diagnosis, treatment, cost, notes, attended-by. Cascading delete on the parent animal.
- Medications (the legal-teeth piece for livestock): drug name, active ingredient, dose, route (oral / IM / SQ / IV / topical / intramammary / intranasal / intrauterine), administered-at + administered-by, optional link to a vet visit, and the two withdrawal periods —
withdrawal_meat_days and withdrawal_milk_hours. meat_clear_at + milk_clear_at are precomputed at insert time the same way REI/PHI are in v3.12, so the cron and UI both compare against flat timestamps.
- Push when meat / milk withdrawal clears.
cron/check_clears.php gains two new sweeps alongside the REI/PHI ones. Same idempotent pattern: rows whose clear-at just elapsed and meat_notified_at / milk_notified_at are NULL get pushed to admins + the administering user + the animal's assignee, then the column gets stamped so the same event never re-fires.
- Hawkeye knows the herd. The live property snapshot now includes an Animals section (active only — sold/deceased/butchered/culled go to history) with species, name/tag, age, location, and any active withdrawal flag — plus an Active Withdrawals section listing every meat/milk clock still in effect with drug, active ingredient, administered-at, and exact clear time. So "which goats are clear for slaughter" / "any animals on antibiotics right now" / "when can we drink Daisy's milk again" all work.
- Schema v28:
animals, vet_records, medications with FKs back to locations + users + vendors + each other. Indexes on the clear-at columns so the cron sweep stays cheap as the table grows. sire_id/dam_id are nullable self-references so we can record pedigree when we know it (v3.14 breeding work will populate them automatically from birth events).
- New endpoints:
GET/POST /api/animals, GET/PUT/DELETE /api/animals/{id}, nested /api/animals/{id}/vet-records + /api/animals/{id}/medications, and a herd-wide GET /api/medications with ?active=1 filter for the dashboard. All gated; helpers can write on animals they created or are assigned to, admins on anything.
- Coming next: v3.14 closes the lifecycle with breeding + pedigree (dam/sire/bred-at/expected-due, birth event auto-creates a new animal with sire_id + dam_id pre-populated).
Plantings + applications with REI/PHI trackingv3.122026-05-24feature
- New Plantings screen in the user menu — visible to any signed-in user. Helpers see plantings they created or are assigned to; admins see all. Status filter chip + a card per planting with crop · variety · location · age · harvest count · application count, with quick-action buttons for logging a harvest or an application.
- Plantings model: crop, variety, source, planted date, expected harvest date, status (planted / growing / harvesting / finished / failed), assignee, location. Logging the first harvest auto-bumps status from
planted/growing → harvesting.
- Harvests: per-planting log with date, quantity, unit (lb / pint / bunch / each / etc. — datalist autocomplete), who, notes. Cascading delete on the parent planting.
- Applications (the "legal teeth" piece): spray / fertilizer / foliar / anything you put on a crop or location. Captures EPA reg #, active ingredient, rate, target pest, applied-at + applied-by, REI hours, PHI days, and notes.
rei_clear_at + phi_clear_at are pre-computed at insert time so the cron + UI both have a flat timestamp to scan.
- Push when REI / PHI clears.
cron/check_clears.php runs every 15 minutes, finds applications whose clear-at just elapsed, and pushes the location's admins + the original applier + the planting's assignee. Notifications stamp rei_notified_at / phi_notified_at so the same row never re-fires.
- Active-restrictions visibility on the Location card.
GET /api/locations now returns active_rei, active_phi, latest_rei_clear, latest_phi_clear, and a count of active plantings — so a location with a live restriction can show a red chip with the exact clear time.
- Hawkeye knows the garden. The live property snapshot now includes a Plantings section (active only — finished/failed go to the log) and an Active Restrictions section listing every REI/PHI still in effect with product, EPA reg #, applied-at, and the exact clear timestamp. So "what can I harvest from bed 3" / "is the south plot safe to walk through" / "what got sprayed last week" all work.
- Schema v27:
plantings, harvests, applications with FKs back to locations + users + each other. Indexes on the clear-at columns so the cron sweep stays cheap as the table grows.
- New endpoints:
GET/POST /api/plantings + GET/PUT/DELETE /api/plantings/{id}, nested /api/plantings/{id}/harvests, and GET/POST/PUT/DELETE /api/applications. All gated; helpers can write on their own plantings, admins can write on anything.
- Coming next: v3.13 adds livestock + vet visits + medications with withdrawal periods (meat / milk discard timers, same cron pattern). v3.14 closes the lifecycle with breeding + pedigree.
Locations — first-class places on the propertyv3.112026-05-24feature
- New "Locations" admin screen in the user menu — manage the named places on the property (Pasture A, Workshop, Chicken Coop, Bed 3, North Field). Each location has a kind (pasture / field / bed / coop / pen / hive / barn / structure / zone / other) that drives the icon shown on cards and selectors.
- Equipment and tasks now carry a location. The Upkeep modal and both the Create-task form and the Edit-task modal have a Location dropdown — optional, with a "— No location —" default. Equipment cards show their location in the subtitle and the detail expander; task rows show the location glyph + name next to the due date.
- Hawkeye knows where things live. The chat's live property snapshot now includes a Locations section listing each place and how many upkeeps/tasks live there, and the Upkeeps section annotates each item with its location. So "where's the chainsaw" / "what's at the workshop" / "what's in Pasture A" all work.
- Safe deletes. Trying to delete a location that's still in use returns a friendly 409 listing what's blocking it (e.g. "In use by 4 upkeeps, 2 tasks — reassign or remove those first") — same pattern as the existing category delete guard.
- Schema v26:
locations(id, name, kind, parent_id, lat, lng, notes, created_by) with kind enum, unique-name check, and FK from equipment.location_id and items.location_id (both nullable, ON DELETE RESTRICT). parent_id and lat/lng are reserved for future hierarchy + weather/geofence work and aren't surfaced in the v3.11 UI.
- New endpoints:
GET /api/locations (helper-read), POST /api/admin/locations, PUT /api/admin/locations/{id}, DELETE /api/admin/locations/{id}. equipment and items create/update accept location_id; their GET responses now include location_name + location_kind.
Hour trackers are one-time milestones — Done means Donev3.10.12026-05-22fix
- The bug: hour-based trackers ("25-Hour Service", "50-Hour Service", "200-Hour Service" etc.) are one-time milestone services the manufacturer wants you to perform at specific hour marks on the machine — not recurring intervals. The old code was treating them as recurring (every N hours), so logging the 25-Hour Service on the UTV at 176 actual hours computed "next due at 50" and stayed flagged overdue forever. There was no way to mark a milestone done.
- The fix: hour trackers are now treated as one-and-done. Once at least one service log exists for them, the tracker is marked complete — no next-due, no overdue badge, no countdown. A green "Done at 27hr · 2026-05-22" badge takes the place of the Overdue chip. Delete the log and the tracker returns to its pre-completion state.
- Date-based trackers (Annual, Monthly, Semi-Annual, Daily Watering, etc.) are unchanged — those genuinely recur and the existing logic handles them.
- Hybrid trackers (e.g. "200-Hour / Annual Service" on the UTV) follow whatever
interval_type is set. The 200-hour milestone fires once at 200 hr; if you want an annual recurrence on top of that, create a second date-based tracker.
- Backend shape: new
is_complete boolean on every tracker response. next_due_hours and hours_remaining are now null for completed milestones. Same three call sites updated: tracker list, tracker detail, admin user-detail. Stopped writing due_hours after each log (it was meaningless under the new semantics).
- "Latest log" query fixed. Previously ordered by
created_at DESC (when you typed it), so a backdated entry typed last could override an older entry that actually happened more recently on the machine. Now ordered by hours_at_service DESC — the actual machine reading.
SMS ripped out — push-only notificationsv3.102026-05-22major
- Why: our A2P 10DLC campaign was rejected a second time (Twilio error 30912 — reviewer flagged the use case as P2P). Push notifications have been carrying the entire notification load since v3.7, so we're done fighting TCR.
- Backend:
send_sms() removed from core.php (tombstone comment in place). All call sites updated: task-assign, tracker-task-add, Project Ranker assign/reassign no longer pass sms_fallback/sms_body to notify_user(). notify_user() itself simplified to push-only.
- Phone verification gone.
POST /api/auth/phone/request and POST /api/auth/phone/verify routes deleted. Phone numbers in user profiles are now plain contact info — save directly in Profile, no SMS round-trip. The users.phone_pending, phone_code, and phone_code_expires columns are left in place but no longer written or read.
- Invite SMS gone. The admin Invite modal no longer has a "Send invite via SMS" checkbox;
admin_create_invite() no longer accepts send_sms; the result view drops the "SMS sent / failed" line. Invites are link-share only.
- Public invite-request form at
/optin.html rewritten from "SMS Opt-In Disclosure" to "Request an invitation." No more SMS consent checkbox; no more carrier compliance prose. create_invite_request() no longer reads wants_sms or writes consent_text. The admin invite-requests dashboard drops the blue/gray "wants SMS" badges.
- Profile modal drops the phone-verify view and the "Changes are confirmed via SMS code" helper text. New helper text clarifies: "Contact info only. Upkeep doesn't send text messages — task notifications come through the app."
- User menu drops the "SMS opt-in" link.
- Privacy + Terms rewritten — all references to Twilio, SMS, STOP/HELP keywords, and message frequency removed. Section 4 of Privacy is now "Push notifications" with a brief explanation of Web Push routing; Terms section 3 is now "Notifications."
- Twilio constants in
config.php are left dormant — operator can delete at any time without affecting anything.
Project Ranker: admin-only top-10 priority list with backlogv3.92026-05-21feature
- New admin-only "Project Ranker" screen from the user menu — a top-10 list of priority tasks. Each card shows a rank badge, the task description, an inline assignee dropdown, an inline priority dropdown, and a delete button. Cards ranked #1-3 are highlighted red so the must-do items pop visually.
- Minimal add form pinned to the top: description + assignee + priority (1-10) + Add button. One-tap entry, no modal.
- Swap-on-collision when editing priority. Move task A to slot 3 and task B already lives at 3 → they swap. Predictable, no surprise reordering of the whole list.
- Bump-to-backlog when creating into an occupied slot. Create a new task at #5 and the current #5 gets bumped to the bottom of the backlog (max(priority)+1). The top-10 stays at 10.
- Backlog pool for everything ranked 11+. Hidden by default; the "Show backlog (N)" button at the bottom toggles it in. Backlog cards render dimmed so the top-10 stays visually dominant. Promote one back into the top-10 anytime by changing its priority dropdown.
- Push notifications fire to the assignee on initial assignment and on reassignment (silent on description / priority edits to avoid notification spam). Falls back to SMS if the assignee has no registered push devices.
- Schema v25:
order_tasks(id, description, assigned_to, priority, created_by, created_at, updated_at) with FKs to users (assigned_to → set null on user delete; created_by → cascade).
- New routes:
GET /api/order (with ?include_backlog=1), POST /api/order, PUT /api/order/{id}, DELETE /api/order/{id}. All admin-gated.
Expenses: receipt scan + searchable history with YTDv3.82026-05-12feature
- New Expenses screen in the user menu — visible to any signed-in user. Helpers see/edit only their own; admins see everything.
- Receipt photo scan via Claude vision. Pick a photo, the app uploads it, Claude reads vendor / total / date / a one-line "what was bought" summary, and the confirm form is pre-filled. You can edit anything before saving.
- Filter chips for Day / Week / Month / Year / All. Each filter shows a window total above the list (count + sum). Default view is "This month."
- Free-text search across vendor and notes, debounced 300ms.
- Sticky YTD bar pinned to the bottom of the Expenses screen — stays put while you filter or search above. Green dollar figure tells you the year-to-date total at a glance.
- Categories reused from the existing categories table — you can tag a receipt with the same colors used on tasks and trackers (HVAC, Plumbing, etc.).
- Schema v24:
expenses(id, user_id, expense_date, vendor, amount, category_id, notes, photo_filename, ai_extracted, created_at, updated_at) with indexes on date / user / category and FKs to users (cascade) + categories (set null).
- New endpoints:
GET /api/expenses, GET /api/expenses/totals, POST /api/expenses/scan (multipart), POST /api/expenses, PUT /api/expenses/{id}, DELETE /api/expenses/{id}.
- Soft-fail on vision errors: if Claude can't read the receipt for any reason, the photo still uploads and the form opens empty for manual entry — so a bad scan never blocks saving the expense.
Web Push notifications + home-screen badgev3.72026-05-12major
- Push notifications instead of SMS for task assignments and tracker tasks. When a helper has push enabled on at least one device, the assignment fires a system notification (banner on the lock screen / Notification Center) and the SMS fallback is skipped — no Twilio cost, no 10DLC compliance burden, no carrier delays. SMS still fires automatically if the helper has zero push devices subscribed.
- Home-screen icon badge shows the user's open-task count. Updates every time the items list reloads (start of session, after completing a task, after receiving a push). Uses the Web Badging API; no-ops on platforms that don't support it.
- iOS works for installed PWAs on iOS 16.4+ — full push + badge support. The Profile modal explicitly explains this and links to
/install.html when push is unavailable because the user is in a Safari tab instead of the installed PWA.
- VAPID keypair generated and stored server-only in
config.php. The browser fetches just the public key via GET /api/push/vapid-key at subscribe time.
- Per-device subscriptions — each browser/device a user signs in from registers its own push subscription. A user with both an iPad and an iPhone gets pushes on both; turning off on one doesn't affect the other.
- "Send test notification" button in Profile (visible after enabling push) lets you confirm delivery without waiting for a real task assignment.
- Schema v23:
push_subscriptions(user_id, endpoint, p256dh, auth, user_agent, created_at, last_used) with a unique key on (user_id, endpoint).
- Library:
minishlink/web-push v8 via Composer (PHP 8.0 compat). Required php-gmp extension installed on Pluto for ECDH key derivation.
- New routes:
GET /api/push/vapid-key, POST /api/push/subscription, DELETE /api/push/subscription, POST /api/push/test.
- Service worker at
/sw.js handles incoming push events, fires showNotification(), sets the app badge, and routes notification taps back to the PWA (focusing an open tab if one exists, otherwise opening a new window).
TCR resubmission: SMS opt-in is now optional everywherev3.62026-05-12fix
- Why this exists: the original A2P 10DLC campaign submission was rejected with reason "consent cannot be a required condition for service or transaction completion." The public invite-request form on
/optin.html was making the SMS-consent checkbox required to submit, which violated that rule.
- Public form change: the SMS consent checkbox is now clearly labeled Optional. Submitting the form requires only name + phone. A user who declines SMS still gets a request on file; the administrator shares the invitation link through a non-SMS channel (email, in person, etc.).
- Backend change:
POST /api/invite-requests no longer requires the consent field. It now accepts an optional wants_sms boolean and persists it. The exact consent text is recorded only when the user opted in (audit trail).
- Schema v22:
invite_requests.wants_sms TINYINT NOT NULL DEFAULT 0.
- Admin invite-requests view shows a blue "✉ wants SMS" badge on requesters who opted in, gray "no SMS" badge otherwise. When the admin clicks Invite from a request, the per-invite SMS toggle now defaults on/off to match the requester's preference.
- New step in the opt-in disclosure at
/optin.html explicitly states: "Use of Upkeep does not require SMS consent. Recipients who decline SMS can still be invited via a copyable link the administrator shares through any channel they prefer."
- No change needed to the user-Profile phone-verification flow — that's user-initiated (a logged-in user adding/changing their own phone), so the verification SMS is the transaction and consent is implicit in the user's action.
Hourly rates & pay totals on the timeclockv3.52026-05-12feature
- Per-user hourly rate — admins set a $/hr rate on each helper. Schema v21 adds
users.hourly_rate (DECIMAL, NULL = no rate, no pay surfaced).
- Pay on the Time screen — alongside Today / This week / All time, helpers with a rate now see running pay in green, ticking once per second while they're clocked in.
- Admin dashboard — each helper card shows week-to-date pay as a green pill when a rate is set.
- Helper drilldown — rate is shown at the top of the profile with an inline Edit button that opens a small modal to set or clear it. Time stats grow to four columns (Today / Week / Month / All time) when a rate exists, each annotated with pay.
- Timesheets — per-bucket pay shown next to hours; a green Total pay tile appears when any row in range has a rate. The CSV export gains
Rate ($/hr) and Pay ($) columns plus a grand-total pay line.
- New endpoint
PUT /api/admin/users/{id} for admin profile edits (name, email, phone, role, hourly_rate). Self-role-change blocked so an admin can't accidentally lock themselves out.
Timezone fix — clock entries now show local EDTv3.4.12026-05-12fix
- MariaDB was reporting UTC even though the OS was on America/New_York, so every
NOW() wrote 4-hour-ahead UTC into datetime columns. The Time screen showed clock-in/out times 4 hours off.
core.php now pins MySQL's session timezone via SET time_zone = '...P...' at connection time, with auto DST handling (returns "-04:00" in summer / "-05:00" in winter via PHP's named-timezone awareness).
- One-shot data shift back-fixed all 26 existing datetime columns across 16 tables (time entries, invites, sessions, equipment, items, vendors, etc.) so historical data displays at the correct local wall-clock time.
Conversational Hawkeye, geofence, install guidev3.42026-05-12feature
- Hawkeye conversation mode — tap the mic and Hawkeye runs a hands-free back-and-forth: speech auto-sends when you pause, mic auto-reopens after the reply (Chrome). On iPhone Safari, between turns the mic shows an amber "tap to continue" pulse — Apple requires a fresh user tap to re-acquire the mic, no way around it.
- Geofence on clock-in — helpers must be within 1 mile of the front gate (28.406958, -82.608989) to clock in. Admins (you + Christy) bypass the check; their location is still recorded for audit. Schema v19 adds
clock_in_lat / lng / accuracy_m columns. Radius is configurable via GEOFENCE_RADIUS_M in config.php.
- How to install page at
/install.html — step-by-step PWA install instructions for iPhone, Android, Windows desktop, and macOS desktop. Linked from the user menu as "How to install".
- One-time install prompt — first-login users see a friendly "Install Upkeep" modal with Skip / Show me how buttons. Server-tracked per user (schema v20 adds
users.install_hint_dismissed) so it never shows again once dismissed. Auto-skipped if the app is already running as an installed PWA.
- Voice fixes: switched to a DOM-attached audio element so iOS Safari honors the autoplay-unlock from the user gesture (was hearing system TTS instead of the chosen ElevenLabs voice). New voice ID
YPtbPhafrxFTDAeaPP4w wired in.
- Bug fix: Speech recognition was caching one instance and reusing it across turns — iOS Safari and recent Chrome silently reject restart on a stale instance. Now creates a fresh recognition object every listen cycle.
- Chat input layout — paperclip + mic stack vertically on the left so the textarea reclaims horizontal width.
Hawkeye gets photos, memory, voice, ElevenLabsv3.32026-05-12major
- Photo upload from chat — paperclip button next to the Hawkeye text box. Pick a photo, add an optional caption, send. Hawkeye sees the image directly via vision, and the photo is also saved to the permanent photo library + auto-vision-indexed so future questions can retrieve it.
- Save-to-memory tool — Hawkeye can now permanently remember facts you tell it. Say "remember this" or share a property-specific detail (gate code, valve location, vendor preference) and Hawkeye writes it to
notes/learned-from-chat.md via a Claude tool-use call. A small "✓ Saved" chip appears under the reply so you can verify it stuck. Saved facts show up in every future chat.
- Voice input (speech-to-text) — microphone button in the chat input. Tap, speak naturally, transcript fills the textarea live. Tap again to stop, or just hit send. Web Speech API; works on iPhone Safari + desktop Chrome/Edge.
- Voice replies (text-to-speech) — speaker toggle in the chat header. When on, Hawkeye's replies are spoken aloud. Primary path: a custom ElevenLabs voice via a server-side proxy so the API key stays private. Fallback: device-native TTS if the ElevenLabs call fails.
- Chat input layout polish — paperclip and mic stack vertically on the left side of the input row, giving the textarea back its horizontal real estate.
- Bug fix: the My Stuff list was crashing with a PDO "Invalid parameter number" error since the task-assignment work — fixed the duplicate
:uid placeholder.
- Bug fix: photo upload from chat was 404'ing because chat.php was including hawkeye.php (which has top-level routing code that 404'd on non-/api/hawkeye URLs). Extracted the shared vision helper into a side-effect-free
api/_hawkeye_lib.php.
Login background, theme picker, Hawkeye logo, release historyv3.22026-05-12feature
- Login page background — full-bleed lightning + ember image with a frosted-glass form card. The form floats over the dark middle of the image; CSS backdrop-blur keeps text readable on any aspect ratio.
- Theme picker in the user menu — System / Light / Dark segmented buttons. Choice persists to localStorage and applies across the main app, Hawkeye admin, and Release history. Inline-init script in
<head> prevents the brief flash of the wrong palette on page load.
- New Hawkeye logo — orange hawk with a headset, transparent background with a subtle drop-shadow so it pops against any page color. Replaces the placeholder "U" icon in the chat FAB and overlay header.
- Upkeep app icon stays as the "U" — PWA app icons (192/512), iOS apple-touch-icon, and favicon all regenerated from the U SVG. Separates the Upkeep app identity from the Hawkeye assistant identity.
- Release history page at
/release-history.html (this page) — accessible from the user menu. Versions, dates, badges, and bullet summaries for every meaningful change.
- Small-caps treatment on the bottom-nav labels and user-menu items, matching the topbar titles.
Tracker + task edit, assignment, polishv3.12026-05-10feature
- Edit tracker from the Trackers screen — Edit button on the inline expanded card and on the tracker detail header. Modal pre-fills with name, equipment, category, interval, notes.
- Edit personal task from My Stuff — Edit button on every task row opens a dedicated modal for name, category, interval, due date, birthdate (animal categories), and notes.
- Task assignment — admins can reassign any task to any user via the new Assigned to dropdown in the edit modal. Reassigned tasks move to the assignee's My Stuff.
- Cancel in-progress session — fat-finger rescue. Cancel button on the inline tracker card and inside the active-session screen. Nothing logs; tracker resets to Start.
- Topbar icons — every screen now shows its bottom-nav icon to the left of the title. Titles render in small caps with a touch of letter-spacing.
- "Add task" page renamed to "Create task" to match the bottom-nav Create label.
- Second admin — Christy Howard added as a co-admin (id=3). Hawkeye admin gating relaxed from owner-only to admin-only.
- Defensive category reload — modals self-heal if the in-memory categories list is empty, fixing race-condition empties in the Add Tracker / Edit task / etc. dropdowns.
Hawkeye AI chatbot + admin UI + photosv3.02026-05-10major
- Hawkeye AI assistant powered by Claude Sonnet 4.5. Floating chat button on every screen → full-width chat overlay constrained to the app column. Knows your Upkeeps, Keys, equipment manuals, animal care notes, and curated property notes.
- Retrieval-based context — the chatbot loads the most relevant manual sections per question (not all manuals every time), keeping requests under the API rate limit.
- Hawkeye admin page at
/admin/hawkeye.html for managing notes, care references, equipment manuals (PDF auto-conversion), and photos. Available from the menu as Hawkeye admin.
- Photos with vision indexing — uploaded photos are auto-described by Claude vision on upload and stored as searchable references. Up to 3 relevant photos per chat query are attached as image content blocks; thumbnails appear under Hawkeye's reply.
- 9 equipment manuals seeded with manifest-routed retrieval (Bobcat CT2540, UTV34XL, Big Bear BBC62, MEP-006A operator/repair/parts, AN/MJQ-12A power plant, PU-650B/G power unit, American Fab 9500M).
- Curated maintenance reference notes for tractor, mower, Polaris, generator, Cushman golf cart in
data/chatbot/notes/.
- 7 equipment service trackers seeded via one-shot SQL: Bobcat tractor (CT2540), UTV (UTV34XL), mower (ZT3500), Polaris 4x4, MEP-006A diesel generator, Big Bear BBC62 chipper, M9500 gas generator. Garden Beds Upkeep with daily watering tracker.
- Mileage field on Upkeeps for vehicle categories — cards show miles instead of hours when present.
- Trackers screen polish — collapsible equipment groups (auto-expand on Due/Overdue filter), category filter row, in-place tracker task editing.
- Invite link-share rewrite — invites now generate a copyable URL that admins can share through any channel; SMS via Upkeep is per-invite opt-in. Resolves Twilio TCR rejection 30923.
- PWA polish — proper maskable icons (192/512), apple-touch-icon, favicon, manifest fixes.
- Security —
/data/ directory locked down with .htaccess; manuals, notes, and photos served only via auth-gated PHP endpoints.
Keys vendor directory; navigation refreshv2.32026-05-03feature
- Keys — new vendor / contact directory under its own bottom-nav tab. Add company info manually or auto-fill from a website URL (scrapes Open Graph + JSON-LD).
- Bidirectional Key linking — attach Keys to Upkeeps or Trackers from either side; the other side updates automatically.
- Navigation icon refresh — all six bottom-nav icons replaced with a consistent line-art set (Create, Keys, Time, Trackers, Upkeeps, Log icons).
- Log consolidated into My Stuff as an expandable card at the bottom of the screen.
- Upkeeps category filter — pill row at the top of the Upkeeps page to narrow by category (Cats, Dogs, Vehicles, etc.).
- Vet fields removed from Upkeeps in favor of linking a Key.
Equipment polish: model, age stat, mileagev2.22026-05-02polish
- Equipment model number field added.
- Animal cards show age (years/months) instead of hours.
- Empty-string → NULL coercion for nullable fields (DATE/INT in MySQL strict mode).
Animal-aware Upkeep modal; HEIC; timesheetsv2.12026-05-02feature
- Animal-aware Upkeep modal: birthdate, microchip, vet info conditional on category being Cat/Dog/Livestock.
- HEIC photo conversion server-side (libheif) plus auto-downscale via GD.
- Admin timesheets with CSV export.
- Terms of Service + Privacy Policy pages, linked from the menu.
Public invite-request CTAv2.0.12026-05-01fix
- Public
/optin.html#request form for prospective helpers to request an invite — required for Twilio A2P 10DLC compliance (CTA verification).
Timeclock, admin dashboard, SMS opt-inv2.02026-05-01major
- Timeclock — clock in / clock out, accumulating hours per user.
- Admin dashboard — at-a-glance stats, helper drilldown, active sessions and clocks "Right now" view.
- SMS opt-in disclosure page at
/optin.html — required for Twilio A2P registration.
- Categories CRUD — admins can add/edit/recolor categories from the dashboard.
Profile editor, password change, phone verificationv1.42026-04-22feature
- Profile modal: edit name, email, phone (with SMS verification code).
- Password change flow.
- Privacy Policy and Terms of Service pages.
Invites + SMS; helpers; tracker assignmentv1.32026-04-22feature
- Helper user role; admin invite + SMS notification system via Twilio.
- "Mine" renamed to "My stuff" throughout the UI.
- Inline tracker assignment from the tracker card (admin only).
Mobile polish; livestock subtypesv1.22026-04-22polish
- Native-feel topbar with safe-area handling, back chevron, card tap-to-edit.
- Add-form destination picker, helper visibility tweaks.
- Service-detail NaN badge fix; filter-row fade-right on overflow.
- Subtypes for livestock (Highland Cow, Donkey, Chicken, Turkey, Dog, Cat).
- Admin user / tracker assignment foundation.
Upkeeps + Trackers terminology; CT2540 seedv1.12026-04-21feature
- "Equipment" renamed to "Upkeeps" and "Services" renamed to "Trackers" throughout the UI.
- Initial Bobcat CT-2540 service seed data (100 / 200 / 400-hour service lists).
- Equipment photo edit flow fix.
Equipment, Services, active sessionsv1.02026-04-15major
- First production-ready release on
upkeep.softwerks.pro.
- Core MVP: Equipment registry, Services (recurring tasks), active service sessions, log entries, photo uploads, categories.
- Initial Upkeep branding throughout.