Files
hiveops-guide/backend/src/main/resources/content/analytics/adoons/architect.md
T
johannes 2f94d62769 content(guide): role-tabs (Internal/Architect/Claude) for all 63 customer modules (DRAFT, Refs #1 #3)
Full role-tab rollout: every customer module now has Customer/Internal/
Architect/Claude tabs, grounded per-module in real code. Backend serves 296
docs / 96 modules. Grounding surfaced ~20 real bugs across services (filed
separately after verification).

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

4.7 KiB

module, title, tab, order, audience
module title tab order audience
analytics.adoons Adoons Insights Architect 30 internal

Internal · architecture. Written 2026-07-01 from hiveops-analytics source. Verify against code before relying on specifics.

Shape of the feature

Adoons Insights is the simplest slice of hiveops-analytics: a single-table CRUD store (ai_insights) exposed over REST, rendered as a card list. Unlike the dashboard/snapshot side of analytics, the insight path is not event-driven and does not use the executor→Kafka→record-store pattern. It's a straight Controller → Service → JpaRepository → Postgres flow.

AdoonsTab.svelte ──GET /insights/active──▶ InsightController ──▶ AiInsightService ──▶ AiInsightRepository ──▶ ai_insights (hiveiq_analytics)
publisher (admin JWT) ──POST /insights──▶ InsightController (@PreAuthorize MSP_ADMIN/BCOS_ADMIN) ──▶ save()

Services involved

  • hiveops-analytics — owns everything for this feature: controller, service, entity, table. Port 8089 (prod host 8012). Cross-link [platform.service-ownership].
  • Publisher of insightsexternal to this repo. Analytics has no insight generator, no Kafka consumer that creates insights, and no scheduled producer for them. Insight rows arrive only via authenticated POST. The intended author is Adoons (hiveops-ai), but that producer is not present in hiveops-analytics (unverified where it lives / whether it's live).

Data flow

There is no Kafka in the insight read/write path. Cross-link [platform.kafka] for the surrounding analytics topics (analytics.snapshot-ready produced by SnapshotEventProducer; hiveops.incidents.* and journal.file-parsed consumed for snapshots) — none of these touch ai_insights.

The only coupling to the rest of analytics is a nullable FK ai_insights.snapshot_id → analytics_snapshots.id. On publish:

  • If snapshotId is supplied, that snapshot is linked.
  • Else AiInsightService.publish() links the latest snapshot (findTopByOrderByCreatedAtDesc()), or null if none exist.

So an insight can reference the fleet metrics snapshot it was derived from, but the reference is optional and never enforced.

DB tables

Table R/W here Columns of interest
ai_insights read + write id, category, severity, title, body, snapshot_id (FK), published_at, expires_at, acknowledged, acknowledged_at, acknowledged_by_user_id
analytics_snapshots read-only (FK lookup on publish) id, created_at (used by findTop...)

DB hiveiq_analytics (PostgreSQL prod / H2 dev). Cross-link [platform.data-architecture]. Flyway manages schema; ai_insights is created in the analytics migration set (V1 init + later columns).

Enums (JPA EnumType.STRING):

  • Category = ANOMALY | TREND | RECOMMENDATION | SUMMARY
  • Severity = INFO | WARNING | CRITICAL (entity default INFO)

Key API endpoints (InsightController, base /api/analytics/insights)

Method Path Behaviour Auth
GET /api/analytics/insights Paged list, findAllByOrderByPublishedAtDescPage<AiInsightResponse> authenticated
GET /api/analytics/insights/active findActive(now): unack'd + unexpired, newest first authenticated
POST /api/analytics/insights publish(req), returns 201 hasAnyRole('MSP_ADMIN','BCOS_ADMIN')
PATCH /api/analytics/insights/{id}/acknowledge acknowledge(id, principal.userId()); 404 if id unknown; returns 204 authenticated
DELETE /api/analytics/insights/active acknowledgeAll(now); returns 204 authenticated

Lifecycle / retention

  • published_at set on @PrePersist if unset.
  • Active = acknowledged = false AND (expires_at IS NULL OR expires_at > now).
  • acknowledge is an atomic JPQL UPDATE; acknowledgeAll clears every unacknowledged row.
  • Nightly purge: AiInsightService.purgeOldAcknowledged()@Scheduled(cron = "0 0 3 * * *"), deletes rows where acknowledged = true AND acknowledged_at < now-30d.

Security model

  • SecurityConfig: stateless, CSRF disabled; permitAll only for /actuator/health + /api/public/**; anyRequest().authenticated().
  • JwtAuthenticationFilter reads the token from the Authorization: Bearer header only (no cookie fallback) and builds an AnalyticsPrincipal(userId, email, role, institutionKey).
  • Only publish is role-restricted; read + acknowledge are open to any authenticated principal (note: no institution scoping on insights — they are fleet-global).

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