Real JSON null for empty product feature; SSR warm-cache button and CLI

Ticket 0068-FE: ProductFeatureJsonRenderer returned json_encode(null), which headless passes on as the STRING null (it only decodes object/array-looking strings) and crashed the front end. It now returns an empty string and the TypoScript field sets ifEmptyReturnNull = 1, giving a real JSON null. No other renderer used the pattern. Ticket 0066-FE: SsrPurgeService::warm() posts to the node /__warm endpoint (derived from SSR_PURGE_ENDPOINT, same secret), exposed as a Warm cache button with confirmation in the VITEC SSR module, a Cache warming progress row fed by /__health, and the CLI vitec:ssr-warm [paths]. Warm runs are deliberately not written to the purge log. Verified: two-path run 2/2 done, affected page delivers productfeature null.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
orascheandClaude Fable 5.2 committed 2026-11-10 10:59:24 +01:00
1 parent cb53ff67ee
commit 8f8ae039d4
7 files changed
+176 -3

No files matched your search

@@ -32,6 +32,33 @@
</f:if>
</td>
</tr>
<tr>
<th>Cache warming</th>
<td>
<f:if condition="{health.warming.running}">
<f:then>
<span class="badge badge-info">running</span>
{health.warming.done} of {health.warming.queued} pages rendered
({health.warming.skipped} still fresh, {health.warming.failed} failed)
<br><small>Reload this module to follow the progress.</small>
</f:then>
<f:else>
<f:if condition="{health.warming.startedAt}">
<f:then>
Last run: {health.warming.done} of {health.warming.queued} pages rendered
({health.warming.skipped} still fresh,
<f:if condition="{health.warming.failed}">
<f:then><span class="badge badge-danger">{health.warming.failed} failed</span></f:then>
<f:else>0 failed</f:else>
</f:if>)
<f:if condition="{health.warming.aborted}"> <span class="badge badge-warning">aborted by restart</span></f:if>
</f:then>
<f:else><span class="text-muted">no run since the server started</span></f:else>
</f:if>
</f:else>
</f:if>
</td>
</tr>
<tr>
<th>Purge configuration</th>
<td>
@@ -60,6 +87,14 @@
<button type="submit" class="btn btn-warning">Purge everything (*)</button>
<small class="text-muted"> — needed after menu/footer changes while auto-purge is off</small>
</form>
<h3 style="margin-top:24px">Warm cache</h3>
<form action="{f:be.uri(route: 'web_vitecssr.warm')}" method="post"
onsubmit="return confirm('This renders every sitemap page (800+) in the background and sends several thousand requests to TYPO3 within a few minutes. Continue?');">
<button type="submit" class="btn btn-success">Warm cache (all sitemap pages)</button>
<small class="text-muted"> — pre-renders every page in the background, so no visitor has to
wait for a first render. Useful after "Purge everything" or a deploy; takes a few minutes.</small>
</form>
</div>
</div>