Files
hiveops-guide/backend/src/main/resources/content/analytics/adoons/claude.md
T
johannes 930a4b968e feat(guide): dev audience tier + GUIDE_SERVED_AUDIENCES env cap (prod = customer,internal)
4-tier ladder customer<internal<dev<bcos. Re-tagged Architect/Testing/Claude +
platform/technical from internal->dev; Processes stays bcos. Backend visible()
enforces a per-instance served-audiences cap at the API. bcos.dev/DLX serve all;
production sets GUIDE_SERVED_AUDIENCES=customer,internal so dev/bcos never leave
dev. Verified: capped instance returns only Customer+Internal, 404s dev/bcos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:11:00 -04:00

4.0 KiB

module, title, tab, order, audience
module title tab order audience
analytics.adoons Adoons Insights Claude 40 dev

Internal · agent reference. Grounded in hiveops-analytics @ 2026-07-01. Only confirmed facts below.

Ownership

  • Service: hiveops-analytics owns this feature end-to-end (controller, service, entity, table).
  • Port: 8089 (prod host 8012). NGINX: /api/analytics/. External base e.g. https://api.bcos.cloud/analytics/api/analytics/insights.
  • No AI generation in-repo. Insights exist only because someone POSTed them. Do not assume an in-service generator/Kafka consumer creates them.

Endpoints (InsightController, base /api/analytics/insights)

Method Path Auth
GET /api/analytics/insights authenticated (paged)
GET /api/analytics/insights/active authenticated
POST /api/analytics/insights hasAnyRole('MSP_ADMIN','BCOS_ADMIN')
PATCH /api/analytics/insights/{id}/acknowledge authenticated
DELETE /api/analytics/insights/active authenticated (ack all)

Frontend calls: getActiveInsightsGET /insights/active; acknowledgeInsight(id)PATCH /insights/{id}/acknowledge.

Auth

  • Header only: Authorization: Bearer <jwt>. No cookie fallback.
  • Open paths: /actuator/health, /api/public/**. Everything else authenticated.
  • Principal: AnalyticsPrincipal(userId, email, role, institutionKey).

Data

  • DB: hiveiq_analytics (Postgres prod on 10.10.10.188 via ProxyJump; H2 dev).
  • Table: ai_insights (cols: id, category, severity, title, body, snapshot_id, published_at, expires_at, acknowledged, acknowledged_at, acknowledged_by_user_id).
  • FK: ai_insights.snapshot_id → analytics_snapshots.id (nullable).
  • Enums: category ∈ {ANOMALY,TREND,RECOMMENDATION,SUMMARY}; severity ∈ {INFO,WARNING,CRITICAL}.

POST body (PublishInsightRequest)

{"category":"TREND","severity":"WARNING","title":"...","body":"...","snapshotId":123,"expiresAt":"2026-08-01T00:00:00Z"}
  • category,severity,title,body = @NotBlank. snapshotId,expiresAt optional.
  • Omit snapshotId → links latest snapshot (or null if none).

Kafka

  • Insight path uses no Kafka. (Analytics produces analytics.snapshot-ready; consumes hiveops.incidents.created/updated/resolved, journal.file-parsed — snapshots only, NOT insights.)

Active-list rule

  • /insights/active = acknowledged=false AND (expires_at IS NULL OR expires_at > now), ORDER BY published_at DESC.
  • Nightly purge: cron 0 0 3 * * * deletes acknowledged rows older than 30d.

Gotchas

  • Severity enum is INFO/WARNING/CRITICAL, but frontend colour map keys CRITICAL/HIGH/MEDIUM/LOW/INFOWARNING renders default blue; HIGH/MEDIUM/LOW can never come from this backend.
  • Customer overview.md lists CRITICAL/HIGH/MEDIUM/LOW/INFO — does NOT match backend enum. Trust the enum.
  • Frontend api.ts sets NO Authorization header / no axios interceptor, yet backend requires JWT on all /api/analytics/**. Token injection is not in frontend code (mechanism unverified — likely NGINX/host shell).
  • AdoonsTab.dismiss() swallows PATCH errors silently → failed acknowledge = card silently stays.
  • acknowledge / acknowledgeAll are NOT role-gated — any authenticated user can dismiss fleet-global insights.
  • POST with bad enum string → 400 (valueOf throws). PATCH unknown id → 404.

Do NOT

  • Do NOT expect insights to auto-appear — none generate inside analytics; only POST creates them.
  • Do NOT use Authorization bearer header assumptions for the frontend; it doesn't set one.
  • Do NOT invent per-institution scoping — insights are fleet-global, no institution_key on the table.
  • Do NOT route insight writes through Kafka; it's plain REST+JPA.
  • Do NOT publish HIGH/MEDIUM/LOW severities — not valid enum values.
  • Do NOT put insight reads under /api/public/** — they require auth by design.

Cross-links: [technical.analytics], [platform.service-ownership].