Plant Manager / myplantjournal.com
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