Get Started

Project Structure

Overview

ShipThatApp is a SwiftUI boilerplate targeting iOS 17+ and built with Swift 6. It follows an MVVM architecture using the @Observable macro, async/await for all asynchronous work, and @MainActor for UI updates. The project is organized by feature first, then by type — so everything that makes up a feature (its views, view models, models, and supporting types) lives close together, while shared infrastructure (services, utilities, navigation) is grouped by responsibility.

Understanding this layout makes it straightforward to find existing code, follow the established patterns, and drop in your own functionality without fighting the structure.

All app source lives under ShipThatApp/. Below is the real top-level layout.

Top-Level Layout

ShipThatApp/
├── ShipThatAppApp.swift     # @main entry point; configures services & routing
├── AppDelegate.swift        # UIKit delegate for legacy hooks (e.g. quick actions)
├── ContentView.swift        # Root view; switches between auth and main flows

├── Views/                   # SwiftUI views + view models, grouped by feature
├── Services/                # Business logic & external integrations
├── Models/                  # Plain Codable / @Model data types
├── Navigation/              # Centralized, type-safe routing
├── Utils/                   # Config, helpers, and extensions
├── Misc/                    # Small standalone components
├── Shared/                  # Reusable view modifiers

├── Assets.xcassets/         # Images, colors, and data assets
├── Lotties/                 # Lottie animation files
└── Support/                 # Support files

Heads Up!

View models live next to the views they drive (for example ChatView.swift and ChatViewModel.swift share a folder), rather than in a separate ViewModels/ directory. This keeps each feature self-contained.

Views

Path: Views/

Views are SwiftUI types with minimal logic; their state and behavior live in a sibling @Observable view model. The folder is grouped by feature.

AI

Path: Views/AI/

The AI-powered feature screens, each in its own subfolder:

  • Chat/ — Multi-turn ChatGPT conversation UI. Includes ChatView, ChatViewModel, ChatModel, ChatRepository, ChatBubbleView, and SingleRequestView (a one-off, non-conversational request).
  • GenImage/ — DALL·E image generation, via GenImageView and GenImageViewModel.
  • Vision/ — Image analysis with the Vision API, via VisionView and VisionViewModel.
  • Pokedex/ — The flagship "Dex" scanner. Scan anything to identify it, then collect the result. This folder holds the UI and feature models: ScannerView, ScannerViewModel, PokedexHomeView, DexEntryViews, plus the supporting types DexCategory, DexEntry (a SwiftData @Model), and ScanResult.

SignIns

Path: Views/SignIns/

The authentication UI: SignIn, SignInOptions, RegistrationView, AppleButton, and SignInViewModel. These drive email/password, Magic Link, and Sign in with Apple flows through AuthManager.

Paywalls

Path: Views/Paywalls/

Three ready-made RevenueCat paywall designs — Paywall1View, Paywall2View, Paywall3View — plus the shared PaywallProductView.

Other Feature Views

  • Onboarding/OnboardingView, the swipeable first-run feature tour.
  • Settings/SettingsView, EditProfileView, and FeedbackView.
  • Animations/ — Lottie animation showcases (Lottie1View, Lottie2View, Lottie3View).
  • Content/ContentScreenView, the placeholder home for your app's core content.

A handful of top-level views live directly under Views/: LandingView (the unauthenticated entry point that also handles Magic Link deep links), WelcomeScreen, and SplashScreenView.

Services

Path: Services/

Business logic and external integrations. Services are typically @Observable classes (or lightweight structs), receive dependencies through their initializers, and expose async/await APIs.

Auth

Path: Services/Auth/

AuthManager — the single source of truth for authentication, backed by Supabase (supabase-swift). Handles sessions for email/password, Magic Link, and Sign in with Apple.

APIClient

Path: Services/APIClient/

A small, type-safe networking layer used by the AI features:

  • APIManager — performs requests and decodes responses.
  • Endpoints — defines the available backend routes.
  • Models/Endpoint, RequestMethod, RequestError, and EmptyResponse.

Heads Up!

Every AI call goes through a secure backend proxy with HMAC-signed requests, so your OpenAI keys never ship inside the app. The signing logic lives in Utils/CryptoUtils.swift, and routes are declared in Services/APIClient/Endpoints.swift.

OpenAI

Path: Services/OpenAI/

Thin service wrappers for each AI capability, grouped by type:

  • Chat/ChatGPTService (multi-turn) and ChatGPTSimpleService (one-off).
  • Dalle/DALLEService for image generation.
  • Vision/VisionService for general image analysis, and DexVisionService for the Dex scanner's structured identification (it reuses the signed vision endpoint and parses the model's JSON into a ScanResult).

Vision & Pokedex (the Dex scanner)

The Dex scanner is a hybrid of on-device and cloud intelligence, split across two services:

  • Services/Vision/ImageClassifier, which wraps Apple's on-device VNClassifyImageRequest. It runs offline and off the main thread to produce an instant, private coarse category and confidence (LocalGuess) that seeds the UI.
  • Services/Pokedex/DexStore, which owns a dedicated SwiftData ModelContainer (Dex.store) so collected DexEntry discoveries persist in their own store, separate from the chat history.

Other Services

  • Purchases/PurchaseManager, the RevenueCat v5 integration powering the paywalls.
  • QuickActionsManager/QuickActionsManager for Home Screen quick actions.
  • SplashScreen/SplashScreenManager for splash state transitions.
  • Settings/SettingsManager, an @Observable store for user preferences backed by UserDefaults.
  • Recipe/RecipeGeneratorManager, a sample AI feature.
  • AI/LocalLLMService, an on-device language model service.
  • Top-level AuthService.swift and RecipeService.swift round out the layer.

Models

Path: Models/

Plain data types with no business logic — Codable structs for API serialization and small value types:

  • DALLERequest, DALLEResponse — DALL·E payloads.
  • OnboardingFeature — a single onboarding slide.
  • Recipe — the sample recipe model.
  • SplashScreenStep — splash sequence steps.

Feature-specific models that are tightly coupled to one screen (such as DexEntry, DexCategory, and ScanResult) live alongside their views rather than here.

Path: Navigation/

Centralized, type-safe routing built on the AppRouter package. AppRouterTypes.swift defines:

  • AppTab — the main tab bar (welcome, content, settings).
  • AppDestination — every push destination, including URL deep-link parsing via from(path:fullPath:parameters:).
  • AppSheet — sheet presentations (paywall, feedback form, edit profile).

It also declares the AppRouter (tab-based) and AppSimpleRouter (single-stack, for the unauthenticated flow) type aliases used throughout the app.

typealias AppRouter = Router<AppTab, AppDestination, AppSheet>
typealias AppSimpleRouter = SimpleRouter<AppDestination, AppSheet>

Utils

Path: Utils/

Configuration and cross-cutting helpers:

  • Config.swift — central, non-secret app configuration (product IDs, API base URL, timeouts, and similar constants).
  • CryptoUtils.swift — HMAC request signing for the secure API proxy.
  • Extensions/ — focused extensions: Logger+Extensions (OSLog categories), String+Extensions, UIImage+Extensions, and View+Extensions.

Secrets

API keys and other secrets are not in Config.swift. They live in a gitignored Config.xcconfig (never in Info.plist or hardcoded in source). See the configuration docs for setup.

Misc & Shared

  • Misc/ — small standalone components: ImagePicker (a UIViewControllerRepresentable photo picker) and Toaster (the in-app toast/banner system, used via Toast.shared.present(...)).
  • Shared/Modifiers/ — reusable view modifiers, such as LiquidGlassModifier for the translucent "Liquid Glass" aesthetic.

Organization Principles

  1. Feature-based grouping. Views are grouped by feature (AI, SignIns, Paywalls), not by type. Everything for a feature sits together.
  2. MVVM with @Observable. Each view has a sibling @Observable view model; views stay declarative and logic-light.
  3. Dedicated service layer. All external integrations (Supabase, RevenueCat, OpenAI proxy, Vision) live in Services/ and are injected via initializers.
  4. Centralized navigation. Destinations, tabs, and sheets are defined once in Navigation/, keeping routing type-safe and deep-link-ready.
  5. Secrets stay out of source. Configuration is split between Config.swift (safe values) and a gitignored Config.xcconfig (secrets).
Previous
Rename XCode Project