Last updated: 2026-06-05
- SwiftUI
- SwiftData
- Swift Concurrency
- XCTest
- SF Symbols
- Supabase Postgres
- Supabase Edge Functions
- Bundled local JSON seed fixtures
None for V0.
AI tools were used during development, but not inside the core user flow. The comparison logic should be deterministic and testable.
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
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:
- Seed fixtures validate.
- Domain tests pass.
- UI is complete.
- Supabase integration is added behind protocols.
- Remote failures surface clearly instead of silently substituting fixture data.
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
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]
}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.
Important states:
- remote data loaded,
- remote failed,
- stale data,
- missing products,
- low coverage,
- no basket items.
- 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.
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.