Files
VITEC-website/packages/vitec/Resources/Private/Templates/Ssr/Index.html
T
orascheandClaude Fable 5.1 37c4c116d0 SSR-Modul: Client errors mit Details-Aufklapper in jeder Zeile
Bisher gab es den Aufklapper nur bei Meldungen mit Stack. Jetzt hat jede
Zeile "details" mit Zeit, Release, voller URL, kompletter Meldung,
Stack (oder Hinweis "no stack transmitted"), vollem User-Agent und
anonymisierter IP, damit sich jeder Fehler bewerten laesst (Wunsch Harry).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 18:00:58 +01:00

193 lines
10 KiB
HTML

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<h1>VITEC SSR — Control &amp; Protocol</h1>
<div class="row">
<div class="col-md-6">
<h3>Status</h3>
<table class="table table-striped">
<tr>
<th>SSR delivery</th>
<td>
<f:if condition="{flagOn}">
<f:then><span class="badge badge-success">ON — pages served from the VPS</span></f:then>
<f:else><span class="badge badge-secondary">OFF — SPA as before</span></f:else>
</f:if>
<br><small>Toggle: Site Management &rsaquo; Settings &rsaquo; VITEC</small>
</td>
</tr>
<tr>
<th>SSR server</th>
<td>
<f:if condition="{health}">
<f:then>
<span class="badge badge-success">running</span> {health.responseMs} ms<br>
Release <strong>{health.release.release}</strong>
(commit {health.release.commit})<br>
Cache: {health.cachedPages} pages / {health.cacheMB} MB
</f:then>
<f:else>
<span class="badge badge-danger">not reachable</span> {healthError}
</f:else>
</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>
<f:if condition="{configured}">
<f:then><span class="badge badge-success">ok</span></f:then>
<f:else><span class="badge badge-warning">var/vitec-ssr-purge.env missing</span></f:else>
</f:if>
</td>
</tr>
</table>
</div>
<div class="col-md-6">
<h3>Purge cache</h3>
<form action="{f:be.uri(route: 'web_vitecssr.purge')}" method="post" class="form-group">
<label for="purge-paths">Paths (one per line or comma-separated):</label>
<textarea class="form-control" id="purge-paths" name="paths" rows="3"
placeholder="/products/aligo&#10;/insights/news"></textarea>
<input type="hidden" name="mode" value="paths">
<div style="margin-top:8px">
<button type="submit" class="btn btn-primary">Purge these paths</button>
</div>
</form>
<form action="{f:be.uri(route: 'web_vitecssr.purge')}" method="post"
onsubmit="return confirm('Really purge the ENTIRE SSR cache?');">
<input type="hidden" name="mode" value="all">
<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>
<h3>Purge protocol <small>(last 30)</small></h3>
<table class="table table-striped table-sm">
<thead><tr><th>Time</th><th>Trigger</th><th>Paths</th><th>Result</th><th>Duration</th></tr></thead>
<tbody>
<f:for each="{purgeLog}" as="row">
<tr>
<td><f:format.date format="Y-m-d H:i:s">@{row.crdate}</f:format.date></td>
<td>{row.trigger_source}</td>
<td><code>{row.paths}</code></td>
<td>
<f:if condition="{row.success}">
<f:then><span class="badge badge-success">ok</span></f:then>
<f:else><span class="badge badge-danger">HTTP {row.http_code}</span> {row.message}</f:else>
</f:if>
</td>
<td>{row.duration_ms} ms</td>
</tr>
</f:for>
</tbody>
</table>
<h3>Health samples <small>(last 10 — history via cron <code>vitec:ssr-health</code>, every 5 minutes)</small></h3>
<table class="table table-striped table-sm">
<thead><tr><th>Time</th><th>Status</th><th>Release</th><th>Cache</th><th>Response time</th></tr></thead>
<tbody>
<f:for each="{healthLog}" as="row">
<tr>
<td><f:format.date format="Y-m-d H:i:s">@{row.crdate}</f:format.date></td>
<td>
<f:if condition="{row.ok}">
<f:then><span class="badge badge-success">ok</span></f:then>
<f:else><span class="badge badge-danger">down</span></f:else>
</f:if>
</td>
<td>{row.release_id}</td>
<td>{row.cached_pages} pages / {row.cache_mb} MB</td>
<td>{row.response_ms} ms</td>
</tr>
</f:for>
</tbody>
</table>
<h3>Client errors <small>(last 24 h — {clientErrorCount24h} report<f:if condition="{clientErrorCount24h} != 1">s</f:if>, newest 50 shown)</small></h3>
<p class="text-muted" style="font-size:11px">
Browser-side failures reported by the React frontend via <code>POST /api/vitec/client-error</code>
(JS errors, unhandled promise rejections, element error boundaries and "chunk reload" after a deploy).
Limited to 30 reports per minute and IP, 8 KB per report; IPs are stored anonymized.
Kept for 30 days (cron <code>vitec:client-error-cleanup</code>).
</p>
<table class="table table-striped table-sm">
<thead><tr><th>Time</th><th>Release</th><th>Message</th><th>Page</th><th>Browser</th><th>IP</th></tr></thead>
<tbody>
<f:for each="{clientErrors}" as="row">
<tr>
<td style="white-space:nowrap"><f:format.date format="Y-m-d H:i:s">@{row.crdate}</f:format.date></td>
<td><code>{row.release}</code></td>
<td>
<f:if condition="{row.is_chunk_reload}">
<f:then><span class="badge badge-warning">chunk reload</span> </f:then>
<f:else><span class="badge badge-danger">error</span> </f:else>
</f:if>
{row.message}
<details style="margin-top:4px">
<summary style="cursor:pointer" class="text-muted">details</summary>
<table class="table table-sm" style="margin:6px 0 0;font-size:11px;background:#fff">
<tr><th style="width:90px">Reported</th><td><f:format.date format="Y-m-d H:i:s">@{row.crdate}</f:format.date> (entry #{row.uid})</td></tr>
<tr><th>Release</th><td><code>{row.release}</code><f:if condition="!{row.release}"><span class="text-muted">not transmitted</span></f:if></td></tr>
<tr><th>URL</th><td style="word-break:break-all"><a href="{row.url}" target="_blank" rel="noopener">{row.url}</a><f:if condition="!{row.url}"><span class="text-muted">not transmitted</span></f:if></td></tr>
<tr><th>Message</th><td style="white-space:pre-wrap;word-break:break-word">{row.message}</td></tr>
<tr><th>Stack</th><td>
<f:if condition="{row.stack}">
<f:then><pre style="font-size:11px;white-space:pre-wrap;max-height:320px;overflow:auto;margin:0">{row.stack}</pre></f:then>
<f:else><span class="text-muted">no stack transmitted</span></f:else>
</f:if>
</td></tr>
<tr><th>Browser</th><td style="word-break:break-all">{row.user_agent}<f:if condition="!{row.user_agent}"><span class="text-muted">not transmitted</span></f:if></td></tr>
<tr><th>IP</th><td>{row.ip} <span class="text-muted">(anonymized)</span></td></tr>
</table>
</details>
</td>
<td><a href="{row.url}" target="_blank" rel="noopener" title="{row.url}">{row.path}</a></td>
<td title="{row.user_agent}"><small>{row.ua_short}</small></td>
<td><small>{row.ip}</small></td>
</tr>
</f:for>
<f:if condition="!{clientErrors}">
<tr><td colspan="6" class="text-muted">No client errors reported in the last 24 hours.</td></tr>
</f:if>
</tbody>
</table>
</html>