Skip to content

Repository files navigation

BTC/USD Real-Time Price

CI-iOS CI-Modules

A multi-platform (iOS + CLI) app that shows the live BTC/USD exchange price, refreshed every second. Built with the Essential Developer method — TDD, small always-green commits, modular design, and CI. One framework-free domain core, reused verbatim by two thin composition roots (an iOS app and a CLI).

Architecture

BTC/USD ticker — one core, two apps

Layered Swift packages under Modules/ (one package each), consumed by two roots:

Layer Package Role
Domain BTCPriceFoundation BTCPrice value type + BTCPriceLoader seam. Foundation-only — no UI or networking framework.
Infrastructure BTCPriceAPI HTTPClientProtocol seam + URLSessionHTTPClient adapter, Binance/Coinbase endpoints + mappers, RemoteBTCPriceLoader.
Orchestration BTCPriceComposition Fallback composite (Binance → Coinbase) + 1-second timeout decorator.
Presentation BTCPricePresentation MVVM TickerViewModel emitting AsyncStream<TickerViewState> (Foundation-only).
Root (iOS) BTCPriceApp SwiftUI TickerView + composition root.
Root (CLI) btc-cli Console renderer + composition root.

Every dependency points down to the framework-free domain core; only the two roots know concrete types. See docs/ for the light/dark diagrams.

Behaviour (BDD)

Story: A customer wants to watch the live BTC/USD price

Narrative #1 — Happy path
As an online customer
I want the app to show the latest BTC/USD price, refreshed every second
So I always see the current market price

  Given the customer has connectivity
   When the app (iOS) or CLI is running
   Then it displays the latest BTC/USD price, updating every second

Narrative #2 — Update failure
As a customer
I want to keep seeing the last known price and be told the update failed
So I understand the value may be stale

  Given the customer has already seen a price
   When an update fails OR takes longer than one second
   Then it keeps showing the last known price and its timestamp
    And shows "Failed to update value. Displaying last updated value from <date>"
    And hides that error as soon as an update succeeds again

Data sources

  • Primary: https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT
  • Fallback: https://api.coinbase.com/v2/prices/BTC-USD/spot (keyless; replaces the spec'd CryptoCompare endpoint, which now requires an API key)

Getting started

iOS app (Xcode)

  1. git clone https://github.com/anthony1810/BTCPrice.git && cd BTCPrice
  2. open BTCPriceApp/BTCPriceApp.xcodeproj — the committed project; no generation needed.
  3. Select an iOS 17+ simulator and press Run (⌘R).

The .xcodeproj is generated from BTCPriceApp/project.yml with XcodeGen and committed as the source of truth for reviewers. After editing the spec, regenerate with cd BTCPriceApp && xcodegen generate (brew install xcodegen).

CLI (btc-cli)

  1. open btc-cli/Package.swift — Xcode opens it as a Swift package.
  2. Choose the btc-cli scheme and press Run — or from a terminal: swift run --package-path btc-cli (Ctrl-C to stop).

All packages in one windowopen BTCPrice.xcworkspace for a single Xcode window with a scheme per package (app, CLI, each module, the E2E package). Use My Mac as the destination for the module/CLI/E2E schemes; only BTCPriceApp runs on an iOS simulator.

Tests — run a package's suite with swift test --package-path <path>, e.g. swift test --package-path Modules/BTCPriceAPI or swift test --package-path btc-cli. The live end-to-end tests are a separate package: swift test --package-path BTCPriceAPIEndToEndTests (needs an unrestricted network — api.binance.com geo-blocks some regions, including CI IPs).

CI

  • .github/workflows/test-modules.yml — on every push/PR, runs each module's swift test and the btc-cli tests in a matrix on Linux (official swift container). Running off Apple platforms actively proves the framework-free core is platform-agnostic. Deterministic — no network, no simulator.
  • .github/workflows/test-ios.yml — runs xcodebuild test for the iOS app on a simulator (macOS) with the Thread Sanitizer enabled.
  • The live Binance/Coinbase end-to-end tests live in their own package (BTCPriceAPIEndToEndTests/) and are not on the PR gate: api.binance.com returns HTTP 451 to CI's US-based IPs, so no hosted runner can reach it (and a public repo shouldn't self-host). Run them locally, or on-demand via the CI-Modules workflow's manual e2e job — where the Binance test auto-skips (CI env) and the Coinbase test runs.

License

MIT.

About

Live BTC/USD ticker (iOS + CLI) built with the Essential Developer method — TDD, modular SPM design, one framework-free core reused by two thin roots.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages