Grafana (full use of the existing monitoring/ stack, per OSS policy):
- datasources.yml: BotPostgres (uid bot-postgres) over the shared network;
grafana service joins 'shared' + carries the datasource env
- db_init.py: idempotent read-only role obs_reader (USAGE on schema public +
SELECT on bot_traces/bot_trace_events; skipped when
OBS_READER_PASSWORD empty; ALTER ROLE for rotation) + composite index
ix_bot_trace_events_stage_time (stage, created_at DESC) — senior-engineer
review applied with the column-name fix (event_type -> stage); (trace_id)
already covered by the existing (trace_id, created_at) index
- dashboards/bot-observability.json: KPI row (real traffic, events, Jev/
fallback errors, Jev p95, tokens, commits, archive guard), events/day,
per-stage p50/p95, mention statuses (arbiter+fallback aggregates + legacy
rows), DeepSeek arbiter actions, tokens/day, model-drift vs jev-1.13.0,
user-choice A/B, STT + audio.enhance health, archive size guard
- dashboards/bot-trace-explorer.json: trace table + full event drill-down
via the trace_id variable
ERP page (admin-only, Persian RTL, recharts@^3 for React 19):
- backend bot_metrics.py: read-only require_role('admin') endpoints
(summary/routing/quality/jev/stt/traces + trace detail); aggregates count
real traffic only (calibration/demo/chat_id=0 excluded)
- frontend BotMonitorPage at /bot-monitor (KPI cards, daily events,
status donut, arbiter actions, user-choice A/B, STT/enhance tables,
stage latency, tokens chart, traces table + detail drawer with payload
viewer); entry link from the admin panel; MobileTabBar hidden there
- api.ts: typed botMetrics client section
Tooling/docs:
- tools/seed_observability_demo.py: deterministic demo traces (source='demo',
every current pipeline stage incl. audio.enhance/jev.failure/arbitration/
fallback/user choices) — excluded from real-traffic aggregates
- monitoring/README.md + bot/docs/DEPLOY-AND-MONITORING.md: setup, seed and
rollback notes; alerts deliberately deferred (owner decision 2026-10-24)
Verified locally: obs_reader SELECT ok / INSERT denied; panels' SQL run as
obs_reader with data; datasource health OK; both dashboards survive a grafana
restart; endpoints 200 as admin and 403 without role; tsc + vite build clean;
page renders in-browser (admin session); bot startup provisions role+index.
50 lines
1.3 KiB
JSON
50 lines
1.3 KiB
JSON
{
|
|
"name": "procurement-ui-v2",
|
|
"private": true,
|
|
"version": "0.0.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "tsc -b && vite build",
|
|
"lint": "oxlint",
|
|
"preview": "vite preview"
|
|
},
|
|
"dependencies": {
|
|
"@dnd-kit/core": "^6.3.1",
|
|
"@dnd-kit/utilities": "^3.2.2",
|
|
"@hookform/resolvers": "3.10",
|
|
"@openpanel/web": "^1.0.1",
|
|
"@radix-ui/react-checkbox": "^1.3.11",
|
|
"@radix-ui/react-dialog": "^1.1.23",
|
|
"@radix-ui/react-label": "^2.1.15",
|
|
"@radix-ui/react-select": "^2.3.7",
|
|
"@radix-ui/react-slot": "^1.3.3",
|
|
"@sentry/react": "^10.0.0",
|
|
"@tailwindcss/vite": "^4.3.3",
|
|
"@tanstack/react-query": "^5.101.4",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"lucide-react": "^1.30.0",
|
|
"pdfjs-dist": "^4.10.38",
|
|
"react": "^19.2.8",
|
|
"react-dom": "^19.2.8",
|
|
"react-hook-form": "^7.85.0",
|
|
"react-router-dom": "^7.18.2",
|
|
"recharts": "^3.8.0",
|
|
"sonner": "^2.0.8",
|
|
"tailwind-merge": "^3.6.0",
|
|
"tailwindcss": "^4.3.3",
|
|
"zod": "3.25",
|
|
"zustand": "^5.0.14"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^24.13.3",
|
|
"@types/react": "^19.2.17",
|
|
"@types/react-dom": "^19.2.3",
|
|
"@vitejs/plugin-react": "^6.0.4",
|
|
"oxlint": "^1.75.0",
|
|
"typescript": "~6.0.2",
|
|
"vite": "^8.2.0"
|
|
}
|
|
}
|