Skip to content

Latest commit

 

History

History
211 lines (170 loc) · 4.57 KB

File metadata and controls

211 lines (170 loc) · 4.57 KB

04 — Architecture and Stack

Last updated: 2026-06-05

Recommended stack

iOS

  • SwiftUI
  • SwiftData
  • Swift Concurrency
  • XCTest
  • SF Symbols

Backend

  • Supabase Postgres
  • Supabase Edge Functions
  • Bundled local JSON seed fixtures

Runtime AI

None for V0.

AI tools were used during development, but not inside the core user flow. The comparison logic should be deterministic and testable.

High-level architecture

Open.Basket iOS App
  ├── SwiftUI screens
  ├── SwiftData local basket persistence
  ├── Domain services
  │   ├── BasketComparisonEngine
  │   ├── RecommendationPolicy
  │   ├── CoverageCalculator
  │   ├── MatchConfidenceCalculator
  │   ├── SavingsDriverCalculator
  │   └── StalenessPolicy
  ├── Data repositories
  │   ├── ProductRepository protocol
  │   ├── OfferRepository protocol
  │   ├── LocalJSONProductRepository (tests/fixtures)
  │   ├── LocalJSONOfferRepository (tests/fixtures)
  │   └── Supabase catalogue repositories
  └── Resources
      ├── catalogue.demo.json
      └── offers.demo.json

Supabase read-only Edge Functions
  ├── regions
  ├── stores
  ├── canonical_products
  ├── retailer_products
  ├── offers
  └── price_snapshots

Why remote catalogue first

The current submission build is based on the deployed Sydney catalogue service. The reviewer should not need credentials, private retailer tokens, runtime scraping, or local seed toggles.

Build order:

  1. Seed fixtures validate.
  2. Domain tests pass.
  3. UI is complete.
  4. Supabase integration is added behind protocols.
  5. Remote failures surface clearly instead of silently substituting fixture data.

Suggested Swift structure

OpenBasket/
  App/
    OpenBasketApp.swift
    AppRouter.swift

  DesignSystem/
    OBColor.swift
    OBTypography.swift
    OBSpacing.swift
    OBRadius.swift
    OBButton.swift
    OBCard.swift
    OBBadge.swift
    OBLogo.swift

  Features/
    Welcome/
    RegionSetup/
    BasketBuilder/
    BasketReview/
    Recommendation/
    ItemBreakdown/
    MissingItems/
    Methodology/

  Domain/
    Models/
      Region.swift
      Store.swift
      CanonicalProduct.swift
      RetailerProduct.swift
      Offer.swift
      Basket.swift
      BasketItem.swift
      ComparisonResult.swift
      RecommendationState.swift
    Services/
      BasketComparisonEngine.swift
      RecommendationPolicy.swift
      CoverageCalculator.swift
      MatchConfidenceCalculator.swift
      SavingsDriverCalculator.swift
      StalenessPolicy.swift
    Protocols/
      ProductRepository.swift
      OfferRepository.swift

  Data/
    Local/
      LocalJSONProductRepository.swift
      LocalJSONOfferRepository.swift
      SeedDataLoader.swift
    Supabase/
      SupabaseRepositories.swift
    Persistence/
      BasketEntity.swift
      BasketItemEntity.swift
      BasketStore.swift

  Resources/
    catalogue.demo.json
    offers.demo.json

OpenBasketTests/
  BasketComparisonEngineTests.swift
  RecommendationPolicyTests.swift
  CoverageCalculatorTests.swift
  MatchConfidenceCalculatorTests.swift
  SavingsDriverCalculatorTests.swift
  StalenessPolicyTests.swift

Repository abstraction

Use protocols so data source changes do not affect views.

protocol ProductRepository {
    func fetchCatalogue(regionId: String) async throws -> CataloguePayload
}

protocol OfferRepository {
    func fetchCurrentOffers(regionId: String) async throws -> [Offer]
}

Comparison engine contract

Input:

  • selected region,
  • selected stores,
  • basket items,
  • canonical catalogue,
  • retailer products,
  • current offers.

Output:

  • totals by store,
  • recommendation state,
  • estimated saving,
  • confidence,
  • coverage,
  • missing items,
  • item-level comparisons,
  • savings drivers,
  • warnings.

Error handling

Important states:

  • remote data loaded,
  • remote failed,
  • stale data,
  • missing products,
  • low coverage,
  • no basket items.

Security

  • Do not commit .env.
  • Do not commit Supabase service role key.
  • iOS app may use Supabase anonymous key only if read policies are safe.
  • Remote catalogue calls must fail clearly if unavailable; do not claim local JSON as the submission fallback.
  • Do not use private retailer tokens.
  • Do not scrape at runtime.

Observability for future production

Not required for V0, but document future approach:

  • data ingestion success/failure logs,
  • stale data alerts,
  • unmatched product queue,
  • recommendation confidence distribution,
  • crash/error reporting.