f21c783d8c
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>
4.0 KiB
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-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].