Initial commit — Zabbix Dashboard app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
98
CLAUDE.md
Normal file
98
CLAUDE.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm install # install dependencies
|
||||
npm start # run production server (port 3000)
|
||||
npm run dev # run with --watch (auto-restart on file changes)
|
||||
```
|
||||
|
||||
There are no tests or linters configured.
|
||||
|
||||
Docker:
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Single-process Node.js app. `server.js` acts as both an API proxy (keeping the Zabbix token server-side) and a static file host for the vanilla JS frontend in `public/`.
|
||||
|
||||
```
|
||||
server.js Express backend — Zabbix JSON-RPC proxy + REST API
|
||||
public/
|
||||
index.html Shell: header, view toggle, countries layout container, modal
|
||||
style.css Light theme, CSS variables for hex sizing, hex grid layout
|
||||
app.js All frontend logic — fetch, render, interactions
|
||||
.env Runtime config (gitignored)
|
||||
docker-compose.yml Reads ZABBIX_TOKEN from env or .env
|
||||
```
|
||||
|
||||
## Config (env vars)
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `ZABBIX_URL` | `https://monitor.stranto.com` | Zabbix instance |
|
||||
| `ZABBIX_TOKEN` | — | API bearer token (required) |
|
||||
| `CUSTOMER_TAG_VALUE` | `QWE` | Zabbix host tag `customer=<value>` that identifies KFC hosts |
|
||||
| `COUNTRY_TAG` | `country` | Zabbix host tag name used for country grouping |
|
||||
| `PORT` | `3000` | HTTP port |
|
||||
|
||||
## Zabbix API conventions
|
||||
|
||||
- Auth: `Authorization: Bearer <token>` header (Zabbix 6.4+ style — NOT the legacy `auth` body field)
|
||||
- All hosts are scoped by tag `customer=QWE` (operator `1` = equals)
|
||||
- Host groups use `selectHostGroups` / `host.hostgroups` — NOT the deprecated `selectGroups` / `host.groups`
|
||||
- Countries come from a `country` host tag (e.g. `AT`, `SK`)
|
||||
- Restaurants group by `location` host tag; device types group by host group, keyed as `groupid__country`
|
||||
- Severity 0 (Not classified) and 1 (Information) are treated as OK throughout
|
||||
- Acknowledged problems are excluded via `withLastEventUnacknowledged: true`
|
||||
- `expandDescription: true` on `trigger.get` resolves `{HOST.NAME}` and other macros in descriptions
|
||||
|
||||
## Backend API endpoints
|
||||
|
||||
| Endpoint | Returns |
|
||||
|---|---|
|
||||
| `GET /api/restaurants` | Array of `{ location, country, hostCount, problemCount, severity, problems[] }` |
|
||||
| `GET /api/devices` | Same shape but grouped by host group; `name` instead of `location` |
|
||||
| `GET /api/stats` | `{ [countryCode]: { hostCount, itemCount, triggerCount } }` — fetched in parallel with grid data |
|
||||
| `GET /api/detail?type=&id=` | Per-host problem detail for modal |
|
||||
| `GET /api/config` | `{ zabbixUrl, customerTagValue }` |
|
||||
| `GET /api/health` | Zabbix connectivity check |
|
||||
|
||||
Each `problems[]` entry: `{ description, priority, lastchange (unix seconds), hostName }`, sorted by severity desc then time desc.
|
||||
|
||||
## Frontend data flow
|
||||
|
||||
1. Boot: fetch `/api/config`, then fetch grid data + `/api/stats` in parallel
|
||||
2. Items are grouped by `country` field and rendered as equal-width `.country-col` columns
|
||||
3. Each column renders: flag + country header → hex grid → problem list (locations with active problems)
|
||||
4. Single click → detail modal (`/api/detail`); double click → Zabbix Problems page in new tab (240ms timer separates the two)
|
||||
5. Auto-refresh every 30 seconds
|
||||
|
||||
## Hex grid geometry
|
||||
|
||||
For equal gaps on all 6 sides, the hex dimensions must satisfy `--hex-w = --hex-h × sin(60°) ≈ --hex-h × 0.866`. The row vertical overlap is:
|
||||
|
||||
```css
|
||||
margin-top: calc(var(--hex-h) * -0.25 + var(--hex-gap) * 0.866);
|
||||
```
|
||||
|
||||
Changing `--hex-gap` without updating `margin-top` will make diagonal gaps unequal. The even-row offset (`margin-left` on `.hex-row.offset`) is always `(hex-w + hex-gap) / 2`.
|
||||
|
||||
## Zabbix Problems URL format (7.x)
|
||||
|
||||
Parameters use **no** `filter_` prefix. Key params: `show=1` (recent), `evaltype=0`, `tags[N][tag/value/operator]`, `groupids[]`, `severities[]=2..5`. The legacy `filter_show`, `filter_tags`, `filter_set` format does not work in Zabbix 7.x.
|
||||
|
||||
## Severity mapping
|
||||
|
||||
| Zabbix priority | Label | Colour |
|
||||
|---|---|---|
|
||||
| -1 (no problems / ack / info) | OK | green `#2da44e` |
|
||||
| 2 | Warning | amber `#c69026` |
|
||||
| 3 | Average | orange `#e16f24` |
|
||||
| 4 | High | red `#d1242f` |
|
||||
| 5 | Disaster | purple `#8250df` (pulses) |
|
||||
Reference in New Issue
Block a user