When it's a theme job
If the outcome is something visitors see and it works with data Shopify already has (sections, product pages, cart behavior, bundles displayed from metafields), it belongs in the theme. Theme work is fast to ship, has no hosting costs, and your team keeps editing everything in the theme editor.
Modern theme architecture (Online Store 2.0 blocks, metafields, metaobjects) covers far more than most people think: custom PDPs, comparison tables, calculators, even fairly complex interactive tools can live entirely in the theme.
When you need an app (and which kind)
You need an app the moment the feature requires a server: talking to external APIs, storing data Shopify can't hold, reacting to webhooks, doing work on a schedule. A private app, built for just your store, is usually the answer; you own it and pay only hosting.
Checkout changes and discount logic are special: they require Shopify Functions or checkout UI extensions, which live inside an app but run on Shopify's infrastructure.
And sometimes the right answer is an app-store app. If an existing app covers 90%+ of your need at a sane price, I'll say so. Custom development should solve problems apps can't, not reinvent working wheels.
The hybrid reality
Most interesting projects are hybrids: a configurator is a theme-embedded frontend plus an app backend; a subscription portal is an app proxy rendering inside the theme. Don't worry about picking the category yourself: describe the outcome you want, and the architecture follows.