Skip to main content

propeller.json schema

The scaffolded shop's identity card. Lives at frontend/propeller.json. Owned by the shop. Edited rarely. Read by:

  • propeller doctor — verify pinned versions + config drift.
  • The shop's own runtimedata/config.ts (Next) or src/lib/config.ts (Vue) reads shop.mode etc. at boot to populate the <PropellerProvider>.
  • propeller upgrade (Phase B, deferred) — reads template.version and customisations.ejected to decide what to apply.

Shape

{
$schema?: string,
template: {
name: string, // e.g. "propeller-shop-template-next"
version: string, // semver at scaffold time
stack: 'next' | 'vue',
},
shop: {
name: string,
mode: 'b2b' | 'b2c' | 'hybrid',
locales: string[], // BCP-47, non-empty
defaultLocale: string,
currency: string, // display symbol "€"
currencyCode: string, // ISO 4217 "EUR" (length 3)
portalMode: 'open' | 'semi-closed' | 'closed',
siteUrl: string, // valid URL, no trailing slash
},
features: {
quotes: boolean,
authorization: boolean,
favorites: boolean,
clusters: boolean,
search: boolean,
contacts: boolean,
},
cms: {
adapter: 'strapi' | 'cms' | null,
endpoint: string, // typically "${CMS_URL}"
preview: boolean,
},
customisations: {
ejected: string[], // paths relative to frontend/
},
}

Authoritative source: packages/cli/src/schema/propellerJson.ts.

Feature flags

Each flag says "this whole route tree is in use". The future propeller upgrade reads them to decide which sub-trees to diff against. At runtime they're advisory — they don't (yet) tree-shake unused routes.

For mode === 'b2c', the B2B-flavoured flags (quotes/authorization/contacts) default to false. For mode === 'hybrid', they default to true and are gated at runtime by userMode.

customisations.ejected

Phase B (propeller upgrade) will skip diffs for any file path listed here. v0.1 reserves the field; nothing reads it yet. Adding paths now is fine — the upgrade tool will pick them up when it ships.

Substitution variables

The CLI builds a substitution context from the prompt answers and runs Handlebars over every *.template.* file in the template tree. The variables available inside templates:

VariableTypeSource
shopNamestring--name
shopDescriptionstringderived from name
siteUrlURL--site-url
siteHostnamestringparsed from siteUrl
apiHostnamestringparsed from NEXT_PUBLIC_PROPELLER_API_URL placeholder
stack'next' | 'vue'--stack
shopMode'b2b' | 'b2c' | 'hybrid'--mode
isB2B / isB2C / isHybridbooleanderived from shopMode
defaultLocalestring--default-locale
defaultLocaleLowerstringlowercased
locales / localesArray / localesJsonArrayvarious--locales
currency / currencyCodestring--currency-code
portalMode'open' | 'semi-closed' | 'closed'--portal-mode
portalModeConstantOPEN | SEMI_CLOSED | CLOSEDuppercase enum form
channelId, anonymousId, taxZonestringdefaults from data/defaults.ts
cmsAdapter'strapi' | 'cms' | null--cms
cmsAdapterTsValuestring'null' or "'<adapter>'"
cmsAdapterJsonValuestringnull or "<adapter>"
cmsAdapterPackagestringpropeller-v2-cms-adapter-<adapter>
cmsAdapterDisplaystringUI-friendly label
showUserType'Contact' | 'Customer' | nullderived from mode
featureQuotes / featureAuthorization / featureContactsbooleanderived from mode
templateVersionstringCLI version at scaffold time

Handlebars is run only on *.template.* files (suffix stripped on write) — everything else is verbatim. This avoids the Vue {{ }} / Handlebars {{ }} collision in regular .vue files.