Skip to content

Latest commit

ย 

History

History
88 lines (66 loc) ยท 6.32 KB

File metadata and controls

88 lines (66 loc) ยท 6.32 KB

ARCHITECTURE.md

High-level system design for BrewUI. Update when structure changes. Owns: layers, data flow, integrations (Homebrew CLI / JSON API), and product constraints. Defers naming and day-to-day coding patterns to CONVENTIONS.md. Record durable rationale in .ai/memory.md.

Tech Stack

Concern Choice
Language Swift 6.0 (strict concurrency mode)
UI Framework SwiftUI โ€” pure; use AppKit only when SwiftUI cannot meet a requirement
State management @Observable (Swift 5.9+)
Concurrency async/await throughout; actor isolation for shared mutable state
Package manager Swift Package Manager
macOS targets Tahoe 26, Sequoia 15, Sonoma 14 โ€” minimum: Tahoe 26
Data sources Homebrew JSON API (formulae.brew.sh) + brew CLI subprocess
Deployment Unsandboxed macOS app (default Homebrew prefix)

System shape

Flow: View โ†’ ViewModel โ†’ ไป“ๅบ“ or Interactor โ†’ Services โ†’ brew CLI or JSON API.

Guiding patterns:

  • MVVM-C (lightweight): Views stay declarative; ViewModels own presentation state; coordination/navigation policy is centralized in small coordinator-style shell types when needed.
  • Clean Architecture principles: Depend inward on abstractions, keep use cases in Interactors/ไป“ๅบ“, isolate infrastructure in Services, and keep UI/framework concerns out of domain decisions.
  • Emergent architecture: Prefer the smallest pattern that solves todayโ€™s problem; evolve structure incrementally as features and complexity grow.
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    BrewUI (macOS App)                        โ”‚
โ”‚  Views (SwiftUI) โ”€โ”€โ–ถ ViewModels                              โ”‚
โ”‚         โ”‚                    โ”‚                               โ”‚
โ”‚         โ”‚          ไป“ๅบ“    Interactors               โ”‚
โ”‚         โ”‚                 โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜                        โ”‚
โ”‚         โ”‚                      Services (brew + JSON API)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
              brew CLI (subprocess) ยท formulae.brew.sh JSON API

Core components

  • Views: SwiftUI; thin โ€” bind state, forward actions.
  • Feature root views (*Root): Composition boundaries that bridge app-level dependencies into feature content. Root wrappers read environment-level dependencies and construct/inject content-view dependencies while managing view-model lifecycle boundaries.
  • ViewModels: Presentation state and mapping; delegate work downward. Keep domain rules in Interactors or Models, not here.
  • Presentation boundary: Domain models remain UI-agnostic. Map domain values to UI-ready properties through feature ViewModels for top-level surfaces, or dedicated feature Item types for subview/action-level presentation needs.
  • ไป“ๅบ“: CRUD-shaped access to a data source (CLI output, API, storage, in-memory). Swap the implementation, keep the contract.
  • Interactors: One use case each โ€” not generic CRUD (e.g. a doctor run). Prefer protocols + real/mock impls for tests. (One-shot reads such as the brew config snapshot are modelled as ไป“ๅบ“ here, not Interactors.)
  • Services: Infrastructure grouped by integration boundaries.
  • Command center: BrewCommandCenter (actor protocol; app default SerialBrewCommandCenter) โ€” serializes mutating brew work, tracks in-flight / failed operation state (BrewOperationID + BrewOperationPhase) for UI across surfaces, and runs small BrewMutatingCommand types that call BrewCommandRunning + the brew locator. It does not own read/parsing of brew list / brew info output โ€” that stays in repositories. Feature-scoped executors (e.g. upgrade helpers) should stay thin and be invoked from commands the center schedules, not as a second parallel pipeline.
  • Models: Domain-only value types and relationships shared across layers. Keep UI/presentation helpers, transport decoding models, and infrastructure-state containers out of domain models.

Command execution

Run Homebrew commands asynchronously via subprocess; support cancellation; stream or preserve stdout/stderr for transparency and logs. Always make the exact command visible to the user; treat CLI text output as unstable (tolerant parsing, fallbacks).

JSON API

Use the Homebrew JSON API where it helps. Prefer optional / resilient decoding โ€” schema can change; never crash on unknown fields. Combine with CLI only as needed when the app grows.

Constraints & decisions

  • macOS-only. No iOS / iPadOS / cross-platform for now.
  • Default Homebrew prefix only: /opt/homebrew (Apple Silicon) or /usr/local (Intel). No custom prefix initially.
  • No custom taps initially โ€” core tap scope.
  • brew is the source of truth โ€” BrewUI does not poke Homebrew internals.
  • Transparency โ€” users see what runs; no hidden commands.
  • Homebrew is separate โ€” detect and degrade if missing; do not bundle Homebrew.
  • Detection: try /opt/homebrew/bin/brew then /usr/local/bin/brew.
  • Open source โ€” patterns should stay contributor-friendly.

Platform constraints

  • CLI drift: brew text is not a stable API โ€” parsers must be tolerant.
  • JSON drift: decoding must stay resilient as the API evolves.
  • UI tests: async output and sheets need deliberate sync; avoid flakiness.
  • Accessibility: desktop workflows need keyboard and VoiceOver semantics, not only labels.

Resources

Updating this file

Change when layers or major assumptions shift. Put why in .ai/memory.md when it is non-obvious or contentious.