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:
ShowcaseRoutelives inFeatures/Showcase/, not inNavigation/MainRoute.swift.MainShellViewmountsShowcaseTabView(onOpenMenu:)and holds no Showcase navigation state.- When you add a demo you touch three Showcase-local places — a
ShowcaseRoutecase, aCapabilityCatalogentry, and a destination inShowcaseTabView— and never reach back into the app shell. If a demo needs a shell affordance, it takes a generic closure (likeonOpenMenu), 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:
| Type | Role |
|---|---|
TemplateCapability | One catalog row. Described in exactly one place; every surface renders from it. |
CapabilityCategory | The five/six section headers: foundation, authentication, backendData, commerce, growth, operations. |
CapabilityStatus | The runnability pill on each row (see below). |
CapabilityStatus maps directly onto the feature-status vocabulary used across
these docs:
| Status | Meaning | Pill tint |
|---|---|---|
liveDemo | Fully interactive on the simulator, no setup. | green |
configured | Driven by build config (e.g. the update gate's version thresholds). | tint |
deviceOnly | Needs a real device (APNs push, some biometrics). | orange |
requiresKeys | Needs 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— thecase showcaseinMainTab(and itstitleKey/systemImagearms).Features/Main/MainShellView.swift— the// MARK: - Showcase tabblock, theopenShowcase()helper, theonOpenShowcase:argument passed toHomeView, and the.showcasearm inroutePendingDeepLink().Features/Home/HomeView.swift— the fenced// MARK: Showcase promoblock (the "Explore the components" CTA, thecapabilityChipsview, and itsCapabilityChiptype +capabilityChipItemsarray) and theonOpenShowcaseproperty. Home is otherwise independent — its chips use a Home-local list, not theCore/Showcasecatalog.Features/Main/MainShellDrawer.swift— theshowcaseDrawerRow.Core/DeepLinks/DeepLinkResolver.swift— the.showcasecase and the"/showcase"path (the.todosdeep link already routes to Home).SoarStarterSwiftTests/— deleteCapabilityCatalogTests.swiftandShowcaseNavigationTests.swiftso 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.todos — TodosView
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.
