{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "runs": [{"tool": {"driver": {"name": "Repobility", "informationUri": "https://repobility.com", "rules": [{"id": "scanner-5b6b662a2cf93466", "name": "Stray `console.log` in TS/JS \u2014 server.js:140", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server.js:140"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1ca42bd9a19b3d92", "name": "Stray `console.log` in TS/JS \u2014 scripts/test-google-ads.js:22", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 scripts/test-google-ads.js:22"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-90108ff30fa5022f", "name": "Stray `console.log` in TS/JS \u2014 lib/db.js:74", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 lib/db.js:74"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6cc26d1375030cb9", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/RoiCalculator.jsx:309", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/RoiCalculator.jsx:309"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f3bb99e4a0414c6c", "name": "Stray `console.log` in TS/JS \u2014 src/components/RoiCalculator.jsx:1698", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/components/RoiCalculator.jsx:1698"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-acdbd7a78a41d998", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/GoogleDashboardPage.jsx:1393", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/GoogleDashboardPage.jsx:1393"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-dc4e2856ee94789b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/RoiPublicViewPage.jsx:344", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/RoiPublicViewPage.jsx:344"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-a9abbcb3cfd65fef", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/AdminPage.jsx:314", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/AdminPage.jsx:314"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d0c9770cb392ec70", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/DashboardPage.jsx:1743", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/DashboardPage.jsx:1743"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-61fd684a8176aa77", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/FocusPageBelowFold.jsx:759", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/FocusPageBelowFold.jsx:759"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d63da3583b14afc0", "name": "Dockerfile runs as root: Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8987d6d1c30c7202", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-aa5acaa49eb8315b", "name": "Containers defined but no K8s/orchestration manifest found", "shortDescription": {"text": "Containers defined but no K8s/orchestration manifest found"}, "fullDescription": {"text": "Repo has Dockerfiles/compose but no Kubernetes/Nomad manifests. If the target deployment is K8s, the manifests may live in a separate ops repo."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ecec3f5e9564ec71", "name": "Possible secret in scripts/test-db.mjs", "shortDescription": {"text": "Possible secret in scripts/test-db.mjs"}, "fullDescription": {"text": "Detected pattern matching password_literal. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-1d0118844862f919", "name": "Insecure pattern 'local_storage_auth_token' in src/contexts/AuthContext.jsx:32", "shortDescription": {"text": "Insecure pattern 'local_storage_auth_token' in src/contexts/AuthContext.jsx:32"}, "fullDescription": {"text": "Found a known-risky pattern (local_storage_auth_token). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-c7c4c7e899bb15f0", "name": "Insecure pattern 'document_write' in src/pages/AdminPage.jsx:1082", "shortDescription": {"text": "Insecure pattern 'document_write' in src/pages/AdminPage.jsx:1082"}, "fullDescription": {"text": "Found a known-risky pattern (document_write). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3cac53684d4bdc81", "name": "Very large file: server.js (2961 lines)", "shortDescription": {"text": "Very large file: server.js (2961 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8c935ad41083679b", "name": "Very large file: src/components/RoiCalculator.jsx (2586 lines)", "shortDescription": {"text": "Very large file: src/components/RoiCalculator.jsx (2586 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b3bde672d2813b39", "name": "Very large file: src/pages/GoogleDashboardPage.jsx (1809 lines)", "shortDescription": {"text": "Very large file: src/pages/GoogleDashboardPage.jsx (1809 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1e46652ac782a9c3", "name": "Very large file: src/pages/AdminPage.jsx (3245 lines)", "shortDescription": {"text": "Very large file: src/pages/AdminPage.jsx (3245 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c893c74ef0c24d40", "name": "Very large file: src/pages/DashboardPage.jsx (2007 lines)", "shortDescription": {"text": "Very large file: src/pages/DashboardPage.jsx (2007 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2552cc4ff7c199bf", "name": "Very large file: src/pages/FocusPageBelowFold.jsx (1382 lines)", "shortDescription": {"text": "Very large file: src/pages/FocusPageBelowFold.jsx (1382 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "3 test file(s) for 36 source file(s) (ratio 0.08). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-faccb9061e9b52a0", "name": "No README detected", "shortDescription": {"text": "No README detected"}, "fullDescription": {"text": "No README file was found. Generated repos without README context are hard to operate, validate, or safely hand off."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 45 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 60 placeholder/mock markers across 8 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, operator-readme. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ea8f3013f588db25", "name": "Shallow git history limits provenance confidence", "shortDescription": {"text": "Shallow git history limits provenance confidence"}, "fullDescription": {"text": "The repository is a shallow clone. Origin/evolution analysis cannot distinguish fresh generation, imported legacy code, or long-lived human code with high confidence."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8424db9c75e04ba4", "name": "Very short observed git history", "shortDescription": {"text": "Very short observed git history"}, "fullDescription": {"text": "The repo has multiple source files but two or fewer visible commits. This is not a failure by itself, but it lowers confidence in evolution-based diagnosis."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d5d744f4888e6aa8", "name": "Commented-code block (5 lines) in scripts/create-admin.mjs:1", "shortDescription": {"text": "Commented-code block (5 lines) in scripts/create-admin.mjs:1"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-7c29bf39414d8ba0", "name": "Legacy-named symbol `focus_roi_migrated_v1` in src/components/RoiCalculator.jsx:1644", "shortDescription": {"text": "Legacy-named symbol `focus_roi_migrated_v1` in src/components/RoiCalculator.jsx:1644"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9d2d44d2193da125", "name": "Commented-code block (5 lines) in src/components/RoiCalculator.jsx:993", "shortDescription": {"text": "Commented-code block (5 lines) in src/components/RoiCalculator.jsx:993"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-9e8b71197f66bb7a", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/contexts/AuthContext.jsx:23", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/contexts/AuthContext.jsx:23"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-54384ff5e7150528", "name": "Commented-code block (5 lines) in src/lib/benchmarks.js:1", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/benchmarks.js:1"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1aabb665c6400a33", "name": "Dangling fetch: POST https://oauth2.googleapis.com/token (scripts/test-google-ads.js:54)", "shortDescription": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (scripts/test-google-ads.js:54)"}, "fullDescription": {"text": "`scripts/test-google-ads.js:54` calls `POST https://oauth2.googleapis.com/token` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/oauth2.googleapis.com/token`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-b24de6824425b3b1", "name": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-", "shortDescription": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-ads.js:82)"}, "fullDescription": {"text": "`scripts/test-google-ads.js:82` calls `POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/googleads.googleapis.com/v20/customers/<p>/googleads/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-bc7d78abf9df72ab", "name": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-", "shortDescription": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-ads.js:135)"}, "fullDescription": {"text": "`scripts/test-google-ads.js:135` calls `POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/googleads.googleapis.com/v20/customers/<p>/googleads/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-cbbf5db4ab0b52ec", "name": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/google.js:42)", "shortDescription": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/google.js:42)"}, "fullDescription": {"text": "`lib/google.js:42` calls `POST https://oauth2.googleapis.com/token` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/oauth2.googleapis.com/token`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-855513a978653b3f", "name": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${cid}/googleAds:search (lib/google.js:79)", "shortDescription": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${cid}/googleAds:search (lib/google.js:79)"}, "fullDescription": {"text": "`lib/google.js:79` calls `POST https://googleads.googleapis.com/v20/customers/${cid}/googleAds:search` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/googleads.googleapis.com/v20/customers/<p>/googleads/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-73e6bfffc82896c6", "name": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/gmb.js:46)", "shortDescription": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/gmb.js:46)"}, "fullDescription": {"text": "`lib/gmb.js:46` calls `POST https://oauth2.googleapis.com/token` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/oauth2.googleapis.com/token`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c80f6312814e113d", "name": "Dangling fetch: GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts (lib/gmb.js:160)", "shortDescription": {"text": "Dangling fetch: GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts (lib/gmb.js:160)"}, "fullDescription": {"text": "`lib/gmb.js:160` calls `GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/mybusinessaccountmanagement.googleapis.com/v1/accounts`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-888e9d90c204fb43", "name": "Dangling fetch: GET https://mybusinessbusinessinformation.googleapis.com/v1/${accountName}/locations (lib/gmb.js:179)", "shortDescription": {"text": "Dangling fetch: GET https://mybusinessbusinessinformation.googleapis.com/v1/${accountName}/locations (lib/gmb.js:179)"}, "fullDescription": {"text": "`lib/gmb.js:179` calls `GET https://mybusinessbusinessinformation.googleapis.com/v1/${accountName}/locations` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/mybusinessbusinessinformation.googleapis.com/v1/<p>/locations`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-beac1e4adb7a01b3", "name": "Dangling fetch: GET https://mybusinessreviews.googleapis.com/v1/${locationName}/reviews (lib/gmb.js:220)", "shortDescription": {"text": "Dangling fetch: GET https://mybusinessreviews.googleapis.com/v1/${locationName}/reviews (lib/gmb.js:220)"}, "fullDescription": {"text": "`lib/gmb.js:220` calls `GET https://mybusinessreviews.googleapis.com/v1/${locationName}/reviews` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/mybusinessreviews.googleapis.com/v1/<p>/reviews`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-768bdf245eb9f909", "name": "Dangling fetch: GET https://businessprofileperformance.googleapis.com/v1/locations/${locationId}:fetchMultiDailyMetricsT", "shortDescription": {"text": "Dangling fetch: GET https://businessprofileperformance.googleapis.com/v1/locations/${locationId}:fetchMultiDailyMetricsTimeSeries (lib/gmb.js:292)"}, "fullDescription": {"text": "`lib/gmb.js:292` calls `GET https://businessprofileperformance.googleapis.com/v1/locations/${locationId}:fetchMultiDailyMetricsTimeSeries` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/https:/businessprofileperformance.googleapis.com/v1/locations/<p>/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c7a05d36b74b51ae", "name": "Unused endpoint: GET /api/clients", "shortDescription": {"text": "Unused endpoint: GET /api/clients"}, "fullDescription": {"text": "`server.js` declares `GET /api/clients` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-44f3d4d3c08e6182", "name": "Unused endpoint: GET /api/config/clients", "shortDescription": {"text": "Unused endpoint: GET /api/config/clients"}, "fullDescription": {"text": "`server.js` declares `GET /api/config/clients` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-66eca6eaeca31058", "name": "Unused endpoint: POST /api/config/clients", "shortDescription": {"text": "Unused endpoint: POST /api/config/clients"}, "fullDescription": {"text": "`server.js` declares `POST /api/config/clients` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-344f372c2bcfc17b", "name": "Unused endpoint: PUT /api/config/clients/:id", "shortDescription": {"text": "Unused endpoint: PUT /api/config/clients/:id"}, "fullDescription": {"text": "`server.js` declares `PUT /api/config/clients/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d845cd9ab0f1c0e1", "name": "Unused endpoint: DELETE /api/config/clients/:id", "shortDescription": {"text": "Unused endpoint: DELETE /api/config/clients/:id"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/config/clients/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5de711d06bee973e", "name": "Unused endpoint: PATCH /api/config/clients/:id/notes", "shortDescription": {"text": "Unused endpoint: PATCH /api/config/clients/:id/notes"}, "fullDescription": {"text": "`server.js` declares `PATCH /api/config/clients/:id/notes` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9dc3d9ac29e9492d", "name": "Unused endpoint: POST /api/config/test-connection", "shortDescription": {"text": "Unused endpoint: POST /api/config/test-connection"}, "fullDescription": {"text": "`server.js` declares `POST /api/config/test-connection` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4e43ccb397ece9e6", "name": "Unused endpoint: GET /api/insights", "shortDescription": {"text": "Unused endpoint: GET /api/insights"}, "fullDescription": {"text": "`server.js` declares `GET /api/insights` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-af8f926b5763b6d7", "name": "Unused endpoint: GET /api/trend", "shortDescription": {"text": "Unused endpoint: GET /api/trend"}, "fullDescription": {"text": "`server.js` declares `GET /api/trend` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e6af94b1ad21aad1", "name": "Unused endpoint: GET /api/alert-rules", "shortDescription": {"text": "Unused endpoint: GET /api/alert-rules"}, "fullDescription": {"text": "`server.js` declares `GET /api/alert-rules` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6c2d5078c59095c0", "name": "Unused endpoint: POST /api/alert-rules", "shortDescription": {"text": "Unused endpoint: POST /api/alert-rules"}, "fullDescription": {"text": "`server.js` declares `POST /api/alert-rules` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-28ab944f36a1ad0e", "name": "Unused endpoint: PATCH /api/alert-rules/:id", "shortDescription": {"text": "Unused endpoint: PATCH /api/alert-rules/:id"}, "fullDescription": {"text": "`server.js` declares `PATCH /api/alert-rules/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-da16dc9bf26dd6f6", "name": "Unused endpoint: DELETE /api/alert-rules/:id", "shortDescription": {"text": "Unused endpoint: DELETE /api/alert-rules/:id"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/alert-rules/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b4d87f54d62a1386", "name": "Unused endpoint: GET /api/admin/users", "shortDescription": {"text": "Unused endpoint: GET /api/admin/users"}, "fullDescription": {"text": "`server.js` declares `GET /api/admin/users` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4aa35f9c575955ad", "name": "Unused endpoint: POST /api/admin/users", "shortDescription": {"text": "Unused endpoint: POST /api/admin/users"}, "fullDescription": {"text": "`server.js` declares `POST /api/admin/users` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-429e697b3567184c", "name": "Unused endpoint: DELETE /api/admin/users/:username", "shortDescription": {"text": "Unused endpoint: DELETE /api/admin/users/:username"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/admin/users/:username` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-fab85694212d49f5", "name": "Unused endpoint: GET /api/roi/plans", "shortDescription": {"text": "Unused endpoint: GET /api/roi/plans"}, "fullDescription": {"text": "`server.js` declares `GET /api/roi/plans` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d23ff5289d12c699", "name": "Unused endpoint: GET /api/roi/plans/:id", "shortDescription": {"text": "Unused endpoint: GET /api/roi/plans/:id"}, "fullDescription": {"text": "`server.js` declares `GET /api/roi/plans/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e14aa98c762391aa", "name": "Unused endpoint: POST /api/roi/plans", "shortDescription": {"text": "Unused endpoint: POST /api/roi/plans"}, "fullDescription": {"text": "`server.js` declares `POST /api/roi/plans` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b3ced499d347b887", "name": "Unused endpoint: PUT /api/roi/plans/:id", "shortDescription": {"text": "Unused endpoint: PUT /api/roi/plans/:id"}, "fullDescription": {"text": "`server.js` declares `PUT /api/roi/plans/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-baed74c45ac69735", "name": "Unused endpoint: DELETE /api/roi/plans/:id", "shortDescription": {"text": "Unused endpoint: DELETE /api/roi/plans/:id"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/roi/plans/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-752bc6636e9b2bfd", "name": "Unused endpoint: POST /api/roi/plans/:id/share", "shortDescription": {"text": "Unused endpoint: POST /api/roi/plans/:id/share"}, "fullDescription": {"text": "`server.js` declares `POST /api/roi/plans/:id/share` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1ca011effe8b26ea", "name": "Unused endpoint: DELETE /api/roi/plans/:id/share", "shortDescription": {"text": "Unused endpoint: DELETE /api/roi/plans/:id/share"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/roi/plans/:id/share` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-eab2ee61dc0af88a", "name": "Unused endpoint: GET /api/anomalies", "shortDescription": {"text": "Unused endpoint: GET /api/anomalies"}, "fullDescription": {"text": "`server.js` declares `GET /api/anomalies` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1cd6ff9aec438e35", "name": "Unused endpoint: GET /api/campaigns", "shortDescription": {"text": "Unused endpoint: GET /api/campaigns"}, "fullDescription": {"text": "`server.js` declares `GET /api/campaigns` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-bde79939d6f149f0", "name": "Unused endpoint: GET /api/creatives", "shortDescription": {"text": "Unused endpoint: GET /api/creatives"}, "fullDescription": {"text": "`server.js` declares `GET /api/creatives` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-05e93eb5bc35491f", "name": "Unused endpoint: GET /api/google/insights", "shortDescription": {"text": "Unused endpoint: GET /api/google/insights"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/insights` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9dfc582f9a4ce0a4", "name": "Unused endpoint: GET /api/google/trend", "shortDescription": {"text": "Unused endpoint: GET /api/google/trend"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/trend` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3c6a0f1890c5cc44", "name": "Unused endpoint: GET /api/google/campaigns", "shortDescription": {"text": "Unused endpoint: GET /api/google/campaigns"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/campaigns` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f3ba9280144350e1", "name": "Unused endpoint: GET /api/google/youtube", "shortDescription": {"text": "Unused endpoint: GET /api/google/youtube"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/youtube` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cabbcfe67985b21e", "name": "Unused endpoint: GET /api/google/adgroups", "shortDescription": {"text": "Unused endpoint: GET /api/google/adgroups"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/adgroups` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a8c7d7c733126aa5", "name": "Unused endpoint: GET /api/google/devices", "shortDescription": {"text": "Unused endpoint: GET /api/google/devices"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/devices` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-81fc02a455127e0b", "name": "Unused endpoint: GET /api/google/ads", "shortDescription": {"text": "Unused endpoint: GET /api/google/ads"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/ads` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6d9de94e76120e63", "name": "Unused endpoint: GET /api/google/keywords", "shortDescription": {"text": "Unused endpoint: GET /api/google/keywords"}, "fullDescription": {"text": "`server.js` declares `GET /api/google/keywords` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-74dee9a27cc5e672", "name": "Unused endpoint: GET /api/gmb/insights", "shortDescription": {"text": "Unused endpoint: GET /api/gmb/insights"}, "fullDescription": {"text": "`server.js` declares `GET /api/gmb/insights` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-74642487b29a4fd9", "name": "Unused endpoint: GET /api/gmb/reviews", "shortDescription": {"text": "Unused endpoint: GET /api/gmb/reviews"}, "fullDescription": {"text": "`server.js` declares `GET /api/gmb/reviews` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ecfda4b306a8006a", "name": "Unused endpoint: GET /api/gmb/locations", "shortDescription": {"text": "Unused endpoint: GET /api/gmb/locations"}, "fullDescription": {"text": "`server.js` declares `GET /api/gmb/locations` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9d3d909e4d739a76", "name": "Unused endpoint: GET /api/anomalies/history", "shortDescription": {"text": "Unused endpoint: GET /api/anomalies/history"}, "fullDescription": {"text": "`server.js` declares `GET /api/anomalies/history` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-216e9b2159753855", "name": "Unused endpoint: GET /api/report/monthly", "shortDescription": {"text": "Unused endpoint: GET /api/report/monthly"}, "fullDescription": {"text": "`server.js` declares `GET /api/report/monthly` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-26e8db1d9b20052e", "name": "Unused endpoint: GET /*path", "shortDescription": {"text": "Unused endpoint: GET /*path"}, "fullDescription": {"text": "`server.js` declares `GET /*path` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f1b01d41020f33db", "name": "Unused endpoint: GET /api/report-schedules", "shortDescription": {"text": "Unused endpoint: GET /api/report-schedules"}, "fullDescription": {"text": "`server.js` declares `GET /api/report-schedules` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2acf867d6cb7bf59", "name": "Unused endpoint: POST /api/report-schedules", "shortDescription": {"text": "Unused endpoint: POST /api/report-schedules"}, "fullDescription": {"text": "`server.js` declares `POST /api/report-schedules` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a97f627d5f40653a", "name": "Unused endpoint: PATCH /api/report-schedules/:id", "shortDescription": {"text": "Unused endpoint: PATCH /api/report-schedules/:id"}, "fullDescription": {"text": "`server.js` declares `PATCH /api/report-schedules/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ee8ea644dd5dcdcd", "name": "Unused endpoint: DELETE /api/report-schedules/:id", "shortDescription": {"text": "Unused endpoint: DELETE /api/report-schedules/:id"}, "fullDescription": {"text": "`server.js` declares `DELETE /api/report-schedules/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e005f6b7b0ecb3f7", "name": "Unused endpoint: POST /api/report-schedules/:id/send-now", "shortDescription": {"text": "Unused endpoint: POST /api/report-schedules/:id/send-now"}, "fullDescription": {"text": "`server.js` declares `POST /api/report-schedules/:id/send-now` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5291aba3237e4638", "name": "Unused endpoint: GET /api/cron/collect", "shortDescription": {"text": "Unused endpoint: GET /api/cron/collect"}, "fullDescription": {"text": "`server.js` declares `GET /api/cron/collect` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f475275fa6689ceb", "name": "Unused endpoint: GET /api/cron/reports", "shortDescription": {"text": "Unused endpoint: GET /api/cron/reports"}, "fullDescription": {"text": "`server.js` declares `GET /api/cron/reports` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-dde3adb27bf7eebe", "name": "Unused endpoint: USE /api", "shortDescription": {"text": "Unused endpoint: USE /api"}, "fullDescription": {"text": "`server.js` declares `USE /api` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/20088"}, "properties": {"repository": "SPAWN-47/focus-dashboard", "repoUrl": "https://github.com/SPAWN-47/focus-dashboard", "branch": "main"}, "results": [{"ruleId": "scanner-5b6b662a2cf93466", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server.js:140"}, "properties": {"repobilityId": "a9deebb5fdc93edc", "scanner": "scanner-primary", "fingerprint": "5b6b662a2cf93466", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-1ca42bd9a19b3d92", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 scripts/test-google-ads.js:22"}, "properties": {"repobilityId": "1ea7d73c3513ce62", "scanner": "scanner-primary", "fingerprint": "1ca42bd9a19b3d92", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-90108ff30fa5022f", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 lib/db.js:74"}, "properties": {"repobilityId": "410b356045e362c5", "scanner": "scanner-primary", "fingerprint": "90108ff30fa5022f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-6cc26d1375030cb9", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/RoiCalculator.jsx:309"}, "properties": {"repobilityId": "02ca50c94974e8ea", "scanner": "scanner-primary", "fingerprint": "6cc26d1375030cb9", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f3bb99e4a0414c6c", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/components/RoiCalculator.jsx:1698"}, "properties": {"repobilityId": "dc38cee8fa4b3c1b", "scanner": "scanner-primary", "fingerprint": "f3bb99e4a0414c6c", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-acdbd7a78a41d998", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/GoogleDashboardPage.jsx:1393"}, "properties": {"repobilityId": "ba5f9029efcd1932", "scanner": "scanner-primary", "fingerprint": "acdbd7a78a41d998", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-dc4e2856ee94789b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/RoiPublicViewPage.jsx:344"}, "properties": {"repobilityId": "4edbff75a847d65a", "scanner": "scanner-primary", "fingerprint": "dc4e2856ee94789b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a9abbcb3cfd65fef", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/AdminPage.jsx:314"}, "properties": {"repobilityId": "80ce6132fec2e9a4", "scanner": "scanner-primary", "fingerprint": "a9abbcb3cfd65fef", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d0c9770cb392ec70", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/DashboardPage.jsx:1743"}, "properties": {"repobilityId": "c1ec453865b8a459", "scanner": "scanner-primary", "fingerprint": "d0c9770cb392ec70", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-61fd684a8176aa77", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/FocusPageBelowFold.jsx:759"}, "properties": {"repobilityId": "06f0f73f27685b94", "scanner": "scanner-primary", "fingerprint": "61fd684a8176aa77", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d63da3583b14afc0", "level": "warning", "message": {"text": "Dockerfile runs as root: Dockerfile"}, "properties": {"repobilityId": "a2ed1bd120e507db", "scanner": "scanner-primary", "fingerprint": "d63da3583b14afc0", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-8987d6d1c30c7202", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "properties": {"repobilityId": "0c42a25bc06b35c7", "scanner": "scanner-primary", "fingerprint": "8987d6d1c30c7202", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "Dockerfile"}, "region": {"startLine": 3}}}]}, {"ruleId": "scanner-aa5acaa49eb8315b", "level": "note", "message": {"text": "Containers defined but no K8s/orchestration manifest found"}, "properties": {"repobilityId": "b230ea9b68736081", "scanner": "scanner-primary", "fingerprint": "aa5acaa49eb8315b", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["coverage", "deployment"]}}, {"ruleId": "scanner-ecec3f5e9564ec71", "level": "error", "message": {"text": "Possible secret in scripts/test-db.mjs"}, "properties": {"repobilityId": "a7c07bd83047349c", "scanner": "scanner-primary", "fingerprint": "ecec3f5e9564ec71", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "scripts/test-db.mjs"}, "region": {"startLine": 74}}}]}, {"ruleId": "scanner-1d0118844862f919", "level": "warning", "message": {"text": "Insecure pattern 'local_storage_auth_token' in src/contexts/AuthContext.jsx:32"}, "properties": {"repobilityId": "09ac462f0aec2737", "scanner": "scanner-primary", "fingerprint": "1d0118844862f919", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "local_storage_auth_token"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/contexts/AuthContext.jsx"}, "region": {"startLine": 32}}}]}, {"ruleId": "scanner-c7c4c7e899bb15f0", "level": "note", "message": {"text": "Insecure pattern 'document_write' in src/pages/AdminPage.jsx:1082"}, "properties": {"repobilityId": "ab0708187d83bb21", "scanner": "scanner-primary", "fingerprint": "c7c4c7e899bb15f0", "layer": "security", "severity": "low", "confidence": 1.0, "tags": ["owasp", "document_write"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/pages/AdminPage.jsx"}, "region": {"startLine": 1082}}}]}, {"ruleId": "scanner-3cac53684d4bdc81", "level": "note", "message": {"text": "Very large file: server.js (2961 lines)"}, "properties": {"repobilityId": "1479ba50e708c5c1", "scanner": "scanner-primary", "fingerprint": "3cac53684d4bdc81", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-8c935ad41083679b", "level": "note", "message": {"text": "Very large file: src/components/RoiCalculator.jsx (2586 lines)"}, "properties": {"repobilityId": "f2488b837b565c13", "scanner": "scanner-primary", "fingerprint": "8c935ad41083679b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-b3bde672d2813b39", "level": "note", "message": {"text": "Very large file: src/pages/GoogleDashboardPage.jsx (1809 lines)"}, "properties": {"repobilityId": "fb569dcd2cfe0495", "scanner": "scanner-primary", "fingerprint": "b3bde672d2813b39", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-1e46652ac782a9c3", "level": "note", "message": {"text": "Very large file: src/pages/AdminPage.jsx (3245 lines)"}, "properties": {"repobilityId": "e1d74ed5cc6444e6", "scanner": "scanner-primary", "fingerprint": "1e46652ac782a9c3", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-c893c74ef0c24d40", "level": "note", "message": {"text": "Very large file: src/pages/DashboardPage.jsx (2007 lines)"}, "properties": {"repobilityId": "8b5231ac91c8139b", "scanner": "scanner-primary", "fingerprint": "c893c74ef0c24d40", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-2552cc4ff7c199bf", "level": "note", "message": {"text": "Very large file: src/pages/FocusPageBelowFold.jsx (1382 lines)"}, "properties": {"repobilityId": "59f6e68ad354d319", "scanner": "scanner-primary", "fingerprint": "2552cc4ff7c199bf", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "3cbbce808dc895ea", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-faccb9061e9b52a0", "level": "note", "message": {"text": "No README detected"}, "properties": {"repobilityId": "de4d1af738cdbc7c", "scanner": "scanner-primary", "fingerprint": "faccb9061e9b52a0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["docs", "readme", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "c0c93623b95b9291", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "d0d1911e509c84d5", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "a2a5e2da80ae93ae", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "note", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "12a37e552b8dc4cc", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "3ceea464c2cec388", "scanner": "scanner-primary", "fingerprint": "ea8f3013f588db25", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-8424db9c75e04ba4", "level": "none", "message": {"text": "Very short observed git history"}, "properties": {"repobilityId": "f1afbe633b22de24", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-d5d744f4888e6aa8", "level": "none", "message": {"text": "Commented-code block (5 lines) in scripts/create-admin.mjs:1"}, "properties": {"repobilityId": "c0d90585654a7c0f", "scanner": "scanner-primary", "fingerprint": "d5d744f4888e6aa8", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7c29bf39414d8ba0", "level": "note", "message": {"text": "Legacy-named symbol `focus_roi_migrated_v1` in src/components/RoiCalculator.jsx:1644"}, "properties": {"repobilityId": "98039a319e2571f0", "scanner": "scanner-primary", "fingerprint": "7c29bf39414d8ba0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-9d2d44d2193da125", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/components/RoiCalculator.jsx:993"}, "properties": {"repobilityId": "c3a28685736ce784", "scanner": "scanner-primary", "fingerprint": "9d2d44d2193da125", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-9e8b71197f66bb7a", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/contexts/AuthContext.jsx:23"}, "properties": {"repobilityId": "db7e2897e4179934", "scanner": "scanner-primary", "fingerprint": "9e8b71197f66bb7a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-54384ff5e7150528", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/benchmarks.js:1"}, "properties": {"repobilityId": "03de813283335939", "scanner": "scanner-primary", "fingerprint": "54384ff5e7150528", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-1aabb665c6400a33", "level": "error", "message": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (scripts/test-google-ads.js:54)"}, "properties": {"repobilityId": "9af53ca542361d6c", "scanner": "scanner-primary", "fingerprint": "1aabb665c6400a33", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-b24de6824425b3b1", "level": "error", "message": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-ads.js:82)"}, "properties": {"repobilityId": "8718dcfb4e08d045", "scanner": "scanner-primary", "fingerprint": "b24de6824425b3b1", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-bc7d78abf9df72ab", "level": "error", "message": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${customerId}/googleAds:search (scripts/test-google-ads.js:135)"}, "properties": {"repobilityId": "d658d47a1c1ea400", "scanner": "scanner-primary", "fingerprint": "bc7d78abf9df72ab", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-cbbf5db4ab0b52ec", "level": "error", "message": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/google.js:42)"}, "properties": {"repobilityId": "b24a4f71820e6309", "scanner": "scanner-primary", "fingerprint": "cbbf5db4ab0b52ec", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-855513a978653b3f", "level": "error", "message": {"text": "Dangling fetch: POST https://googleads.googleapis.com/v20/customers/${cid}/googleAds:search (lib/google.js:79)"}, "properties": {"repobilityId": "15660a0127b31531", "scanner": "scanner-primary", "fingerprint": "855513a978653b3f", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-73e6bfffc82896c6", "level": "error", "message": {"text": "Dangling fetch: POST https://oauth2.googleapis.com/token (lib/gmb.js:46)"}, "properties": {"repobilityId": "15bb92d13b7858da", "scanner": "scanner-primary", "fingerprint": "73e6bfffc82896c6", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-c80f6312814e113d", "level": "error", "message": {"text": "Dangling fetch: GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts (lib/gmb.js:160)"}, "properties": {"repobilityId": "6d793e480dd0be77", "scanner": "scanner-primary", "fingerprint": "c80f6312814e113d", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-888e9d90c204fb43", "level": "error", "message": {"text": "Dangling fetch: GET https://mybusinessbusinessinformation.googleapis.com/v1/${accountName}/locations (lib/gmb.js:179)"}, "properties": {"repobilityId": "f9800543727b4f75", "scanner": "scanner-primary", "fingerprint": "888e9d90c204fb43", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-beac1e4adb7a01b3", "level": "error", "message": {"text": "Dangling fetch: GET https://mybusinessreviews.googleapis.com/v1/${locationName}/reviews (lib/gmb.js:220)"}, "properties": {"repobilityId": "3ec3556b1c62cfe9", "scanner": "scanner-primary", "fingerprint": "beac1e4adb7a01b3", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-768bdf245eb9f909", "level": "error", "message": {"text": "Dangling fetch: GET https://businessprofileperformance.googleapis.com/v1/locations/${locationId}:fetchMultiDailyMetricsTimeSeries (lib/gmb.js:292)"}, "properties": {"repobilityId": "2be6c465a28d9387", "scanner": "scanner-primary", "fingerprint": "768bdf245eb9f909", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-c7a05d36b74b51ae", "level": "note", "message": {"text": "Unused endpoint: GET /api/clients"}, "properties": {"repobilityId": "67620b03fb9cf39b", "scanner": "scanner-primary", "fingerprint": "c7a05d36b74b51ae", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-44f3d4d3c08e6182", "level": "note", "message": {"text": "Unused endpoint: GET /api/config/clients"}, "properties": {"repobilityId": "402a25d57353680d", "scanner": "scanner-primary", "fingerprint": "44f3d4d3c08e6182", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-66eca6eaeca31058", "level": "note", "message": {"text": "Unused endpoint: POST /api/config/clients"}, "properties": {"repobilityId": "fce1a8bbb3fd1d21", "scanner": "scanner-primary", "fingerprint": "66eca6eaeca31058", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-344f372c2bcfc17b", "level": "note", "message": {"text": "Unused endpoint: PUT /api/config/clients/:id"}, "properties": {"repobilityId": "040c9e1d8aefb73f", "scanner": "scanner-primary", "fingerprint": "344f372c2bcfc17b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d845cd9ab0f1c0e1", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/config/clients/:id"}, "properties": {"repobilityId": "da603387d6bfd36e", "scanner": "scanner-primary", "fingerprint": "d845cd9ab0f1c0e1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5de711d06bee973e", "level": "note", "message": {"text": "Unused endpoint: PATCH /api/config/clients/:id/notes"}, "properties": {"repobilityId": "d1ad2d4ddeecd5f9", "scanner": "scanner-primary", "fingerprint": "5de711d06bee973e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9dc3d9ac29e9492d", "level": "note", "message": {"text": "Unused endpoint: POST /api/config/test-connection"}, "properties": {"repobilityId": "70559a6cae0d238f", "scanner": "scanner-primary", "fingerprint": "9dc3d9ac29e9492d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4e43ccb397ece9e6", "level": "note", "message": {"text": "Unused endpoint: GET /api/insights"}, "properties": {"repobilityId": "aed1c62886036df5", "scanner": "scanner-primary", "fingerprint": "4e43ccb397ece9e6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-af8f926b5763b6d7", "level": "note", "message": {"text": "Unused endpoint: GET /api/trend"}, "properties": {"repobilityId": "b02558f501adbb26", "scanner": "scanner-primary", "fingerprint": "af8f926b5763b6d7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e6af94b1ad21aad1", "level": "note", "message": {"text": "Unused endpoint: GET /api/alert-rules"}, "properties": {"repobilityId": "38e060b3d0fdd4d4", "scanner": "scanner-primary", "fingerprint": "e6af94b1ad21aad1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6c2d5078c59095c0", "level": "note", "message": {"text": "Unused endpoint: POST /api/alert-rules"}, "properties": {"repobilityId": "258ff7d009d1c57e", "scanner": "scanner-primary", "fingerprint": "6c2d5078c59095c0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-28ab944f36a1ad0e", "level": "note", "message": {"text": "Unused endpoint: PATCH /api/alert-rules/:id"}, "properties": {"repobilityId": "26b27692fa34c891", "scanner": "scanner-primary", "fingerprint": "28ab944f36a1ad0e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-da16dc9bf26dd6f6", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/alert-rules/:id"}, "properties": {"repobilityId": "5ed4b1ba4959053b", "scanner": "scanner-primary", "fingerprint": "da16dc9bf26dd6f6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b4d87f54d62a1386", "level": "note", "message": {"text": "Unused endpoint: GET /api/admin/users"}, "properties": {"repobilityId": "cdd56bf6fa5be168", "scanner": "scanner-primary", "fingerprint": "b4d87f54d62a1386", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4aa35f9c575955ad", "level": "note", "message": {"text": "Unused endpoint: POST /api/admin/users"}, "properties": {"repobilityId": "812b8c028bdd0080", "scanner": "scanner-primary", "fingerprint": "4aa35f9c575955ad", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-429e697b3567184c", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/admin/users/:username"}, "properties": {"repobilityId": "c0dd3a35a67e991b", "scanner": "scanner-primary", "fingerprint": "429e697b3567184c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fab85694212d49f5", "level": "note", "message": {"text": "Unused endpoint: GET /api/roi/plans"}, "properties": {"repobilityId": "3b7b85c56c36ddd8", "scanner": "scanner-primary", "fingerprint": "fab85694212d49f5", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d23ff5289d12c699", "level": "note", "message": {"text": "Unused endpoint: GET /api/roi/plans/:id"}, "properties": {"repobilityId": "01bf339d13cc92b2", "scanner": "scanner-primary", "fingerprint": "d23ff5289d12c699", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e14aa98c762391aa", "level": "note", "message": {"text": "Unused endpoint: POST /api/roi/plans"}, "properties": {"repobilityId": "c628c00bdbb8171e", "scanner": "scanner-primary", "fingerprint": "e14aa98c762391aa", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b3ced499d347b887", "level": "note", "message": {"text": "Unused endpoint: PUT /api/roi/plans/:id"}, "properties": {"repobilityId": "2acb56d3e9d1be21", "scanner": "scanner-primary", "fingerprint": "b3ced499d347b887", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-baed74c45ac69735", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/roi/plans/:id"}, "properties": {"repobilityId": "055db9ab31567360", "scanner": "scanner-primary", "fingerprint": "baed74c45ac69735", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-752bc6636e9b2bfd", "level": "note", "message": {"text": "Unused endpoint: POST /api/roi/plans/:id/share"}, "properties": {"repobilityId": "a8fa31869e1b09d2", "scanner": "scanner-primary", "fingerprint": "752bc6636e9b2bfd", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1ca011effe8b26ea", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/roi/plans/:id/share"}, "properties": {"repobilityId": "eb9816ff4bc6e166", "scanner": "scanner-primary", "fingerprint": "1ca011effe8b26ea", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-eab2ee61dc0af88a", "level": "note", "message": {"text": "Unused endpoint: GET /api/anomalies"}, "properties": {"repobilityId": "5b92103b25a087b4", "scanner": "scanner-primary", "fingerprint": "eab2ee61dc0af88a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1cd6ff9aec438e35", "level": "note", "message": {"text": "Unused endpoint: GET /api/campaigns"}, "properties": {"repobilityId": "de7b2f97f5c7a616", "scanner": "scanner-primary", "fingerprint": "1cd6ff9aec438e35", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-bde79939d6f149f0", "level": "note", "message": {"text": "Unused endpoint: GET /api/creatives"}, "properties": {"repobilityId": "567276a22e603710", "scanner": "scanner-primary", "fingerprint": "bde79939d6f149f0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-05e93eb5bc35491f", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/insights"}, "properties": {"repobilityId": "371552033ed56eb4", "scanner": "scanner-primary", "fingerprint": "05e93eb5bc35491f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9dfc582f9a4ce0a4", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/trend"}, "properties": {"repobilityId": "0d60f04d31bf1c91", "scanner": "scanner-primary", "fingerprint": "9dfc582f9a4ce0a4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3c6a0f1890c5cc44", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/campaigns"}, "properties": {"repobilityId": "2ea8fba62f1a3e15", "scanner": "scanner-primary", "fingerprint": "3c6a0f1890c5cc44", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f3ba9280144350e1", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/youtube"}, "properties": {"repobilityId": "4dd19798073f6954", "scanner": "scanner-primary", "fingerprint": "f3ba9280144350e1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cabbcfe67985b21e", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/adgroups"}, "properties": {"repobilityId": "df415a89b4eb41ae", "scanner": "scanner-primary", "fingerprint": "cabbcfe67985b21e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a8c7d7c733126aa5", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/devices"}, "properties": {"repobilityId": "9d1e29903771ad36", "scanner": "scanner-primary", "fingerprint": "a8c7d7c733126aa5", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-81fc02a455127e0b", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/ads"}, "properties": {"repobilityId": "4618210a8eaf37a8", "scanner": "scanner-primary", "fingerprint": "81fc02a455127e0b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6d9de94e76120e63", "level": "note", "message": {"text": "Unused endpoint: GET /api/google/keywords"}, "properties": {"repobilityId": "608f3bf467186174", "scanner": "scanner-primary", "fingerprint": "6d9de94e76120e63", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-74dee9a27cc5e672", "level": "note", "message": {"text": "Unused endpoint: GET /api/gmb/insights"}, "properties": {"repobilityId": "1e6e5039b89385a3", "scanner": "scanner-primary", "fingerprint": "74dee9a27cc5e672", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-74642487b29a4fd9", "level": "note", "message": {"text": "Unused endpoint: GET /api/gmb/reviews"}, "properties": {"repobilityId": "06a9292cd716c310", "scanner": "scanner-primary", "fingerprint": "74642487b29a4fd9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ecfda4b306a8006a", "level": "note", "message": {"text": "Unused endpoint: GET /api/gmb/locations"}, "properties": {"repobilityId": "240a471b1240b989", "scanner": "scanner-primary", "fingerprint": "ecfda4b306a8006a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9d3d909e4d739a76", "level": "note", "message": {"text": "Unused endpoint: GET /api/anomalies/history"}, "properties": {"repobilityId": "a5815e5eca2ca627", "scanner": "scanner-primary", "fingerprint": "9d3d909e4d739a76", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-216e9b2159753855", "level": "note", "message": {"text": "Unused endpoint: GET /api/report/monthly"}, "properties": {"repobilityId": "a37b3bda9be167e2", "scanner": "scanner-primary", "fingerprint": "216e9b2159753855", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-26e8db1d9b20052e", "level": "note", "message": {"text": "Unused endpoint: GET /*path"}, "properties": {"repobilityId": "250b6a6da724d0bd", "scanner": "scanner-primary", "fingerprint": "26e8db1d9b20052e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f1b01d41020f33db", "level": "note", "message": {"text": "Unused endpoint: GET /api/report-schedules"}, "properties": {"repobilityId": "894419ddcce9d850", "scanner": "scanner-primary", "fingerprint": "f1b01d41020f33db", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2acf867d6cb7bf59", "level": "note", "message": {"text": "Unused endpoint: POST /api/report-schedules"}, "properties": {"repobilityId": "2b27394f365cc2f1", "scanner": "scanner-primary", "fingerprint": "2acf867d6cb7bf59", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a97f627d5f40653a", "level": "note", "message": {"text": "Unused endpoint: PATCH /api/report-schedules/:id"}, "properties": {"repobilityId": "fb5acc0043ea353a", "scanner": "scanner-primary", "fingerprint": "a97f627d5f40653a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ee8ea644dd5dcdcd", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/report-schedules/:id"}, "properties": {"repobilityId": "4eb6c74834641d7b", "scanner": "scanner-primary", "fingerprint": "ee8ea644dd5dcdcd", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e005f6b7b0ecb3f7", "level": "note", "message": {"text": "Unused endpoint: POST /api/report-schedules/:id/send-now"}, "properties": {"repobilityId": "898b7536d3e763af", "scanner": "scanner-primary", "fingerprint": "e005f6b7b0ecb3f7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5291aba3237e4638", "level": "note", "message": {"text": "Unused endpoint: GET /api/cron/collect"}, "properties": {"repobilityId": "d6980cc50059b92a", "scanner": "scanner-primary", "fingerprint": "5291aba3237e4638", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f475275fa6689ceb", "level": "note", "message": {"text": "Unused endpoint: GET /api/cron/reports"}, "properties": {"repobilityId": "1b1fadaf692bf7cb", "scanner": "scanner-primary", "fingerprint": "f475275fa6689ceb", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-dde3adb27bf7eebe", "level": "note", "message": {"text": "Unused endpoint: USE /api"}, "properties": {"repobilityId": "a3eddf5065ffbf6c", "scanner": "scanner-primary", "fingerprint": "dde3adb27bf7eebe", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}