Showcase

The removable demo catalog and the step-by-step recipe to delete it.

The Showcase tab is a demo catalog — a self-guided tour of everything the template ships, built so you can delete it in one sitting and lose nothing. It's the one feature labeled Removable demo, and for most buyers the first thing you'll want is the removal recipe at the bottom of this page.

Source of truth: Features/Showcase/README.md in the template. This page mirrors it — if the two ever disagree, the README (and the code) win.

The one rule: dependencies point one way

Core never names a Showcase type. The Showcase may name anything in core.

This is the single invariant that makes deletion safe. The Showcase only ever launches core feature views (TodosView, UploadView, PermissionsView, ReferView, AccountSecurityView, PaywallView, …) inside its own navigation stack (ShowcaseTabView). It never becomes the sole home of a core feature and never hands off to another tab. Because nothing in core imports a Showcase type, removing the module can't break a core feature.

Concretely:

  • ShowcaseRoute lives in Features/Showcase/, not in Navigation/MainRoute.swift. MainShellView mounts ShowcaseTabView(onOpenMenu:) and holds no Showcase navigation state.
  • When you add a demo you touch three Showcase-local places — a ShowcaseRoute case, a CapabilityCatalog entry, and a destination in ShowcaseTabView — and never reach back into the app shell. If a demo needs a shell affordance, it takes a generic closure (like onOpenMenu), never a Showcase type.

The CapabilityCatalog data model

The catalog is data-driven: every row is one TemplateCapability value in Core/Showcase/CapabilityCatalog.swift, and both the Showcase list and Home's "What's inside" tiles render from it. Adding a capability is a one-line edit — no view changes.

TemplateCapability(
    id: "todos",                    // stable slug, unique across the catalog
    titleKey: "showcase.todos.title",
    summaryKey: "showcase.todos.summary",
    category: .backendData,         // section grouping
    systemImage: "checklist",       // SF Symbol row glyph
    route: .todos,                  // ShowcaseRoute pushed on tap (nil = no demo)
    status: .liveDemo               // how runnable it is in this build
)

The supporting types:

TypeRole
TemplateCapabilityOne catalog row. Described in exactly one place; every surface renders from it.
CapabilityCategoryThe five/six section headers: foundation, authentication, backendData, commerce, growth, operations.
CapabilityStatusThe runnability pill on each row (see below).

CapabilityStatus maps directly onto the feature-status vocabulary used across these docs:

StatusMeaningPill tint
liveDemoFully interactive on the simulator, no setup.green
configuredDriven by build config (e.g. the update gate's version thresholds).tint
deviceOnlyNeeds a real device (APNs push, some biometrics).orange
requiresKeysNeeds secrets in Secrets.xcconfig (IAP, analytics); the consumer controller no-ops when absent.grey

So a row like paywall shows requiresKeys until you add a RevenueCat key, and push-notifications shows deviceOnly because the simulator never receives a token — the catalog is honest about what will actually run.

How to remove the Showcase

Deleting the demo is a small, mechanical operation. After step 2 the project still builds and every core feature (Todos, Upload, Permissions, Refer, Account/Security, Paywall) stays reachable through its own entry point.

Delete the two folders

rm -rf SoarStarterSwift/Core/Showcase/
rm -rf SoarStarterSwift/Features/Showcase/

Delete the fenced seams

Each seam is marked with a comment naming the Showcase, so they're greppable. Remove:

  • Navigation/MainRoute.swift — the case showcase in MainTab (and its titleKey / systemImage arms).
  • Features/Main/MainShellView.swift — the // MARK: - Showcase tab block, the openShowcase() helper, the onOpenShowcase: argument passed to HomeView, and the .showcase arm in routePendingDeepLink().
  • Features/Home/HomeView.swift — the fenced // MARK: Showcase promo block (the "Explore the components" CTA, the capabilityChips view, and its CapabilityChip type + capabilityChipItems array) and the onOpenShowcase property. Home is otherwise independent — its chips use a Home-local list, not the Core/Showcase catalog.
  • Features/Main/MainShellDrawer.swift — the showcase DrawerRow.
  • Core/DeepLinks/DeepLinkResolver.swift — the .showcase case and the "/showcase" path (the .todos deep link already routes to Home).
  • SoarStarterSwiftTests/ — delete CapabilityCatalogTests.swift and ShowcaseNavigationTests.swift so the test target still compiles.

(Optional) Drop the demo guides

Features/Guide/ is only reached from the Showcase. It compiles standalone but becomes dead code — delete it if you don't want bundled guides.

(Optional) Prune strings

The showcase.*, capabilityCategory.*, capabilityStatus.*, and tabs.showcase keys in Localizable.xcstrings become unused. They're harmless if left; delete by prefix for a clean catalog. Keep tabs.todosTodosView uses it and Todos is core.

Removing the Showcase does not require touching any core feature, repository, controller, or view model. Rebuild after step 2 to confirm — the xcodebuild command should stay green.

Don't delete Features/Todos/, Features/Upload/, Features/Permissions/, Features/Refer/, or Features/Profile/ when you remove the Showcase — those are Example features, reachable on their own, not part of the demo module.

On this page