diff --git a/.cursor/debug-378b5f.log b/.cursor/debug-378b5f.log new file mode 100644 index 0000000..75b536d --- /dev/null +++ b/.cursor/debug-378b5f.log @@ -0,0 +1 @@ +{\ diff --git a/backend/routes/textDataRoutes.js b/backend/routes/textDataRoutes.js index 44b6dd0..62b2156 100644 --- a/backend/routes/textDataRoutes.js +++ b/backend/routes/textDataRoutes.js @@ -148,6 +148,9 @@ function createTextDataPOST(s3Key, formatLine, validate, validateItem = null) { } catch {} if (current && (ifMatch || etag) && current !== String(ifMatch || etag)) { + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H2',location:'backend/routes/textDataRoutes.js:etag-mismatch',message:'ETag mismatch detected in text POST',data:{s3Key:String(s3Key||''),currentEtag:String(current||''),providedEtag:String(ifMatch||etag||'')},timestamp:Date.now()})}).catch(()=>{}); + // #endregion const { headMeta } = require('../services/s3Service'); const meta = await headMeta(s3Key); return sendError(res, 412, 'Precondition Failed: ETag mismatch', 'E_ETAG_MISMATCH', { diff --git a/backend/server.js b/backend/server.js index 3431fa3..8548319 100644 --- a/backend/server.js +++ b/backend/server.js @@ -412,12 +412,18 @@ app.post('/api/server-filters/:serverId', serverConfigsRoutes.postServerFilters) // === LOCKS === app.get('/api/locks/:resource', (req, res) => { const status = getLockStatus(req.params.resource); + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-get',message:'Lock status requested',data:{resource:String(req?.params?.resource||''),locked:Boolean(status?.locked)},timestamp:Date.now()})}).catch(()=>{}); + // #endregion res.json(status); }); app.post('/api/locks/:resource', (req, res) => { const { owner = 'anonymous', ttlSeconds = 120 } = req.body || {}; const result = acquireLock(req.params.resource, owner, ttlSeconds); + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-post',message:'Lock acquire attempted',data:{resource:String(req?.params?.resource||''),owner:String(owner||''),success:Boolean(result?.success),locked:Boolean(result?.locked)},timestamp:Date.now()})}).catch(()=>{}); + // #endregion if (!result.success) { return sendError(res, 423, 'Resource is locked by another user', 'E_RESOURCE_LOCKED', { owner: result.owner, @@ -429,6 +435,9 @@ app.post('/api/locks/:resource', (req, res) => { app.delete('/api/locks/:resource', (req, res) => { const result = releaseLock(req.params.resource); + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H4',location:'backend/server.js:locks-delete',message:'Lock released',data:{resource:String(req?.params?.resource||''),released:Boolean(result?.released)},timestamp:Date.now()})}).catch(()=>{}); + // #endregion res.json(result); }); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d7c31bb..05cd965 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -196,6 +196,12 @@ function MainLayout() { } }, [location.pathname, layout]); + useEffect(() => { + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H5',location:'frontend/src/App.jsx:route-change',message:'Route changed in MainLayout',data:{pathname:String(location?.pathname||''),layout:String(layout||'')},timestamp:Date.now()})}).catch(()=>{}); + // #endregion + }, [location.pathname, layout]); + // Состояние для управления выпадающими меню const [dropdownStates, setDropdownStates] = useState({ data: false, diff --git a/frontend/src/components/ErrorBoundary.jsx b/frontend/src/components/ErrorBoundary.jsx index 6f79921..eab5d78 100644 --- a/frontend/src/components/ErrorBoundary.jsx +++ b/frontend/src/components/ErrorBoundary.jsx @@ -23,6 +23,9 @@ class ErrorBoundary extends Component { componentDidCatch(error, errorInfo) { // Логируем ошибку console.error('ErrorBoundary caught an error:', error, errorInfo); + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H3',location:'frontend/src/components/ErrorBoundary.jsx:componentDidCatch',message:'React ErrorBoundary caught error',data:{message:String(error?.message||''),name:String(error?.name||''),componentStack:String(errorInfo?.componentStack||'').slice(0,500)},timestamp:Date.now()})}).catch(()=>{}); + // #endregion // Отправляем в мониторинг (если настроен) this.logErrorToService(error, errorInfo); diff --git a/frontend/src/lib/api.js b/frontend/src/lib/api.js index 4e7a958..7aed1c6 100644 --- a/frontend/src/lib/api.js +++ b/frontend/src/lib/api.js @@ -39,6 +39,9 @@ function buildCacheKey(config) { // Улучшенный retry interceptor с поддержкой всех методов и типов ошибок api.interceptors.response.use( (response) => { + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:response',message:'API response received',data:{method:String(response?.config?.method||'get').toUpperCase(),url:String(response?.config?.url||''),status:Number(response?.status||0)},timestamp:Date.now()})}).catch(()=>{}); + // #endregion try { const method = String(response?.config?.method || 'get').toLowerCase(); if (method === 'get') { @@ -104,6 +107,9 @@ api.interceptors.response.use( api.interceptors.response.use( (res) => res, (err) => { + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:error',message:'API response error',data:{method:String(err?.config?.method||'get').toUpperCase(),url:String(err?.config?.url||''),status:Number(err?.response?.status||0),code:String(err?.response?.data?.code||err?.code||'')},timestamp:Date.now()})}).catch(()=>{}); + // #endregion try { // Не показываем уведомления если это повторная попытка const isRetrying = err?.config?.__retryCount > 0; @@ -135,6 +141,9 @@ api.interceptors.response.use( // Request интерсептор: If-Match из etag (если не задан явный заголовок) api.interceptors.request.use((config) => { try { + // #region agent log + fetch('http://192.168.10.2:7343/ingest/aa002dd6-6968-4a35-b09d-f05302d83266',{method:'POST',headers:{'Content-Type':'application/json','X-Debug-Session-Id':'378b5f'},body:JSON.stringify({sessionId:'378b5f',runId:'baseline',hypothesisId:'H1_H2',location:'frontend/src/lib/api.js:request',message:'API request started',data:{method:String(config?.method||'get').toUpperCase(),url:String(config?.url||'')},timestamp:Date.now()})}).catch(()=>{}); + // #endregion // If-None-Match для GET на базе кеша const method = String(config.method || 'get').toLowerCase(); if (method === 'get') {