# psiphon-inc/psiphon-ios-vpn architecture

> Architecture diagram of the GitHub repository psiphon-inc/psiphon-ios-vpn, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-22). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/psiphon-inc/psiphon-ios-vpn
- Repository: https://github.com/psiphon-inc/psiphon-ios-vpn

## Overview

1. **Overall shape**
   Psiphon iOS VPN is a mixed Swift/Objective-C iOS codebase built around three runtime pieces: the main app, a NetworkExtension packet-tunnel target, and shared libraries/data models used by both. The app is a VPN client UI plus subscription/PsiCash commerce flows; the extension is the actual tunnel process.

2. **Main application target**
   The `Psiphon/` directory contains the app shell, screens, reducers, custom views, and launch/onboarding flows. `AppDelegate`, `SwiftDelegate`, `MainViewController`, `RootContainerController`, and the `ViewControllers/` tree drive the user-facing navigation; `View/` and `ViewControllers/Views/` hold the custom animated UI used on the home, region, onboarding, subscription, and PsiCash screens.

3. **State and logic layer**
   The app’s behavior is organized around reducer/store-style state management rather than ad hoc view logic. You can see this in `MainViewReducer`, `VPNStateReducer`, `PsiCashReducer`, `AppReceiptReducer`, `FeedbackReducer`, and the `PsiApi/Sources/PsiApi/Store/` package (`Store`, `Effect`, `SerialEffect`, `MainState`). UI reacts to state changes through ReactiveObjC and custom reactive helpers.

4. **Shared domain package**
   `PsiApi/` is a Swift package that packages reusable domain logic: HTTP request modeling, localization, logging, IPC notifications, platform abstractions, and a shared store architecture. It also contains the reusable App Store IAP and PsiCash client models, so the app target is not the only consumer of purchase and status logic.

5. **VPN tunnel boundary**
   `PsiphonVPN/` is the packet tunnel extension target. `PacketTunnelProvider` and `BasePacketTunnelProvider` are the entrypoint for the OS-managed VPN process, and they bridge to the prebuilt `PsiphonTunnel.xcframework`, which contains the platform-specific tunnel engine and reachability/default-route helpers.

6. **Host app ↔ extension communication**
   The host app and tunnel extension share state through app-group-backed storage and notification plumbing rather than direct in-process calls. Shared Core Data (`Shared/CoreData/SharedModel.xcdatamodeld` and `PsiApi/Sources/.../SharedCoreData`) plus keyed stores in `PsiphonVPN/LocalDatastore` and shared `NSUserDefaults` wrappers carry authorization, configuration, and status between processes; `Shared/Notifier` and IPC notification helpers provide signaling.

7. **Configuration and embedded runtime inputs**
   The tunnel process depends on static configuration artifacts checked into the repo: `Shared/psiphon_config.stub` and `Shared/embedded_server_entries.stub` are runtime inputs for network parameters and server discovery. The app also bundles `Psiphon/InAppSettings.bundle` for user-configurable settings and reads localized strings from `Shared/Strings/` and `StoreAssets/`.

8. **Commerce and monetization flows**
   The repo has two distinct payment-related subsystems. `PsiApi/Sources/AppStoreIAP/` manages App Store receipt/payment queue/subscription validation, while `Psiphon/PsiCash/` plus `PsiApi/Sources/PsiCashClient/` wrap the `PsiCashLib.xcframework` binary for PsiCash account/balance/speed-boost purchasing. UI for these flows lives in dedicated view controllers and PsiCash-specific views.

9. **Shared services and utilities**
   `Shared/` contains cross-cutting infrastructure used by both app and extension: logging, profiling, jetsam tracking, file utilities, rotating log files, localization helpers, and app metadata wrappers. The `asn1c/` sources are included for receipt parsing, and `Shared/External/c-timestamp` plus `Utilities/` provide common low-level primitives.

10. **Dependencies, packaging, and build tooling**
   The project mixes source dependencies and prebuilt binaries: CocoaPods brings in `ReactiveObjC`, `InAppSettingsKit`, `MBProgressHUD`, and `EFCountingLabel`, while `PsiphonTunnel.xcframework` and `Frameworks/PsiCashLib.xcframework` are vendored binaries. Build/release automation is handled by `build.sh`, Fastlane, GitHub Actions, localization scripts, and several SwiftPM utility/dev tools under `Utilities/`, `Testing/`, and `dev/`.

Main entry points: [`Psiphon/MainViewReducer.swift`](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/MainViewReducer.swift) (App state), [`Psiphon/ViewControllers/MainViewController.m`](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/ViewControllers/MainViewController.m) (Main flow), [`PsiphonVPN/PacketTunnelProvider.m`](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/PacketTunnelProvider.m) (VPN extension), [`PsiphonVPN/LocalDatastore/ExtensionDataStore.m`](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/LocalDatastore/ExtensionDataStore.m) (Extension store)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["Main app"]
  node_psiphon_app_delegate["App entry<br/>app lifecycle<br/>[AppDelegate.m]"]
  node_psiphon_swift_delegate["Swift delegate<br/>startup glue"]
  node_psiphon_root_ui["Root UI<br/>navigation shell"]
  node_psiphon_main_flow["Main flow<br/>home/onboarding"]
  node_psiphon_views["Custom views<br/>ui components"]
  node_psiphon_subscriptions["Subscriptions<br/>iap UI"]
  node_psiphon_psicash_ui["PsiCash UI<br/>commerce UI"]
  node_psiphon_state["App state<br/>reducers/state"]
end

subgraph group_shared["Shared code"]
  node_psiphon_shared_core["Shared core<br/>shared runtime<br/>[Notifier.swift]"]
  node_psiphon_shared_coredata[("Shared Core Data<br/>app-group db<br/>[contents]")]
  node_psiphon_shared_strings["Strings<br/>localization assets"]
  node_psiphon_shared_config["Runtime config<br/>embedded inputs"]
end

subgraph group_vpn["VPN target"]
  node_psiphon_vpn_extension["VPN extension<br/>packet tunnel"]
  node_psiphon_vpn_datastore["Extension store<br/>extension datastore"]
end

subgraph group_packages["Swift packages"]
  node_psiapi_store["Store core<br/>swift store<br/>[Store.swift]"]
  node_psiapi_iap["App Store IAP<br/>purchase domain<br/>[IAPReducer.swift]"]
  node_psiapi_psicash["PsiCash client<br/>purchase domain<br/>[PsiCashState.swift]"]
end

subgraph group_deps["Vendored deps"]
  node_psiphon_tunnel_framework{{"Tunnel engine<br/>vendored framework<br/>[PsiphonTunnel]"}}
  node_psicash_framework{{"PsiCash lib<br/>vendored framework<br/>[PsiCashLib]"}}
end

node_psiphon_app_delegate -->|"hands off to"| node_psiphon_swift_delegate
node_psiphon_app_delegate -->|"roots"| node_psiphon_root_ui
node_psiphon_root_ui -->|"hosts"| node_psiphon_main_flow
node_psiphon_main_flow -->|"renders with"| node_psiphon_views
node_psiphon_main_flow -->|"drives"| node_psiphon_state
node_psiphon_state -->|"built on"| node_psiapi_store
node_psiphon_state -->|"consumes"| node_psiapi_iap
node_psiphon_state -->|"consumes"| node_psiapi_psicash
node_psiphon_subscriptions -->|"uses"| node_psiapi_iap
node_psiphon_psicash_ui -->|"uses"| node_psiapi_psicash
node_psiphon_psicash_ui -->|"bridges to"| node_psicash_framework
node_psiphon_shared_core -->|"persists"| node_psiphon_shared_coredata
node_psiphon_vpn_extension -->|"reads/writes"| node_psiphon_vpn_datastore
node_psiphon_vpn_extension -->|"drives"| node_psiphon_tunnel_framework
node_psiphon_vpn_datastore -->|"shares"| node_psiphon_shared_coredata
node_psiphon_vpn_datastore -->|"signals via"| node_psiphon_shared_core
node_psiphon_main_flow -->|"consumes"| node_psiphon_shared_core
node_psiphon_state -->|"reads"| node_psiphon_shared_config
node_psiphon_vpn_extension -->|"reads"| node_psiphon_shared_config
node_psiapi_iap -->|"shares"| node_psiphon_shared_coredata
node_psiapi_psicash -->|"wraps"| node_psicash_framework
node_psiphon_shared_strings -->|"localizes"| node_psiphon_main_flow

click node_psiphon_app_delegate "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/AppDelegate.m"
click node_psiphon_swift_delegate "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/SwiftDelegate.swift"
click node_psiphon_root_ui "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/ViewControllers/RootContainerController.m"
click node_psiphon_main_flow "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/ViewControllers/MainViewController.m"
click node_psiphon_views "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/View/AnimatedUIButton.swift"
click node_psiphon_subscriptions "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/SubscriptionViewController.m"
click node_psiphon_psicash_ui "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/PsiCash/PsiCashReducer.swift"
click node_psiphon_state "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/MainViewReducer.swift"
click node_psiphon_shared_core "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/Notifier.swift"
click node_psiphon_shared_coredata "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/CoreData/SharedModel.xcdatamodeld/SharedModel.xcdatamodel/contents"
click node_psiphon_shared_strings "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/Strings/en.lproj/Localizable.strings"
click node_psiphon_shared_config "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/psiphon_config.stub"
click node_psiphon_vpn_extension "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/PacketTunnelProvider.m"
click node_psiphon_vpn_datastore "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/LocalDatastore/ExtensionDataStore.m"
click node_psiphon_tunnel_framework "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonTunnel.xcframework/ios-arm64/PsiphonTunnel.framework/PsiphonTunnel"
click node_psicash_framework "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Frameworks/PsiCashLib.xcframework/ios-arm64_armv7/PsiCashLib.framework/PsiCashLib"
click node_psiapi_store "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/PsiApi/Store/Store.swift"
click node_psiapi_iap "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/AppStoreIAP/IAPReducer.swift"
click node_psiapi_psicash "https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/PsiCashClient/PsiCashState.swift"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_psiphon_app_delegate,node_psiphon_swift_delegate,node_psiphon_root_ui,node_psiphon_main_flow,node_psiphon_views,node_psiphon_subscriptions,node_psiphon_psicash_ui,node_psiphon_state toneBlue
class node_psiphon_shared_core,node_psiphon_shared_coredata,node_psiphon_shared_strings,node_psiphon_shared_config toneAmber
class node_psiphon_vpn_extension,node_psiphon_vpn_datastore toneMint
class node_psiapi_store,node_psiapi_iap,node_psiapi_psicash toneRose
class node_psiphon_tunnel_framework,node_psicash_framework toneIndigo
```

## Components

### Main app

Host iOS client UI, onboarding, settings, and commerce flows.

- [App entry](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/AppDelegate.m): app lifecycle · Application startup and root app wiring. · `Psiphon/AppDelegate.m`
- [Swift delegate](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/SwiftDelegate.swift): startup glue · Swift-side app coordination and lifecycle helpers. · `Psiphon/SwiftDelegate.swift`
- [Root UI](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/ViewControllers/RootContainerController.m): navigation shell · Primary container and navigation controllers for the app. · `Psiphon/ViewControllers/RootContainerController.m`
- [Main flow](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/ViewControllers/MainViewController.m): home/onboarding · Main screen, onboarding, launch, and deep-link routing. · `Psiphon/ViewControllers/MainViewController.m`
- [Custom views](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/View/AnimatedUIButton.swift): ui components · Animated buttons, status widgets, and reusable presentation views. · `Psiphon/View/AnimatedUIButton.swift`
- [Subscriptions](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/SubscriptionViewController.m): iap UI · App Store subscription and receipt-facing user flows. · `Psiphon/SubscriptionViewController.m`
- [PsiCash UI](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/PsiCash/PsiCashReducer.swift): commerce UI · PsiCash account, balance, and purchase screens. · `Psiphon/PsiCash/PsiCashReducer.swift`
- [App state](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Psiphon/MainViewReducer.swift): reducers/state · Central reducers and state for VPN, main screen, feedback, and commerce. · `Psiphon/MainViewReducer.swift`

### Shared code

Cross-target models, storage, logging, localization, and utilities.

- [Shared core](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/Notifier.swift): shared runtime · Cross-process data models, shared defaults, logging, profiling, and notifications. · `Shared/Notifier.swift`
- [Shared Core Data](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/CoreData/SharedModel.xcdatamodeld/SharedModel.xcdatamodel/contents): app-group db · Shared authorization and persisted state used by host app and extension. · `Shared/CoreData/SharedModel.xcdatamodeld/SharedModel.xcdatamodel/contents`
- [Strings](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/Strings/en.lproj/Localizable.strings): localization assets · Localized strings and app/store asset text bundles. · `Shared/Strings/en.lproj/Localizable.strings`
- [Runtime config](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Shared/psiphon_config.stub): embedded inputs · Static Psiphon config and embedded server entries consumed at runtime. · `Shared/psiphon_config.stub`

### VPN target

Packet-tunnel extension and host-extension data bridge.

- [VPN extension](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/PacketTunnelProvider.m): packet tunnel · NetworkExtension packet-tunnel entrypoint and extension-side logic. · `PsiphonVPN/PacketTunnelProvider.m`
- [Extension store](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonVPN/LocalDatastore/ExtensionDataStore.m): extension datastore · Keyed storage, authorization, and notification bridge inside the extension. · `PsiphonVPN/LocalDatastore/ExtensionDataStore.m`

### Swift packages

Standalone reusable packages and development tools.

- [Store core](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/PsiApi/Store/Store.swift): swift store · Reducer/effect store architecture shared by app logic and domain code. · `PsiApi/Sources/PsiApi/Store/Store.swift`
- [App Store IAP](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/AppStoreIAP/IAPReducer.swift): purchase domain · Receipt parsing, subscription verification, and payment queue logic. · `PsiApi/Sources/AppStoreIAP/IAPReducer.swift`
- [PsiCash client](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiApi/Sources/PsiCashClient/PsiCashState.swift): purchase domain · Shared PsiCash models, state, and effects for commerce flows. · `PsiApi/Sources/PsiCashClient/PsiCashState.swift`

### Vendored deps

Prebuilt binaries and third-party libraries integrated into the repo.

- [Tunnel engine](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/PsiphonTunnel.xcframework/ios-arm64/PsiphonTunnel.framework/PsiphonTunnel): vendored framework · Prebuilt tunnel runtime and reachability/default-route helpers. · `PsiphonTunnel.xcframework/ios-arm64/PsiphonTunnel.framework/PsiphonTunnel`
- [PsiCash lib](https://github.com/psiphon-inc/psiphon-ios-vpn/blob/master/Frameworks/PsiCashLib.xcframework/ios-arm64_armv7/PsiCashLib.framework/PsiCashLib): vendored framework · Binary PsiCash client library used for balance and purchase operations. · `Frameworks/PsiCashLib.xcframework/ios-arm64_armv7/PsiCashLib.framework/PsiCashLib`

## Connections

- App entry → Swift delegate: hands off to · Startup delegates split between Obj-C and Swift.
- App entry → Root UI: roots · Creates the main container and navigation shell.
- Root UI → Main flow: hosts · Primary container presents launch, onboarding, and main screens.
- Main flow → Custom views: renders with · Uses custom animated and reusable UI components.
- Main flow → App state: drives · UI behavior is driven by reducer/state updates.
- App state → Store core: built on · App state follows the shared store/effect architecture.
- App state → App Store IAP: consumes · Subscription and receipt logic flow through shared IAP domain code.
- App state → PsiCash client: consumes · PsiCash state and effect models back the commerce UI.
- Subscriptions → App Store IAP: uses · Subscription screens rely on receipt and purchase verification logic.
- PsiCash UI → PsiCash client: uses · PsiCash screens bind to shared client models and actions.
- PsiCash UI → PsiCash lib: bridges to · Binary PsiCash library handles account and purchase operations.
- Shared core → Shared Core Data: persists · Shared authorization and status data are stored in app-group Core Data.
- VPN extension → Extension store: reads/writes · Extension process stores shared status and authorization values.
- VPN extension → Tunnel engine: drives · Packet tunnel provider delegates core VPN work to the vendored engine.
- Extension store → Shared Core Data: shares · Extension storage interoperates with the shared Core Data model.
- Extension store → Shared core: signals via · Uses shared notifier/IPC helpers to communicate with the host app.
- Main flow → Shared core: consumes · App screens and reducers rely on shared logging, defaults, and IPC helpers.
- App state → Runtime config: reads · State and tunnel setup use embedded config and server entries.
- VPN extension → Runtime config: reads · Tunnel startup depends on static runtime configuration inputs.
- App Store IAP → Shared Core Data: shares · Subscription authorization uses the same shared persistent backing.
- PsiCash client → PsiCash lib: wraps · Shared PsiCash domain code wraps the vendored binary library.
- Strings → Main flow: localizes · Localized resources feed the app UI and store assets.
