iOS App Store distribution with Turbo Native (turbo-ios) #108

Closed
opened 2026-06-05 04:02:59 +00:00 by ldraney · 1 comment
Owner

Type

Feature

Lineage

Standalone — scoped during multi-user planning session (2026-06-04).
Depends on #107 (auth) landing first.

Repo

ldraney/landscaping-assistant (Rails backend)
New repo: ldraney/landscaping-ios (Swift/Xcode project)

User Story

As a crew member
I want to download the app from the App Store on my iPhone
So that I can access the landscaping tool like any other app

Context

The app is a Rails 8.1 Hotwire app (Turbo + Stimulus). Turbo Native (turbo-ios) is the Rails-ecosystem answer to App Store distribution — it's the Swift library that 37signals built and uses to ship HEY and Basecamp to the App Store.

turbo-ios wraps your existing Turbo-powered web views in a native iOS navigation shell. The Rails server does all the heavy lifting — the Swift project is a thin client that handles native navigation chrome (back buttons, transitions, tab bar) and can optionally add native screens for things like camera access or push notifications.

Why Turbo Native over Capacitor: This is a Hotwire app. Turbo Native is purpose-built for Hotwire apps. It understands Turbo Drive navigation, Turbo Frame rendering, and provides native-feeling page transitions automatically. Capacitor is a generic WebView wrapper that doesn't integrate with Turbo at all.

Backend: The Rails app runs on k3s behind Tailscale. Users must have Tailscale installed on their phone. The iOS app points at landscaping-assistant.tail5b443a.ts.net.

Key turbo-ios concepts:

  • Session — manages a WKWebView and handles Turbo navigation events
  • Visitable — a view controller that loads a Turbo-powered page
  • PathConfiguration — a JSON file (served by Rails) that maps URL paths to native behavior (e.g., /login could be a native screen, everything else is a web view)
  • The Rails app can serve a turbo/native/path_configuration.json endpoint to control navigation behavior from the server side

File Targets

New repo landscaping-ios:

  • Xcode project with turbo-ios Swift package dependency
  • SceneDelegate.swift — configure Turbo Session pointing at Tailscale URL
  • PathConfiguration.json — URL-to-behavior mapping
  • App icons (1024x1024 source, Xcode generates all sizes)
  • Launch storyboard / splash screen

Rails backend (this repo):

  • app/controllers/turbo/native/path_configurations_controller.rb — serve path config JSON
  • config/routes.rb — add path configuration endpoint
  • Detect Turbo Native requests (request.user_agent includes "Turbo Native") for any native-specific behavior

Acceptance Criteria

  • landscaping-ios Xcode project builds and runs in Simulator
  • App connects to Tailscale-hosted Rails backend
  • Native iOS navigation (back button, swipe-to-go-back) works with Turbo pages
  • Login form (#107) works within the native shell
  • All existing tabs (Today, Week, Properties, Manage, Photos) accessible
  • App icon and launch screen branded (not placeholder)
  • TestFlight build uploaded and installable by invited crew members
  • App Store submission (requires Apple review — may need privacy policy page)
  • PathConfiguration served from Rails so navigation behavior can be updated server-side

Test Expectations

  • Xcode project builds without warnings
  • UI test: app launches, navigates to login, authenticates, reaches main screen
  • Request spec (Rails): GET /turbo/native/path_configuration returns valid JSON
  • Run command: xcodebuild test -scheme LandscapingAssistant -destination 'platform=iOS Simulator,name=iPhone 16'

Constraints

  • Requires a Mac with Xcode for builds
  • Apple Developer account ($99/year) — enroll before starting
  • Tailscale must be installed on the user's iPhone for backend access
  • turbo-ios Swift package: https://github.com/hotwired/turbo-ios
  • Minimum iOS target: iOS 16 (covers ~95% of active devices)
  • App Store review may require a privacy policy URL and demo account
  • The Turbo Native wrapper should be as thin as possible — all UI/logic lives in Rails

Checklist

  • Apple Developer account enrolled
  • landscaping-ios repo created
  • Xcode project configured with turbo-ios dependency
  • TestFlight build distributed to crew
  • App Store submission approved
  • PR opened (Rails-side path configuration endpoint)
  • Tests pass
  • No unrelated changes
  • landscaping-assistant — project
  • #107 — Keycloak auth (must land first)
  • turbo-ios GitHub — the library
  • HEY iOS — production reference (same approach)
  • sop-keycloak-client-creation — Keycloak client for the app
### Type Feature ### Lineage Standalone — scoped during multi-user planning session (2026-06-04). Depends on #107 (auth) landing first. ### Repo `ldraney/landscaping-assistant` (Rails backend) New repo: `ldraney/landscaping-ios` (Swift/Xcode project) ### User Story As a crew member I want to download the app from the App Store on my iPhone So that I can access the landscaping tool like any other app ### Context The app is a Rails 8.1 Hotwire app (Turbo + Stimulus). **Turbo Native (turbo-ios)** is the Rails-ecosystem answer to App Store distribution — it's the Swift library that 37signals built and uses to ship HEY and Basecamp to the App Store. turbo-ios wraps your existing Turbo-powered web views in a native iOS navigation shell. The Rails server does all the heavy lifting — the Swift project is a thin client that handles native navigation chrome (back buttons, transitions, tab bar) and can optionally add native screens for things like camera access or push notifications. **Why Turbo Native over Capacitor**: This is a Hotwire app. Turbo Native is purpose-built for Hotwire apps. It understands Turbo Drive navigation, Turbo Frame rendering, and provides native-feeling page transitions automatically. Capacitor is a generic WebView wrapper that doesn't integrate with Turbo at all. **Backend**: The Rails app runs on k3s behind Tailscale. Users must have Tailscale installed on their phone. The iOS app points at `landscaping-assistant.tail5b443a.ts.net`. **Key turbo-ios concepts**: - `Session` — manages a WKWebView and handles Turbo navigation events - `Visitable` — a view controller that loads a Turbo-powered page - `PathConfiguration` — a JSON file (served by Rails) that maps URL paths to native behavior (e.g., `/login` could be a native screen, everything else is a web view) - The Rails app can serve a `turbo/native/path_configuration.json` endpoint to control navigation behavior from the server side ### File Targets New repo `landscaping-ios`: - Xcode project with turbo-ios Swift package dependency - `SceneDelegate.swift` — configure Turbo Session pointing at Tailscale URL - `PathConfiguration.json` — URL-to-behavior mapping - App icons (1024x1024 source, Xcode generates all sizes) - Launch storyboard / splash screen Rails backend (this repo): - `app/controllers/turbo/native/path_configurations_controller.rb` — serve path config JSON - `config/routes.rb` — add path configuration endpoint - Detect Turbo Native requests (`request.user_agent` includes "Turbo Native") for any native-specific behavior ### Acceptance Criteria - [ ] `landscaping-ios` Xcode project builds and runs in Simulator - [ ] App connects to Tailscale-hosted Rails backend - [ ] Native iOS navigation (back button, swipe-to-go-back) works with Turbo pages - [ ] Login form (#107) works within the native shell - [ ] All existing tabs (Today, Week, Properties, Manage, Photos) accessible - [ ] App icon and launch screen branded (not placeholder) - [ ] TestFlight build uploaded and installable by invited crew members - [ ] App Store submission (requires Apple review — may need privacy policy page) - [ ] PathConfiguration served from Rails so navigation behavior can be updated server-side ### Test Expectations - [ ] Xcode project builds without warnings - [ ] UI test: app launches, navigates to login, authenticates, reaches main screen - [ ] Request spec (Rails): GET /turbo/native/path_configuration returns valid JSON - Run command: `xcodebuild test -scheme LandscapingAssistant -destination 'platform=iOS Simulator,name=iPhone 16'` ### Constraints - Requires a Mac with Xcode for builds - Apple Developer account ($99/year) — enroll before starting - Tailscale must be installed on the user's iPhone for backend access - turbo-ios Swift package: `https://github.com/hotwired/turbo-ios` - Minimum iOS target: iOS 16 (covers ~95% of active devices) - App Store review may require a privacy policy URL and demo account - The Turbo Native wrapper should be as thin as possible — all UI/logic lives in Rails ### Checklist - [ ] Apple Developer account enrolled - [ ] `landscaping-ios` repo created - [ ] Xcode project configured with turbo-ios dependency - [ ] TestFlight build distributed to crew - [ ] App Store submission approved - [ ] PR opened (Rails-side path configuration endpoint) - [ ] Tests pass - [ ] No unrelated changes ### Related - `landscaping-assistant` — project - `#107` — Keycloak auth (must land first) - [turbo-ios GitHub](https://github.com/hotwired/turbo-ios) — the library - [HEY iOS](https://apps.apple.com/app/hey-email/id1506603805) — production reference (same approach) - `sop-keycloak-client-creation` — Keycloak client for the app
Author
Owner

Scope update (2026-06-05): App will use a public URL, not Tailscale-only. The app serves both web users (browser) and App Store users (turbo-ios). Tailscale is no longer a prerequisite for end users.

This means:

  • The turbo-ios app points at the public prod URL, not a Tailscale hostname
  • Auth (#107) is even more critical -- the app is internet-facing
  • No Tailscale dependency for crew members' phones

Pipeline: dev (docker-compose + MacBook Xcode) → CI (Woodpecker) → dev URL (pal-e-deployments) → public prod URL → TestFlight → App Store.

**Scope update (2026-06-05)**: App will use a **public URL**, not Tailscale-only. The app serves both web users (browser) and App Store users (turbo-ios). Tailscale is no longer a prerequisite for end users. This means: - The turbo-ios app points at the public prod URL, not a Tailscale hostname - Auth (#107) is even more critical -- the app is internet-facing - No Tailscale dependency for crew members' phones Pipeline: dev (docker-compose + MacBook Xcode) → CI (Woodpecker) → dev URL (pal-e-deployments) → public prod URL → TestFlight → App Store.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/landscaping-assistant#108
No description provided.