Landscaping Assistant

project-landscaping-assistant Project Page

active project-page

Vision

Property management app for a landscaping business operating in Utah County and SLC. Track client properties, their addresses, services (edging & trimming, mowing, weeding), and per-property notes. Address lookup via Nominatim geocoding so you can enter a house number and get the full verified address. Built with Ruby on Rails to learn the framework while shipping a real tool.

User Stories

Key Role Summary Success Metric
address-lookup Landscaper Enter house number, get full address Address auto-fills from Nominatim results
property-crud Landscaper Add/edit/delete client properties Full CRUD with search and filter
service-tracking Landscaper Assign services to properties Checkboxes for edging/mowing/weeding per property
special-notes Landscaper Per-property free-text notes Notes visible on property detail page
work-queue Landscaper Queue properties for today and reorder route Drag-to-reorder, complete/uncomplete toggle, Turbo Stream updates
weekly-tracking Landscaper Track weekly completion across all active properties Week view shows completed/total, inactive properties excluded
schedule-upload Landscaper Snap a photo of the paper schedule for later reference Upload photo, view thumbnails, editable captions, MinIO storage in prod
comments All roles Threaded discussion on property detail pages with photo attachments, reply threads, and activity-based sort Comments support photos, one-level threading, newest-activity-first sort. Umbrella: #303. Children: #302 (camera crash), #304 (sort order)
saas All roles SaaS subscription, business codes for crew onboarding, admin approval of join requests, Apple IAP billing Business admin generates join code, crew enters code to request access, admin approves/denies. Apple IAP subscription at $49.99/mo. Umbrella: #308. Children: #309 (join form), #310 (admin approval), #312 (Keycloak registration field)
auth All roles Log in with Keycloak, see role-appropriate tabs and features Auth Code + PKCE login, role-based nav (5-slot grid), PaperTrail audit trail, graceful degradation without Keycloak
account-email All roles Receive password reset and email verification emails via Postmark SMTP 100% of password reset requests result in delivered email (verified via Postmark Activity feed). Story note: <code>story-landscaping-assistant-account-email</code>
multi-tenancy Platform owner Business model with row-level property isolation so multiple landscaping companies can use the app without seeing each other's data Properties scoped to current_business behind multi_tenancy feature flag. Second test business (Greenview Landscaping) fully isolated from D&amp;T Lawn Rangers. Umbrella: #282. Children: #294 (model), #295 (scoping), #296 (seed data)
custom-domain All roles Access app via landscaping-assistant.app instead of Tailscale hostname. DNS A record to Hetzner edge VPS (godaddy-tofu/pal-e-platform), Caddy reverse proxy (Salt state), Rails config.hosts + Keycloak redirect URI updates landscaping-assistant.app resolves and serves the app publicly. Umbrella: landscaping-assistant#223. Children: pal-e-platform#434 (Caddy), landscaping-assistant#224 (Rails+Keycloak)
deploy-validation Platform owner Staging environment that auto-deploys every commit for deploy validation via observability before promoting to prod staging.landscaping-assistant.app serves the app, golden signals visible in Grafana, alerts fire on broken deploys, prod remains manual promotion. Parent: #342
app-store-submission All roles Submit and maintain iOS App Store listing (privacy declarations, review compliance, metadata) App approved and published on App Store
ci-performance Developer CI pipelines reuse pre-compiled gems from base image for faster builds bundle-install step seeds from pre-baked gems, pipeline time reduced
crew-time-tracking Crew Member, Crew Lead Clock in/out, track breaks, view daily/weekly hours from Hours tab (nav slot 2). BusyBusy-inspired time tracking. 100% of crew can clock in, break, and clock out with accurate time totals. Story note: <code>story-landscaping-assistant-crew-time-tracking</code>. Parent: #331

Architecture

Monolithic Rails 8.1.3 app with Hotwire (Turbo + Stimulus). PostgreSQL via shared CNPG cluster. Nominatim for geocoding. ActiveStorage + MinIO for photo uploads.
  • Domain: Property, Service, PropertyService (join), WorkQueueItem, Upload
  • Turbo Streams for queue add/remove/complete toggle
  • Stimulus controllers: location, filter, sortable, add-location, week-move, upload
  • Five-tab bottom nav: Today / Week / New / Properties / Photos
  • ActiveStorage with S3-compatible MinIO backend in prod, local disk in dev
  • No separate frontend -- Rails serves HTML directly

Board

Primary kanban: board-landscaping-assistant
Observability kanban: board-landscaping-observability (dedicated project: landscaping-observability)

Observability

Target: full Datadog-equivalent observability using the open-source Grafana ecosystem. Benchmark table tracks progress against every Datadog capability. Detailed rollout plan in docs/observability-roadmap.md. Parent issue: #43.
Datadog Capability Our Equivalent Status Issue
Infrastructure Monitoring kube-prometheus-stack + node-exporter COMPLETE --
Log Management Loki + Promtail + Grafana Explore COMPLETE --
Application Metrics yabeda-rails + yabeda-prometheus COMPLETE #19 (done)
Dashboards Grafana (26 dashboards + golden signals) COMPLETE #16 (done)
Alerting Alertmanager -&gt; Telegram + Slack PARTIAL #17 (backlog)
CI Visibility DORA exporter + Woodpecker API COMPLETE #20 (done)
Synthetic Monitoring Blackbox exporter (13 probes) COMPLETE #21 (done)
Container Scanning Harbor Trivy COMPLETE --
APM / Distributed Tracing OpenTelemetry + Grafana Tempo NOT STARTED #85
Database Monitoring (query-level) pg_stat_statements + Grafana dashboard NOT STARTED #86
Continuous Profiling Grafana Pyroscope NOT STARTED #87
Infrastructure Visualization Headlamp + Grafana NodeGraph NOT STARTED #88
RUM (Frontend) Grafana Faro NOT STARTED #89
SLOs / Error Budgets Pyrra NOT STARTED #90
Runtime Security Falco NOT STARTED #90