Skip to main content
The full config schema is machine-readable in template.manifest.json (repo root) under configSchema. The keys below are the authoritative source consumed by the app and the scripts/appstore-43-audit.sh gate.

Config Keys

KeyTypeRequiredSecretPurpose
SUPABASE_URLurlYesNoSupabase project URL (auth + backend)
SUPABASE_ANON_KEYstringYesYesSupabase anonymous key
REVENUECAT_API_KEYstringNoYesRevenueCat public SDK key
RC_ENTITLEMENT_IDstringNoNoRevenueCat entitlement identifier
PROXY_BASE_URLurlNoNoAI proxy base URL; EchoLLMClient is used when empty
PROXY_PATHstringNoNoAI proxy path
ONESIGNAL_APP_IDstringNoYesOneSignal push app ID

Configuration Files

Config/Secrets.xcconfig

Location: Config/Secrets.xcconfig (gitignored)
This file contains API keys and secrets. Never commit it to git.
Template: Config/Secrets.example.xcconfig (copy this to get started)
# Supabase Configuration
SUPABASE_URL = https://YOUR-PROJECT-REF.supabase.co
SUPABASE_ANON_KEY = YOUR_PUBLIC_ANON_KEY

# Google Sign In (Optional)
# GOOGLE_CLIENT_ID = YOUR_IOS_CLIENT_ID.apps.googleusercontent.com

# RevenueCat Configuration
REVENUECAT_API_KEY = YOUR_RC_KEY
RC_ENTITLEMENT_ID = pro

# AI Proxy Configuration (Supabase Edge Function)
PROXY_BASE_URL = https://YOUR-PROJECT-REF.supabase.co/functions/v1
PROXY_PATH = /ai

# OneSignal Push Notifications (Optional)
ONESIGNAL_APP_ID = YOUR_ONESIGNAL_APP_ID
Generate Configuration.swift:
# After filling in Config/Secrets.xcconfig, run:
bash scripts/update-config.sh
This regenerates SwiftAIBoilerplatePro/Generated/Configuration.swift (the AppConfiguration enum) with your values. Keys whose value still contains a YOUR placeholder are written as a comment and treated as “not configured” at runtime.

Config/App.xcconfig

Location: Config/App.xcconfig General app-level build settings, including the single source of truth for app identity. Every target’s bundle ID and the app-group entitlements derive from APP_BUNDLE_ID.
PRODUCT_NAME = $(TARGET_NAME)

# Single source of truth for app identity. Test, UI-test, and extension
# bundle IDs plus the app-group entitlements all derive from this value.
APP_BUNDLE_ID = com.berkin.SwiftAIBoilerplatePro
SWIFT_VERSION = 6.0
IPHONEOS_DEPLOYMENT_TARGET = 17.0
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor

# Include secrets if present (local only)
#include? "Config/Secrets.xcconfig"

Environment Variables

Set in Xcode Scheme → Edit Scheme → Run → Arguments → Environment Variables.
VariableReads inDefault behaviorPurpose
AUTH_BYPASSDEBUG onlyMock used unless set to 0Set 0 to use the real Supabase auth client (and MockPaymentsClient is also swapped for RevenueCatClient)
DIAGNOSTICS_ENABLEDRELEASEfalseSet true to enable diagnostics in Release
CRASHLYTICS_ENABLEDRELEASEfalseSet true to enable Firebase Crashlytics in Release
CHAT_SYNC_ENABLEDRELEASEfalseSet true to enable Supabase chat history sync in Release
PROXY_DEFAULT_HEADERSAnynoneOptional JSON string of extra headers for the AI proxy
The mock-vs-real auth decision is made in CompositionRoot.swift from AUTH_BYPASS, not in FeatureFlags. In RELEASE the app always uses real auth; the MockAuthClient is DEBUG-only.

Feature Flags

Location: SwiftAIBoilerplatePro/Composition/FeatureFlags.swift
import Foundation

/// Feature flags for optional capabilities
public struct FeatureFlags {
    /// Master switch for diagnostics (MetricKit always enabled)
    public static var diagnosticsEnabled: Bool {
        #if DEBUG
        return true
        #else
        return ProcessInfo.processInfo.environment["DIAGNOSTICS_ENABLED"] == "true"
        #endif
    }

    /// Enable Firebase Crashlytics
    public static var crashlyticsEnabled: Bool {
        #if DEBUG
        return false // Off by default in debug
        #else
        return ProcessInfo.processInfo.environment["CRASHLYTICS_ENABLED"] == "true"
        #endif
    }

    /// Enable Supabase chat history sync
    /// When false (default), chat data stays local-only in SwiftData.
    /// See docs/CHAT_SYNC_SETUP.md for setup instructions.
    public static var chatSyncEnabled: Bool {
        #if DEBUG
        return false // Off by default in debug
        #else
        return ProcessInfo.processInfo.environment["CHAT_SYNC_ENABLED"] == "true"
        #endif
    }
}

Backend Configuration

Supabase

SUPABASE_URL = https://dev-project.supabase.co
SUPABASE_ANON_KEY = dev_anon_key
PROXY_BASE_URL = https://dev-project.supabase.co/functions/v1
Get credentials: Supabase Dashboard → Project Settings → API

OpenRouter

Set as Supabase secret:
supabase secrets set OPENROUTER_API_KEY=sk-or-v1-YOUR_KEY
Get key: OpenRouter Dashboard

RevenueCat

REVENUECAT_API_KEY = appl_YOUR_PUBLIC_KEY
RC_ENTITLEMENT_ID = pro
Get key: RevenueCat Dashboard → Settings → API Keys

CompositionRoot Configuration

Location: SwiftAIBoilerplatePro/Composition/CompositionRoot.swift The DI container reads configuration from the generated AppConfiguration enum and chooses real or mock implementations. The LLM client is selected by createLLMClient(...) in LLMClientFactory.swift:
// Auth: real Supabase + Apple + Email, or MockAuthClient in DEBUG (CompositionRoot.swift)
#if DEBUG
let shouldUseMock = ProcessInfo.processInfo.environment["AUTH_BYPASS"] != "0"
if shouldUseMock {
    self.sessionManager = Auth.MockAuthClient()
} else {
    self.sessionManager = SessionManagerWrapper(/* Supabase SessionManager */)
}
#endif

// LLM: ProxyLLMClient when PROXY_BASE_URL is real, EchoLLMClient otherwise (LLMClientFactory.swift)
guard let baseURL = URL(string: AppConfiguration.PROXY_BASE_URL),
      !AppConfiguration.PROXY_BASE_URL.contains("YOUR"),
      !AppConfiguration.PROXY_BASE_URL.contains("placeholder") else {
    return EchoLLMClient()
}
return ProxyLLMClient(baseURL: baseURL, httpClient: httpClient, path: AppConfiguration.PROXY_PATH)
When PROXY_BASE_URL is unconfigured the app also wires an UnconfiguredHTTPClient instead of a real URLSessionHTTPClient, so unconfigured backends fail explicitly rather than calling a placeholder host.

Xcode Build Configuration

Debug vs Release

Debug (default):
  • Mock auth enabled by default
  • Detailed logging
  • Crashlytics disabled
  • No optimization
Release:
  • Real auth required
  • Production logging
  • Crashlytics opt-in (requires CRASHLYTICS_ENABLED=true and a GoogleService-Info.plist)
  • Full optimization
Switch configuration:
Product → Scheme → Edit Scheme → Run → Build Configuration

Quick Reference

  1. Edit Scheme → Run → Environment Variables
  2. Set AUTH_BYPASS = 0
  3. Fill in Config/Secrets.xcconfig with real Supabase credentials
  4. Run bash scripts/update-config.sh
  5. Clean and rebuild
  1. Run SQL migration
  2. Set chatSyncEnabled = true in FeatureFlags
  3. Uncomment Supabase repositories
  4. Wire up in CompositionRoot
  1. Update Config/Secrets.xcconfig with production URLs/keys
  2. Run bash scripts/update-config.sh to regenerate Configuration.swift
  3. Verify in RELEASE build configuration
  4. Archive and test

Installation

Initial configuration

Supabase Setup

Backend configuration

Building Guide

Production configuration

Architecture

How config flows through app