Last updated: 2026-06-12
Open.Basket is a native SwiftUI iOS app for Project B - New Product Feature / Brief 3A - Smart Shopping Destination.
It helps a user answer one practical question: where should I shop this week for my usual grocery basket? The app compares matched basket totals across Coles and Woolworths price contexts, then explains the recommendation with estimated savings, savings drivers, matched coverage, confidence, missing items, source type, and last checked dates.
- TestFlight: https://testflight.apple.com/join/dwU2gAUA
- Written walkthrough:
docs/10_SUBMISSION_WALKTHROUGH.md - Privacy policy: https://stickkb.github.io/OpenBasket/privacy.html
- Support page: https://stickkb.github.io/OpenBasket/support.html
- App display name:
Open.Basket - Version/build:
1.1 (21) - Bundle ID:
com.stickkb.OpenBasket - Target: iOS 17+
- Default external TestFlight mode: deployed read-only Sydney catalogue service, no sign-in, no tracking, no analytics SDK, no account flow, no payments, and no location permission.
- Optional receipt scanning: on-device VisionKit/Vision OCR only. Receipt text and selected line items are saved locally with SwiftData when the tester chooses to import them.
- Product images: external URL thumbnails display when the deployed catalogue returns image URLs; neutral item markers appear only when an image URL is missing or fails to load.
- Install the TestFlight build or run the app from Xcode.
- Launch Open.Basket.
- Tap
Try demo basket. - Pick a basket template or build a basket from catalogue search.
- Review quantities and tap
Compare stores. - Read the recommendation, matched totals, savings drivers, confidence, coverage, missing items, source, and last checked date.
- Open
Item breakdown,Missing item review, andMethodologyfor the trust details. - Optionally scan or paste receipt text to update the recurring basket locally.
Open.Basket is decision-first rather than catalogue-first. Grocery catalogues are large and messy, so the app does not ask reviewers to manually inspect thousands of products before seeing value. It starts from recurring baskets, demo templates, or receipt import, then turns comparison data into a clear weekly recommendation.
Key product choices:
- Show estimated savings as "about $X" rather than fake precision.
- Use "too close to call" when the saving is below the switching threshold.
- Exclude missing items from matched totals and show them separately so one retailer does not look cheaper unfairly.
- Always show Sydney Metro/postcode context, store pair, source type, last checked date, coverage, confidence, and missing items.
- Use catalogue-provided external image URLs only; the app does not download, bundle, or rehost retailer product images.
- Keep Coles/Woolworths data behind a repository boundary so Supabase Edge Functions, seed fixtures, or a future licensed feed can be swapped without changing SwiftUI views.
The app is built with:
- SwiftUI for the native iOS interface.
- SwiftData for local basket and receipt-log persistence.
- Swift Concurrency for repository loading.
- XCTest for domain, repository, persistence, and app-flow tests.
- Read-only Supabase Edge Functions behind repository protocols for the submission catalogue path.
- Bundled JSON seed fixtures for deterministic tests and validation tooling.
- Supabase Postgres projections behind Edge Functions for live catalogue validation.
- Python ingestion scripts and GitHub Actions for server-side catalogue and specials refresh experiments.
Business logic lives in domain services and ShoppingFlowModel, not in SwiftUI view bodies. The comparison engine is deterministic and covered by tests for recommendation state, savings drivers, missing items, stale data, coverage, confidence, and close-call behaviour.
The external TestFlight build is safe by default: it calls the deployed read-only Supabase Edge Functions for Sydney Metro catalogue data and does not embed Supabase credentials in the app.
The repo still includes seed fixtures used by tests and data-validation tooling:
- 1 region: Sydney Metro.
- 2 paired demo stores.
- 50 canonical products.
- 100 retailer product matches.
- 97 offer rows.
- 2 demo baskets.
The latest repo iteration uses a production-shaped live-data lane for the review build:
- Read-only Supabase Edge Functions for catalogue search, offers, source status, and source freshness.
- Compact Postgres projections for retailer observations, catalogue mirror rows, source runs, and current offers.
- Local browser ingestion scripts for developer-run Coles/Woolworths exports.
- Quality gates that filter marketplace/non-core rows, preserve package sizes, reject weak product pairings, and keep secrets out of the iOS app.
- GitHub Actions for bounded scheduled/manual ingestion, with cost and database-size guards.
The iOS app does not embed private retailer tokens, service-role keys, database passwords, browser cookies, or scraper credentials.
OpenBasket/
App/ App shell, navigation, repository factory
DesignSystem/ Open.Basket colours, typography, logo, spacing, components
Domain/ Models, protocols, comparison and receipt services
Data/
Local/ Seed-fixture repositories for tests and validation tooling
Persistence/ SwiftData basket and receipt storage
Supabase/ URLSession-backed read-only remote repositories
Features/
Welcome/ First-run and resume entry points
Shopping/ Basket builder, comparison, result, methodology
Receipts/ Local receipt scan/text import flow
Resources/ Seed fixture JSON, privacy manifest, app assets
OpenBasketTests/ Domain, data, persistence, and app-flow tests
scripts/ Seed validation and live-ingestion tooling
supabase/ Migrations and read-only Edge Functions
site/ GitHub Pages privacy/support site
docs/ Submission and architecture notes
Open OpenBasket.xcodeproj in Xcode, or run:
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild test -project OpenBasket.xcodeproj -scheme OpenBasket -destination 'platform=iOS Simulator,name=iPhone 17'Validate the seed fixture data:
python3 scripts/validate_seed_data.pyRun ingestion unit tests:
python3 -m unittest scripts/test_ingest_seed_data.py scripts/test_live_ingestion.pyOptional live-ingestion fixture smoke test:
python3 scripts/live_ingestion/run_weekly.py --source fixture --postcode 2000 --limit 2 --dry-run-costThe local machine may print a provisioning warning for /Users/nding/Library/MobileDevice/Provisioning Profiles/test.touch; it is unrelated to this app and does not fail the build.
docs/10_SUBMISSION_WALKTHROUGH.md- written walkthrough for the reviewer.docs/14_TESTFLIGHT_REVIEW_NOTES.md- App Review/TestFlight notes.docs/04_ARCHITECTURE_STACK.md- architecture and stack.docs/05_DATA_STRATEGY_SCHEMA.md- data model and source strategy.docs/13_LIVE_DATA_SOURCE_STRATEGY.md- production data path.docs/14_CATALOGUE_DATA_REPAIR.md- latest catalogue repair and pairing guardrails.
- Current comparisons are estimates for matched items, not live shelf-stock guarantees.
- Prices may vary by store, postcode, channel, and time.
- Production-scale catalogue coverage still needs either a licensed/official feed or a more robust approved ingestion pipeline.
- Product matching needs a review queue before this could become a commercial product.
- Receipt import is useful for recurring-basket setup, but it is local-only and intentionally conservative.
- No checkout/cart integration, loyalty integration, push notifications, or user accounts are included.
Given more time, I would add a manual match-review console, stronger catalogue freshness monitoring, user brand/substitution preferences, better receipt correction UX, weekly comparison history, and a licensed data-source path for broader regions and retailers.