feat(app): bindAll() now checks NODE_ENV in addition to USE_DEV_SEED

Three-rule resolution order in bindAll() (first match wins):

  1. USE_DEV_SEED === 'true'   → bindAllDevSeed (explicit override)
  2. NODE_ENV    === 'production' → bindAllProduction
  3. otherwise                  → bindAllDevSeed (developer default)

Rationale: 'pnpm dev' should boot the app without requiring Payload to
be running locally — dev seed is the more useful default for non-
production environments. Production servers explicitly set
NODE_ENV=production and get the real binding. The USE_DEV_SEED override
remains the escape hatch (force seed in any NODE_ENV — e.g. staging
preview, design review).

bind-production.test.ts grows from 3 tests to 8 — covers the dispatcher
matrix:
- USE_DEV_SEED='true' wins even when NODE_ENV='production'
- NODE_ENV='production' (no override) → production
- NODE_ENV='development' → dev seed (default)
- NODE_ENV unset → dev seed (default)
- USE_DEV_SEED='false' treated as not-set (only the literal 'true' triggers)
- Pre-existing 'binds all five repos' test now also asserts bindProductionMedia

di-explainer.html conditions table + mode flag strings updated to match
the new three-rule logic.
This commit is contained in:
2026-05-06 19:32:00 +02:00
parent 61dde18b53
commit 6bf19f35c5
3 changed files with 136 additions and 12 deletions

View File

@@ -867,11 +867,18 @@ footer .colophon {
<p>The web app's server entry point runs <code>bindAll()</code>, which checks <code>process.env.USE_DEV_SEED</code> and dispatches to either <code>bindAllProduction()</code> or <code>bindAllDevSeed()</code>. Each calls every feature's binder.</p>
</div>
<pre class="code" data-lang="typescript // apps/web-next/src/server/bind-production.ts"><span class="k">export async function</span> <span class="n">bindAll</span>(): <span class="t">Promise</span>&lt;<span class="t">void</span>&gt; {
<span class="c">// 1. Explicit override wins, regardless of NODE_ENV.</span>
<span class="k">if</span> (<span class="n">process</span>.<span class="n">env</span>.<span class="n">USE_DEV_SEED</span> === <span class="s">"true"</span>) {
<span class="k">await</span> <span class="n">bindAllDevSeed</span>();
<span class="k">return</span>;
}
<span class="k">await</span> <span class="n">bindAllProduction</span>();
<span class="c">// 2. Production env → real Payload.</span>
<span class="k">if</span> (<span class="n">process</span>.<span class="n">env</span>.<span class="n">NODE_ENV</span> === <span class="s">"production"</span>) {
<span class="k">await</span> <span class="n">bindAllProduction</span>();
<span class="k">return</span>;
}
<span class="c">// 3. Default: dev seed, so `pnpm dev` boots without Payload.</span>
<span class="k">await</span> <span class="n">bindAllDevSeed</span>();
}</pre>
</div>
@@ -1032,15 +1039,20 @@ footer .colophon {
<div class="outcome">default · empty mock</div>
</div>
<div class="conditions-row">
<div class="scenario">Server (any env) with USE_DEV_SEED=true</div>
<div class="scenario">Server (any env) with USE_DEV_SEED=true · explicit override wins</div>
<div class="trigger">bindAll() → bindAllDevSeed()</div>
<div class="outcome">dev seed · populated mock</div>
</div>
<div class="conditions-row">
<div class="scenario">Server (any env) with USE_DEV_SEED unset / not "true"</div>
<div class="scenario">NODE_ENV=production, USE_DEV_SEED unset</div>
<div class="trigger">bindAll() → bindAllProduction(config)</div>
<div class="outcome">production · real Payload</div>
</div>
<div class="conditions-row">
<div class="scenario">pnpm dev (NODE_ENV=development or unset), no env flag</div>
<div class="trigger">bindAll() → bindAllDevSeed() (default)</div>
<div class="outcome">dev seed · populated mock</div>
</div>
<div class="conditions-row">
<div class="scenario">Storybook story that wants populated data</div>
<div class="trigger">await bindDevSeedBlog()</div>
@@ -1172,7 +1184,7 @@ const MODES = {
],
},
seed: {
flag: 'USE_DEV_SEED === "true" · bindAllDevSeed() ran',
flag: 'USE_DEV_SEED="true" OR NODE_ENV ≠ "production" (default) · bindAllDevSeed() ran',
scenarioTag: 'when this happens',
title: 'Dev seed binder ran at app boot',
narrative: [
@@ -1191,7 +1203,7 @@ const MODES = {
],
},
prod: {
flag: 'USE_DEV_SEED unset or not "true" · bindAllProduction(config) ran',
flag: 'NODE_ENV="production", USE_DEV_SEED unset · bindAllProduction(config) ran',
scenarioTag: 'when this happens',
title: 'Production binder ran at app boot',
narrative: [