docs: add root CLAUDE.md for hiveiq-ops

Covers sub-project index, agent release workflow, What's New releases.json
process, share.bcos.cloud API, and common operational mistakes. Content
sourced from hiveops-src CLAUDE.md sections that belong to ops rather than
application source.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 14:38:39 -04:00
commit d1a427cea0
+202
View File
@@ -0,0 +1,202 @@
# CLAUDE.md — hiveiq-ops
Operations repo for the HiveIQ/HiveOps platform. Split from `hiveops-src` (application source) to separate deployment configs, infrastructure, and documentation from service code.
**Application source:** `/source/hiveops-src/`
**Ops source (this repo):** `/source/hiveiq-ops/`
---
## Sub-Projects
| Directory | Purpose |
|-----------|---------|
| `hiveiq-devops/` | Docker Compose + Kubernetes + Ansible deployment configs — see `hiveiq-devops/CLAUDE.md` |
| `hiveiq-openmetal/` | Production OpenMetal cloud infrastructure (VMs, DNS, CDN, bcos infra) — see `hiveiq-openmetal/CLAUDE.md` |
| `hiveiq-docs/` | MkDocs documentation site — `mkdocs.yml` (main) + `mkdocs-qsa.yml` (QSA audit) |
**Start here for infra/VM reference:** `hiveiq-openmetal/CLAUDE.md`
**Start here for deployment configs:** `hiveiq-devops/CLAUDE.md`
---
## Releasing a New Agent Version
The agent build lives in `/source/hiveops-src/hiveops-agent/` but the release deploys to CDN (managed here in `hiveiq-openmetal`).
```bash
# 1. Bump version in source repo
cd /source/hiveops-src/hiveops-agent
mvn versions:set -DnewVersion=X.Y.Z -DgenerateBackupPoms=false
# 2. Build fat JAR
mvn clean package -DskipTests
# 3. Build dist packages — run sequentially (build-dist.sh clears dist/ each run)
deployment/build-dist.sh --release --platform windows
scp -i ~/.ssh/id_ed25519_hiveiq deployment/dist/hiveops-agent-X.Y.Z-standard-windows.zip bcosadmin@173.231.195.252:~/hiveiq/hiveops-openmetal/hiveops/instances/browser/downloads/agent/
deployment/build-dist.sh --release --patch --platform windows
scp -i ~/.ssh/id_ed25519_hiveiq deployment/dist/hiveops-agent-X.Y.Z-patch-windows.zip bcosadmin@173.231.195.252:~/hiveiq/hiveops-openmetal/hiveops/instances/browser/downloads/agent/
deployment/build-dist.sh --release --platform linux
scp -i ~/.ssh/id_ed25519_hiveiq deployment/dist/hiveops-agent-X.Y.Z-standard-linux.tar.gz bcosadmin@173.231.195.252:~/hiveiq/hiveops-openmetal/hiveops/instances/browser/downloads/agent/
deployment/build-dist.sh --release --patch --platform linux
scp -i ~/.ssh/id_ed25519_hiveiq deployment/dist/hiveops-agent-X.Y.Z-patch-linux.tar.gz bcosadmin@173.231.195.252:~/hiveiq/hiveops-openmetal/hiveops/instances/browser/downloads/agent/
# 4. Update CDN manifest — pass all 5 args so patches appear in Fleet Artifacts
ssh -i ~/.ssh/id_ed25519_hiveiq bcosadmin@173.231.195.252
cd ~/hiveiq/hiveops-openmetal/hiveops/instances/browser
./scripts/release-agent.sh X.Y.Z \
"hiveops-agent-X.Y.Z-standard-windows.zip" \
"hiveops-agent-X.Y.Z-standard-linux.tar.gz" \
"hiveops-agent-X.Y.Z-patch-windows.zip" \
"hiveops-agent-X.Y.Z-patch-linux.tar.gz"
# 5. Commit version bump + push in source repo
cd /source/hiveops-src/hiveops-agent
git add -A && git commit -m "chore(agent): bump version to X.Y.Z"
git push
# 6. Update VERSIONS.md in hiveops-src
```
**Bearer token revocation rule:** before revoking any `agent.auth.token`, push a CONFIG_UPDATE fleet-wide and wait for all tasks to drain. Revoking while ATMs still hold the token kills module threads — recovery requires a manual JVM restart on every affected ATM.
---
## Updating "What's New" Release Notes
**Repo:** `/source/hiveops-src/hiveops-release/` (separate source repo, deploy via script)
```bash
cd /source/hiveops-src/hiveops-release
# 1. Edit releases.json — prepend new entry to the relevant service array
# 2. Deploy
./deploy.sh
# 3. Verify
# https://cdn.bcos.cloud/whats-new?app=<key>
```
### Service keys in releases.json
| Key | Service |
|-----|---------|
| `browser` | HiveIQ Browser (Electron) |
| `incident` | Incident web app |
| `fleet` | Fleet web app (`fleet.bcos.cloud`) |
| `devices` | Devices web app |
| `transactions` | Transactions web app |
| `analytics` | Analytics web app |
| `agent` | HiveIQ Agent (ATM JAR) |
| `journal` | Journal microservice |
| `rules` | Journal parsing rules |
| `reports` | Reports microservice |
Entry format:
```json
{
"version": "v1.2.0",
"title": "Short descriptive title",
"date": "May 10, 2026",
"sections": [
{
"type": "added",
"items": [
{ "title": "Feature name", "note": "One sentence describing what changed and why." }
]
}
]
}
```
Section `type` values: `added`, `fixed`, `improved`, `changed`, `removed`.
---
## share.bcos.cloud — Customer File Distribution
Used to distribute patches that can't be auto-updated (e.g. ATEC Java 8 branch with `agent.update.enabled=false`).
**VM:** `bcos-share` — `173.231.195.254`
**Login:** `hiveiq@bcos.cloud`
Pingvin Share v1.13.0 reads the JWT from **cookies**, not the `Authorization` header.
```bash
# 1. Sign in
curl -s -c /tmp/pingvin-cookies.txt -X POST https://share.bcos.cloud/api/auth/signIn \
-H "Content-Type: application/json" \
-d '{"email":"hiveiq@bcos.cloud","password":"<password>"}'
# 2. Create share
curl -s -b /tmp/pingvin-cookies.txt -X POST https://share.bcos.cloud/api/shares \
-H "Content-Type: application/json" \
-d '{"id":"my-share-id","expiration":"never","recipients":[],"description":"..."}'
# 3. Upload file (chunk params as query string, body is raw binary)
curl -s -b /tmp/pingvin-cookies.txt -X POST \
"https://share.bcos.cloud/api/shares/my-share-id/files?chunkIndex=0&totalChunks=1&name=filename.zip" \
-H "Content-Type: application/octet-stream" \
--data-binary "@/path/to/file.zip"
# 4. Complete
curl -s -b /tmp/pingvin-cookies.txt -X POST \
https://share.bcos.cloud/api/shares/my-share-id/complete
```
Share URL: `https://share.bcos.cloud/s/{shareId}`
---
## HiveIQ API — Service Account Login
```bash
LOGIN=$(curl -s -X POST "https://api.bcos.cloud/auth/api/login" \
-H "Content-Type: application/json" \
-d '{"email":"hiveiq@bcos.cloud","password":"HiveIQ-Admin-2026!","rememberMe":false}')
JWT=$(echo "$LOGIN" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('token',''))")
```
- Response field is `token` (not `accessToken`), signed HS512
- Route API calls through NGINX: `https://api.bcos.cloud/<service>/api/...`
- Login body uses `email` field (not `username`)
---
## Common Operational Mistakes
### PostgreSQL is on a SEPARATE VM
The `hiveiq-postgres` container runs on **`10.10.10.188`** (hiveiq-database VM), NOT on `173.231.195.250` (services VM).
```bash
# CORRECT — ProxyJump to database VM
ssh -i ~/.ssh/id_ed25519_hiveiq -J bcosadmin@173.231.195.250 bcosadmin@10.10.10.188 \
"docker exec hiveiq-postgres psql -U hiveiq -d hiveiq_journal -c 'SELECT ...'"
# WRONG — postgres container is not on the services VM
ssh -i ~/.ssh/id_ed25519_hiveiq bcosadmin@173.231.195.250 \
"docker exec hiveiq-postgres ..."
```
### NEVER use backslashes in fleet task payloads
All paths in `configPatch` (LOG_COLLECT_PATH, CONFIG_UPDATE, etc.) must use **forward slashes**. The agent normalizes separators on Windows.
```json
{ "path": "C:/hiveops-agent/logs/hiveops-agent.log" } // CORRECT
{ "path": "C:\\hiveops-agent\\logs\\hiveops-agent.log" } // WRONG
```
### Generating a JWT without a real user account
```python
import jwt, time
secret = '<JWT_SECRET value from .env>'
token = jwt.encode({
'sub': '1', 'email': 'admin@bcos.cloud', 'role': 'MSP_ADMIN',
'iat': int(time.time()), 'exp': int(time.time()) + 3600
}, secret.encode('utf-8'), algorithm='HS256')
print(token)
```
Do not base64-decode the secret — pass the raw string encoded as UTF-8.