Skip to content

Path A quickstart

Path A is the Apple Native runtime path (DeploymentPath.appleNative). Core product flows run on Apple infrastructure: Sign in with Apple + SwiftData local persistence, with CloudKit enabled in production builds.

  • Auth: Sign in with Apple (AuthenticationServices)
  • Persistence: SwiftData (ModelContainer) for users, conversations, messages, and settings
  • Sync: CloudKit-backed SwiftData configuration in production
  • Payments: StoreKit 2 (native)
  • Analytics: TelemetryDeck (optional)
  • Explicit backend exceptions: AI chat (and feedback submission) call Worker endpoints
Terminal window
cd ios
xcodegen generate --spec project.yml
open SwiftLaunch.xcodeproj

In Xcode, select the SwiftLaunch target and set your Development Team under Signing & Capabilities. Make sure these capabilities are enabled:

  • Sign in with Apple
  • iCloud (with CloudKit container)

AppConfig.current resolves deployment path at runtime in ios/SwiftLaunch/Core/Config/AppConfig.swift. If nothing is overridden, it defaults to .appleNative.

// Resolution order in AppConfig.runtime():
// 1) E2E override
// 2) SWIFTLAUNCH_DEPLOYMENT_PATH env var
// 3) UserDefaults("deploymentPath")
// 4) Info.plist SWIFTLAUNCH_DEPLOYMENT_PATH
// 5) .appleNative fallback
let config = AppConfig.current
assert(config.deploymentPath == .appleNative)

Select an iOS 17+ simulator and hit Cmd+R. The app will:

  1. Show the onboarding flow (4 pages)
  2. Present Sign in with Apple on the login screen
  3. Drop you into the main Home + Explore + Settings tabs (Tab.home, Tab.explore, Tab.settings)
  4. Let you open AI chat from Home (feature card) or deep links that route to Home chat

AppleAuthService (ios/SwiftLaunch/Features/Auth/Services/AppleAuthService.swift) handles Sign in with Apple by:

  1. Presenting ASAuthorizationController via SwiftUI’s SignInWithAppleButton
  2. Receiving the Apple credential (user ID, identity token, authorization code)
  3. Verifying token/code presence before creating a session
  4. Storing credentials in Keychain via KeychainService
  5. Creating a local User object and restoring it via credential-state checks
ios/SwiftLaunch/Features/Auth/AuthState.swift
@Observable
final class AuthState {
var currentUser: User?
func signIn() async {
currentUser = try await service.signInWithApple()
}
func checkSession() async {
currentUser = await service.checkAuthStatus()
}
}

SwiftData models live in ios/SwiftLaunch/Core/Database/SwiftDataModels.swift:

  • SDUser — user profile with Apple user ID
  • SDConversation — chat conversation container
  • SDMessage — individual chat messages
  • SDUserSettings — user preferences

LaunchSwiftApp creates and injects the shared ModelContainer:

ios/SwiftLaunch/App/LaunchSwiftApp.swift
let schema = Schema(versionedSchema: SwiftLaunchSchemaV1.self)
let configuration = ModelConfiguration(
"SwiftLaunch",
schema: schema,
cloudKitDatabase: cloudKitDatabase(for: config)
)

Repository wiring happens in feature state objects when deploymentPath == .appleNative:

  • AuthState.configureLocalPersistenceIfNeeded(...) -> UserRepository
  • AIState.configureLocalPersistenceIfNeeded(...) -> ConversationRepository
  • SettingsState.configureLocalPersistenceIfNeeded(...) -> SettingsRepository

This gives local persistence for core auth-adjacent user data, chat history, and settings without requiring backend storage.

CloudKit capability is declared in:

  • ios/SwiftLaunch/SwiftLaunch.entitlements
  • ios/project.yml entitlements

At runtime, RootShellBootstrap.cloudKitDatabase(for:) enables CloudKit only when:

  • buildEnvironment == .production
  • AppConfig.cloudKitContainerIdentifier is present

Explicit backend exceptions (Path A is not backend-free for everything)

Section titled “Explicit backend exceptions (Path A is not backend-free for everything)”
  • AI chat transport still uses Worker endpoints (/api/chat route family). In Path A, chat transcripts are persisted locally with SwiftData, but message streaming still requires backend-authenticated request context on those routes.
  • Feedback submission posts to /api/feedback and has the same backend-auth requirement.

Important runtime qualifier for Path A:

  • Apple Native sign-in (AppleAuthService) satisfies app-shell auth gates (AppRouter.isAuthenticated) so users can navigate to AI/Feedback UI.
  • Backend middleware still enforces authenticated sessions on /api/chat* and /api/feedback (or a debug x-test-user-id header during E2E bypass), so Apple Native auth alone does not guarantee those requests will succeed in normal production runs.

You can deploy just the backend worker surface needed for these exceptions:

Terminal window
cd backend
npm install
npm run dev # local proxy on http://localhost:8787

Set your AI provider keys in backend/wrangler.toml or via wrangler secret put.

Consider moving to Path B when you need:

  • Custom server-side API endpoints
  • Email/password or social auth beyond Apple
  • Server-side session management
  • Rate limiting and usage tracking
  • A path toward multi-platform (Android, web)

The iOS app code is shared between both paths — switching is a configuration change, not a rewrite.