← All projects

Plant Journal

Plant Manager / myplantjournal.com plants

A full-stack plant care and journaling application — built as a web app, then rebuilt as a native iOS app with offline-first SwiftData storage.
---

What It Does

Plant Manager is a household plant tracking system. You can catalog every plant you own, log care events (watering, fertilizing, repotting, pruning, pest treatment, growth measurements), attach photos, write notes, and manage to-do lists — all scoped to your plant collection. NFC stickers and QR codes can be programmed and physically attached to plants, so scanning a tag instantly opens that plant's profile. ---

Web App (v1)

Live at: myplantjournal.com Stack: Next.js 16 (App Router) · React 19 · TypeScript · Supabase (PostgreSQL + Auth + Storage) · Tailwind CSS 4 · shadcn/ui · TanStack Query · Zod Key features:
  • Multi-user household model with invite-based read/write sharing
  • Row Level Security enforced at the database layer via Supabase RLS
  • NFC/QR tag management — tags resolve to a public plant page (no login required)
  • Plant journal with 7 entry types, photo uploads, and growth tracking
  • Plant-scoped and household-scoped notes and to-do lists
  • Admin panel for user management; first-run admin bootstrap via atomic DB function
  • Deployed behind nginx on a self-hosted Proxmox LXC container with production Next.js builds
---

iOS App (v2 — In Progress)

A ground-up SwiftUI rewrite targeting iOS 17+, removing the Supabase dependency entirely in favor of local-first storage. Stack: SwiftUI · SwiftData · CoreNFC · CoreImage · PhotosUI Key decisions & trade-offs:
  • SwiftData replaces PostgreSQL — all data lives on-device in a SQLite store managed by the framework, with @Attribute(.externalStorage) for image blobs
  • No authentication — eliminated entirely; single-user model with optional iCloud CloudKit sync for cross-device access
  • NFC/QR tags encode a custom URL scheme (plantmanager://tag/{uuid}) that deep-links directly into the app, replacing the public web resolver page
  • Household sharing deferred — architecture is CloudKit-compatible, making future family sharing an additive change rather than a rewrite
  • The admin panel and multi-user RLS logic were dropped as unnecessary complexity for a personal app
Key features:
  • Full plant CRUD with care profiles, photo picker, and archive support
  • Journal entries with all 7 types, growth measurements, multi-photo attachment
  • NFC tag read/write via CoreNFC; QR code generation via CoreImage (no third-party libraries)
  • Plant-scoped and global notes and to-do lists
  • Dashboard with live stats (active plants, today's logged entries, open tasks)
  • Deep link handling: scanning any programmed NFC tag or QR code opens the app to the correct plant
---

What I Learned

  • Designing for Row Level Security from the start is significantly easier than retrofitting it — the household-sharing RLS policies became complex fast once share permissions needed to layer on top of ownership checks
  • SwiftData's @Observable + @Query pattern eliminates most of the boilerplate that made Core Data tedious; the tradeoff is iOS 17+ only
  • NFC writing on iOS requires careful handling of the NFCNDEFReaderSession delegate lifecycle — invalidateAfterFirstRead: false is required for write mode, and the session must be invalidated explicitly after a successful write
  • Building the web version first made the iOS data model much cleaner — I had already worked through the edge cases (tag assignment history, optional plant scoping for notes/todos) and could make deliberate simplifications for the native version