feat: Sentry monitoring a kompletnější sledování stavů Bolt Food

- integrace Sentry na serveru (@sentry/node) i klientu (@sentry/react):
  chyby 5xx, pády a console logy se hlásí do self-hosted Sentry
- nový veřejný endpoint GET /api/config — klient si z něj za běhu
  vyzvedne Sentry DSN (SENTRY_DSN / SENTRY_CLIENT_DSN v env)
- ErrorBoundary na klientu a sourcemapy pro čitelné stack traces
- oprava mapování stavu waiting_acceptance (zobrazoval se jako Příprava)
- mapování stavů kurýra matched/accepted, logování přechodů stavů
  Bolt objednávek pro postupné zmapování nedokumentovaného API
- simulátor Bolt ve vývoji nově prochází celou reálnou sekvenci stavů
- vypnuté logování connect/disconnect websocket klientů
This commit is contained in:
2026-07-14 11:25:49 +02:00
parent a708eda421
commit 12fa87f3ad
17 changed files with 420 additions and 17 deletions
+31 -5
View File
@@ -6,20 +6,38 @@ import './index.css';
import AppRoutes from './AppRoutes';
import { BrowserRouter } from 'react-router';
import { client } from '../../types/gen/client.gen';
import { getConfig } from '../../types/gen/sdk.gen';
import { getToken } from './Utils';
import { toast } from 'react-toastify';
import * as Sentry from '@sentry/react';
client.setConfig({
auth: () => getToken(),
baseUrl: '/api', // openapi-ts si to z nějakého důvodu neumí převzít z api.yml
});
// Sentry se inicializuje až podle runtime konfigurace ze serveru (bez DSN zůstává vypnuté).
// Klient je statický build, takže DSN nejde zapéct při buildu — server ho zná z env.
getConfig().then(({ data }) => {
if (data?.sentry.dsn) {
Sentry.init({
dsn: data.sentry.dsn,
environment: data.sentry.environment,
enableLogs: true,
});
}
}).catch(() => { /* config endpoint nedostupný — běžíme bez Sentry */ });
// Interceptor na vyhození toasteru při chybě
client.interceptors.response.use(async response => {
// TODO opravit - login je zatím výjimka, voláme ho "naprázdno" abychom zjistili, zda nás nepřihlásily trusted headers
if (!response.ok && !response.url.includes("/login")) {
const json = await response.json();
toast.error(json.error, { theme: "colored" });
// Serverové chyby hlásíme do Sentry; 4xx jsou očekávané (chyby uživatele)
if (response.status >= 500) {
Sentry.captureMessage(`API ${response.status}: ${new URL(response.url).pathname}${json.error}`, 'error');
}
}
return response;
});
@@ -29,10 +47,18 @@ const root = ReactDOM.createRoot(
);
root.render(
<React.StrictMode>
<BrowserRouter>
<ProvideAuth>
<AppRoutes />
</ProvideAuth>
</BrowserRouter>
<Sentry.ErrorBoundary fallback={
<div className="text-center p-5">
<h4>Něco se pokazilo 😕</h4>
<p>Chyba byla nahlášena. Zkuste stránku načíst znovu.</p>
<button className="btn btn-primary" onClick={() => window.location.reload()}>Načíst znovu</button>
</div>
}>
<BrowserRouter>
<ProvideAuth>
<AppRoutes />
</ProvideAuth>
</BrowserRouter>
</Sentry.ErrorBoundary>
</React.StrictMode>
);