930a4b968e
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>
4.0 KiB
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-analyticsowns 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: getActiveInsights → GET /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,expiresAtoptional.- Omit
snapshotId→ links latest snapshot (or null if none).
Kafka
- Insight path uses no Kafka. (Analytics produces
analytics.snapshot-ready; consumeshiveops.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 BYpublished_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 keysCRITICAL/HIGH/MEDIUM/LOW/INFO→WARNINGrenders default blue;HIGH/MEDIUM/LOWcan never come from this backend. - Customer
overview.mdlists CRITICAL/HIGH/MEDIUM/LOW/INFO — does NOT match backend enum. Trust the enum. - Frontend
api.tssets 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/acknowledgeAllare NOT role-gated — any authenticated user can dismiss fleet-global insights.- POST with bad enum string → 400 (
valueOfthrows). PATCH unknown id → 404.
Do NOT
- Do NOT expect insights to auto-appear — none generate inside analytics; only
POSTcreates them. - Do NOT use
Authorizationbearer header assumptions for the frontend; it doesn't set one. - Do NOT invent per-institution scoping — insights are fleet-global, no
institution_keyon the table. - Do NOT route insight writes through Kafka; it's plain REST+JPA.
- Do NOT publish
HIGH/MEDIUM/LOWseverities — not valid enum values. - Do NOT put insight reads under
/api/public/**— they require auth by design.
Cross-links: [technical.analytics], [platform.service-ownership].