Files
hiveops-guide/backend/src/main/resources/content/analytics/adoons/claude.md
T
johannes f21c783d8c fix(guide): gate Architect + Claude tabs to BCOS_ADMIN only (#16)
The 162 Architect/Claude docs were tagged 'audience: dev'. The 'dev' tier
resolves to isInternal() = ROLE_MSP_ADMIN || ROLE_BCOS_ADMIN, so every
MSP_ADMIN could read full internal architecture: source paths, DB tables,
service ports, NGINX routes. Verified live on bcos.dev as msp_a@msp1.bcos.dev.

Retag them to 'audience: bcos' (isBcos, BCOS_ADMIN only). Content-only change;
the 'dev' tier mapping is deliberately left alone so the 15 Internal, 35
Overview and 66 Testing docs stay MSP-visible.

Also add platform.guide-access documenting the audience tiers and the
per-role visibility matrix, so the access model is queryable from the Guide
instead of re-derived from source each time.

Verified: MSP module count unchanged (116 across 17 apps); no module loses
all its tabs. Guide is bcos.dev only, not deployed to production.

Closes #16

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

4.0 KiB

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

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].