PlanBoard — Platform Decision Record

A dated entry for every cross-platform decision baked into the codebase. Treat this as a living document — every PR that adds an #if os(...) block updates this file.

Format:

## PDR-NNN — Short title
**Date**: YYYY-MM-DD
**File(s)**: relative path
**Decision**: what we did
**Rationale**: why
**Alternatives considered**: brief
**Revisit if**: condition

PDR-001 — Native macOS, not Catalyst

Date: 2024-09-01 Files: project-level (Xcode target setup) Decision: Two separate targets — PlanBoard-iOS and PlanBoard-macOS — sharing Swift packages, not a single iOS target with Catalyst. Rationale: Mac-feeling app. Catalyst’s iOS chrome doesn’t pass a Mac user’s smell test (button tints, toolbar sizing, missing keyboard nav). Alternatives considered: Catalyst (faster, worse UX); SwiftUI multiplatform single target with #available(macOS ...) (couples shipping cadences). Revisit if: Apple converges Catalyst + SwiftUI lifecycle further and the Mac chrome story improves.

PDR-002 — NavigationStack on iPhone, NavigationSplitView on iPad and Mac

Date: 2024-09-03 Files: PlanBoardiOS/RootView.swift, PlanBoardMac/RootView.swift Decision: iPhone uses a stack-based navigation root; iPad and Mac use 3-pane split view. Rationale: Phone screen is too small for split view to be useful. iPad and Mac users expect sidebar/content/detail. Alternatives considered: Split view everywhere (cramped on iPhone); stack everywhere (wastes screen on iPad/Mac). Revisit if: iPhone introduces a new form factor where a sidebar makes sense (foldable).

PDR-003 — MenuBarExtra on Mac, no equivalent on iOS

Date: 2024-09-05 Files: PlanBoardMac/App.swift Decision: Mac app declares a MenuBarExtra scene with a popover showing top 3 cards. iOS has no equivalent. Rationale: Menu bar is a native Mac affordance; iOS has Widgets which fill the same role. Alternatives considered: NSStatusItem via NSApplicationDelegate (legacy, more boilerplate). Revisit if: Apple adds a system-tray-like surface to iOS.

PDR-004 — CommandMenu only on Mac

Date: 2024-09-05 Files: PlanBoardMac/App.swift Decision: .commands { ... } modifier is applied only to the Mac scene. Rationale: iOS doesn’t render command menus. Including them does nothing on iOS but adds clutter. Alternatives considered: Apply to all platforms (no harm but no benefit; we prefer explicit). Revisit if: SwiftUI on iPad gets first-class menu support.

PDR-005 — Multi-window only on Mac

Date: 2024-09-06 Files: PlanBoardMac/App.swift Decision: WindowGroup(id: "board", for: UUID.self) only declared in Mac target. Rationale: iPad does support multi-window via scenes, but the UX is less common and adds complexity. Defer to v2. Alternatives considered: Add iPad multi-window now (longer scope). Revisit if: a user explicitly requests iPad multi-window.

PDR-006 — Card drag with Transferable everywhere, custom for cross-window only on Mac

Date: 2024-09-08 Files: PlanBoardShared/Card+Transferable.swift, PlanBoardMac/MultiWindowDragHandler.swift Decision: Card conforms to Transferable for all platforms; cross-window drag handler is Mac-only. Rationale: Single-window drag works the same everywhere via Transferable. Cross-window drag only matters on Mac (only Mac has multi-window in v1). Alternatives considered: Implement custom drag everywhere (over-engineered). Revisit if: iPad multi-window is added (then this handler needs iPad support too).

PDR-007 — Hover effects only on Mac

Date: 2024-09-10 Files: PlanBoardShared/View+Hover.swift Decision: A .planboardCardHover() modifier applies .onHover only when os(macOS). Rationale: iPad has pointer events too, but the design feedback is similar to touch. Mac is the primary hover-driven platform. Alternatives considered: Enable hover on iPad with pointer (could revisit). Revisit if: iPad pointer usage becomes a primary interaction model worth designing around.

PDR-008 — Different “primary action” gesture per platform

Date: 2024-09-12 Files: PlanBoardShared/CardView.swift Decision: Tap on iOS, click on Mac (same .onTapGesture); long-press on iOS shows context menu, right-click on Mac shows the same menu. Rationale: .contextMenu handles both — single API, platform-correct trigger. Alternatives considered: Custom gesture handling per platform (unnecessary). Revisit if: tvOS or visionOS support is added.

PDR-009 — Inspector as sheet on iPhone, third pane on iPad/Mac

Date: 2024-09-14 Files: PlanBoardiOS/RootView.swift, PlanBoardMac/RootView.swift Decision: Card detail is a .sheet on iPhone, the detail column on iPad/Mac. Rationale: iPhone screen can’t fit a third pane; sheet is the iOS-idiomatic modal. Alternatives considered: Sheet on all platforms (wastes screen on iPad/Mac); navigation push on iPhone (loses context). Revisit if: a new iPhone form factor changes this.

PDR-010 — Widget shape varies by host

Date: 2024-09-16 Files: PlanBoardWidget-iOS/WidgetEntryView.swift, PlanBoardMac/MenuBarContent.swift Decision: Same TopCardsContent view; iOS wraps in containerBackground(.fill.tertiary, for: .widget), Mac wraps in a popover-shaped container. Rationale: Widget hosts have different visual conventions; the content is identical. Alternatives considered: Two completely separate widget implementations (duplication). Revisit if: Apple introduces unified widget chrome across platforms.

PDR-011 — Keyboard shortcuts only declared on Mac

Date: 2024-09-18 Files: PlanBoardMac/App.swift Decision: .keyboardShortcut(...) modifiers exist only inside Mac CommandMenu declarations. iOS shortcuts (for hardware keyboards) are not declared in v1. Rationale: Scope. iOS hardware keyboard shortcuts are a v2 polish. Alternatives considered: Declare shortcuts in shared scenes (works but doesn’t address discoverability on iOS). Revisit if: a user with an iPad+keyboard requests it.

PDR-012 — NavigationSplitViewStyle.balanced on Mac, .automatic elsewhere

Date: 2024-09-20 Files: PlanBoardShared/View+Navigation.swift Decision: .planboardNavigationStyle() modifier uses .balanced on Mac, .automatic elsewhere. Rationale: Balanced gives Mac users a familiar 3-equal-column layout; automatic adapts well on iPad. Alternatives considered: .prominentDetail (Mac feels off); .automatic everywhere (Mac sidebar collapses too aggressively). Revisit if: SwiftUI improves the default Mac sidebar behavior.


How to maintain this document

When you add an #if os(...) block:

  1. Append a new PDR entry below the last.
  2. Number sequentially.
  3. Always include date, files, decision, rationale, alternatives, revisit condition.
  4. In your PR description, link to the PDR entry.

When you remove an #if os(...) block:

  1. Add a new PDR entry noting the removal (don’t delete the historical one).
  2. Reference the original PDR.
  3. Explain why the conditional is no longer needed.

This way the file grows monotonically and contains the full history of cross-platform decisions for the app’s lifetime.


Continue to the Appendix.