Skip to content

[ALFMOB-421] Add Alfie Companion app, retire DebugMenu, wire config override chain#81

Draft
amccall-mindera wants to merge 5 commits into
mainfrom
feat/ALFMOB-421-ios-debug-companion
Draft

[ALFMOB-421] Add Alfie Companion app, retire DebugMenu, wire config override chain#81
amccall-mindera wants to merge 5 commits into
mainfrom
feat/ALFMOB-421-ios-debug-companion

Conversation

@amccall-mindera

@amccall-mindera amccall-mindera commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

ALFMOB-421 — iOS Debug Companion App v1

Implements all agent-doable and Xcode-UI steps. Remaining prerequisite: run ./Alfie/scripts/verify.sh (requires Xcode) and complete TestFlight distribution (step 8) + device end-to-end validation (step 9.2).

What changed

New — shared storage primitives (SPM, no pbxproj)

  • AlfieKit/Sources/Model/Services/Persistence/AppGroupUserDefaults.swiftUserDefaultsProtocol wrapper around UserDefaults(suiteName:); falls back to .standard if suite unavailable.
  • AlfieKit/Sources/Core/Services/Configuration/Providers/DebugAppConfigurationProvider.swift — reads App Group suite group.com.mindera.alfie.shared at position 0 of the config chain; returns nil when key absent so the chain falls through to Firebase → Local → defaults.

Modified — Alfie/Alfie/Service/ServiceProvider.swift

  • sharedDefaults (AppGroupUserDefaults) passed only to ApiEndpointService — companion endpoint override reads from the App Group. userDefaults = .standard kept for BagService/WishlistService to avoid silently relocating persisted data.
  • #if DEBUG DebugConfigurationProvider.shared replaced by DebugAppConfigurationProvider() at position 0 unconditionally (no-op when App Group suite is empty).

Removed — DebugMenu SPM module

  • Deleted AlfieKit/Sources/DebugMenu/ + DebugConfigurationProvider.swift / DebugConfigurationProviderProtocol.swift.
  • Package.swift: removed DebugMenu product, target, Home dep on it, DebugMenuTests target; added Mocks as direct Home dep (was transitive via DebugMenu → Mocks; needed for HomeView #Preview).
  • HomeViewModel: removed import DebugMenu, didTapDebugMenu(), fullScreenCover, dead configurationService/apiEndpointService properties.
  • HomeDependencyContainer slimmed to sessionService only; AppFeatureViewModel, HomeViewModelProtocol, MockHomeViewModel, Home+Toolbar, ToolbarItemProvider updated accordingly.

New — unit tests

  • AlfieKit/Tests/CoreTests/ServiceTests/DebugAppConfigurationProviderTests.swift — override-wins and fall-through paths.
  • AlfieKit/Tests/CoreTests/ServiceTests/AppGroupUserDefaultsTests.swift — read/write/remove round-trips.

New — Alfie Companion target + UI (Xcode steps)

  • Alfie/Alfie Companion/ — new iOS app target, bundle id com.mindera.alfie.companion, same signing team.
  • Alfie/Alfie/Alfie.entitlementscom.apple.security.application-groups added for group.com.mindera.alfie.shared.
  • Alfie/Alfie Companion/Alfie Companion.entitlements — same App Group capability on companion side.
  • Bundle id collapsed: Debug config now uses com.mindera.alfie (same as Release); Configuration/Debug/GoogleService-Info.plist removed (main app uses single Firebase app).
  • Companion UI: CompanionStore.swift (ObservableObject over App Group suite), FlagsView.swift (known + custom flag overrides), EndpointView.swift (endpoint picker + custom URL), InspectorView.swift (Firebase RC + local_config.json + App Group browser + Reset All).
  • Alfie_CompanionApp.swift calls FirebaseApp.configure() on launch; ContentView.swift tabs into the three views.
  • local_config.json added to companion target via pbxproj build file exception.
  • Core and Model SPM package products linked to companion target.

Docs + gitignore

  • Removed stale DebugMenu references from Docs/Testing.md, Docs/Architecture.md, Docs/QuickReference.md, README.md.
  • Alfie/Alfie Companion/GoogleService-Info.plist added to .gitignore (same pattern as main-app Firebase plists managed by git-secret).

Key invariants for reviewer

  1. ServiceProvider.swift: sharedDefaults flows only to ApiEndpointServiceBagService/WishlistService at ~lines 98–109 still use self.userDefaults (.standard).
  2. ConfigurationKey.allCases used in CompanionStore and FlagsView — this works because ConfigurationKey has an explicit allCases that enumerates only the named cases (excluding .custom(_)), which is exactly the right scope for Reset All and the flags list.
  3. endpointKey is private in CompanionStore.swift — not accidentally exported.

Items requiring human verification

  • verify.sh — mandatory gate per CLAUDE.md. Must pass before flipping to ready.
  • import Firebase in Alfie_CompanionApp.swift — companion links Core (which depends on FirebaseAnalytics, FirebaseCrashlytics, FirebaseRemoteConfig). Verify that the Firebase umbrella module is available at compile time; if not, add FirebaseCore as an explicit package dep in Xcode.
  • GoogleService-Info.plist (gitignored) — run git secret reveal or copy the companion plist into Alfie/Alfie Companion/ before building.
  • TestFlight distribution (step 8) — create ASC record for com.mindera.alfie.companion, internal eng/QA group; archive and upload.
  • Device end-to-end validation (step 9.2) — App Group round-trip requires both apps installed on a real device with release signing.

🤖 Generated with Claude Code

amccall-mindera and others added 5 commits June 16, 2026 17:00
- Add AppGroupUserDefaults (App Group suite wrapper, UserDefaultsProtocol conformance)
- Add DebugAppConfigurationProvider (reads group.com.mindera.alfie.shared, position-0 in chain)
- Wire ServiceProvider: sharedDefaults passed only to ApiEndpointService; Bag/Wishlist keep standard defaults
- Remove DebugConfigurationProvider and #if DEBUG chain insertion
- Delete DebugMenu SPM module and DebugMenuTests (including style-guide/demo gallery)
- Remove DebugConfigurationProviderProtocol and FeatureToggleViewModelProtocol (now dead)
- Clean HomeViewModel, HomeViewModelProtocol, MockHomeViewModel, Home+Toolbar of debug menu wiring
- Slim HomeDependencyContainer to sessionService-only; update AppFeatureViewModel callsite
- Remove ToolbarItemProvider.debugMenuItem
- Add DebugAppConfigurationProviderTests and AppGroupUserDefaultsTests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follows the same pattern as the main-app Firebase plists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Collapse main app bundle ID to com.mindera.alfie for both Debug and Release (step 4)
- Remove Debug GoogleService-Info.plist; main app now uses single Firebase app (step 4)
- Add com.apple.security.application-groups to Alfie.entitlements (step 5)
- Create Alfie Companion target (com.mindera.alfie.companion) with entitlements,
  GoogleService-Info.plist, and Xcode-generated test targets (step 5)
- Implement companion UI: FlagsView (known + custom flags), EndpointView (picker +
  custom URL), InspectorView (Firebase RC + local_config.json + App Group browser),
  CompanionStore (ObservableObject wrapping App Group UserDefaults), Reset All (step 6)
- Firebase configured on companion launch via FirebaseApp.configure()

Pending: link Model and FirebaseRemoteConfig package products to Alfie Companion
target in Xcode (packageProductDependencies empty — step 5.4 incomplete)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bility

- Xcode: add Core and Model packageProductDependencies to Alfie Companion
  target (fixes "packageProductDependencies empty" noted in prior commit)
- CompanionStore: add missing `import Combine` (needed for @published /
  ObservableObject even if available transitively via Model)
- Make endpointKey file-private (was module-internal with no reason to be)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@amccall-mindera amccall-mindera changed the title [ALFMOB-421] Retire DebugMenu and wire DebugAppConfigurationProvider into the config chain [ALFMOB-421] Add Alfie Companion app, retire DebugMenu, wire config override chain Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant