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.
What you get on Path A
Section titled “What you get on Path A”- 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
1. Generate and open the project
Section titled “1. Generate and open the project”cd iosxcodegen generate --spec project.ymlopen SwiftLaunch.xcodeproj2. Configure signing
Section titled “2. Configure signing”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)
3. Confirm runtime deployment path
Section titled “3. Confirm runtime deployment path”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 fallbacklet config = AppConfig.currentassert(config.deploymentPath == .appleNative)4. Run
Section titled “4. Run”Select an iOS 17+ simulator and hit Cmd+R. The app will:
- Show the onboarding flow (4 pages)
- Present Sign in with Apple on the login screen
- Drop you into the main Home + Explore + Settings tabs (
Tab.home,Tab.explore,Tab.settings) - Let you open AI chat from Home (feature card) or deep links that route to Home chat
How auth works
Section titled “How auth works”AppleAuthService (ios/SwiftLaunch/Features/Auth/Services/AppleAuthService.swift) handles Sign in with Apple by:
- Presenting
ASAuthorizationControllervia SwiftUI’sSignInWithAppleButton - Receiving the Apple credential (user ID, identity token, authorization code)
- Verifying token/code presence before creating a session
- Storing credentials in Keychain via
KeychainService - Creating a local
Userobject and restoring it via credential-state checks
@Observablefinal class AuthState { var currentUser: User?
func signIn() async { currentUser = try await service.signInWithApple() }
func checkSession() async { currentUser = await service.checkAuthStatus() }}How local persistence is wired
Section titled “How local persistence is wired”SwiftData models live in ios/SwiftLaunch/Core/Database/SwiftDataModels.swift:
SDUser— user profile with Apple user IDSDConversation— chat conversation containerSDMessage— individual chat messagesSDUserSettings— user preferences
LaunchSwiftApp creates and injects the shared ModelContainer:
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(...)->UserRepositoryAIState.configureLocalPersistenceIfNeeded(...)->ConversationRepositorySettingsState.configureLocalPersistenceIfNeeded(...)->SettingsRepository
This gives local persistence for core auth-adjacent user data, chat history, and settings without requiring backend storage.
CloudKit behavior
Section titled “CloudKit behavior”CloudKit capability is declared in:
ios/SwiftLaunch/SwiftLaunch.entitlementsios/project.ymlentitlements
At runtime, RootShellBootstrap.cloudKitDatabase(for:) enables CloudKit only when:
buildEnvironment == .productionAppConfig.cloudKitContainerIdentifieris 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/chatroute 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/feedbackand 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 debugx-test-user-idheader 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:
cd backendnpm installnpm run dev # local proxy on http://localhost:8787Set your AI provider keys in backend/wrangler.toml or via wrangler secret put.
When to upgrade to Path B
Section titled “When to upgrade to Path B”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.