2f94d62769
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>
3.9 KiB
3.9 KiB
module, title, tab, order, audience
| module | title | tab | order | audience |
|---|---|---|---|---|
| analytics.transactions | Transactions | Claude | 40 | internal |
Act-without-guessing reference. Transactions tab = analytics UI tab
id: 'journal', label: 'Transactions'→JournalCoverageTab.svelte→GET /api/analytics/journal-coverage. Data source of truth is hiveops-journal, not analytics.
Ownership
- hiveops-journal OWNS the data (
journal_transactions,journal_gaps, DBhiveiq_journal). - hiveops-analytics (port 8089) is a read-only aggregator/proxy; forwards caller JWT to journal.
- Frontend:
hiveops-analytics/frontend,analytics.bcos.cloud(port 5174).
Endpoints (METHOD path → service)
| Method | Path | Service | Auth |
|---|---|---|---|
| GET | /api/analytics/journal-coverage |
analytics | authenticated JWT, no role gate |
| GET | /api/journal/transactions/summary?dateFrom=&dateTo= |
journal | JWT (no method-level @PreAuthorize; filter chain enforces) |
| GET | /api/journal/gaps?status=OPEN |
journal | @PreAuthorize("isAuthenticated()") |
| GET | /api/journal/transactions/top-atms?dateFrom=&dateTo=&limit=10 |
journal | @PreAuthorize("isAuthenticated()"), size cap 50 |
| PUT | /api/journal/gaps/{id}/request-fetch |
journal | isAuthenticated() (marks gap FETCH_REQUESTED) |
- Analytics frontend
apiBasedefault (dev):http://localhost:8089/api/analytics; prod fromwindow.__APP_CONFIG__.apiUrl. NGINX path/api/analytics/. - Analytics
journalWebClientbase =JOURNAL_SERVICE_URL(defaulthttp://hiveops-journal:8087).
Tables (DB hiveiq_journal)
| Table | Use |
|---|---|
journal_transactions |
total / APPROVED / DECLINED counts, top-ATMs |
journal_gaps |
open gaps (status OPEN) |
- No table is WRITTEN to serve this tab.
analytics_snapshots/ai_insights(DBhiveiq_analytics) are NOT used by this tab.
Kafka
- None in this request path.
journal-coverageis a synchronous WebClient pull. - (Context only, other tabs) analytics consumes
journal.file-parsed,hiveops.incidents.{created,updated,resolved}; producesanalytics.snapshot-ready. Journal producesjournal.file-parsed, consumesjournal.parse-requests.{INSTITUTION}.
Response shape (JournalCoverageResponse)
dailyVolume: [{date, total, successful, failed}]— today only, single element.parseSuccessRateToday = successful*100/total(0 if total 0).openGapsTotal,atmsWithGaps: [{atmId, gapCount}](≤20, UI shows 10).topAtmsByVolume: [{atmId, transactionCount}](≤10).
Field semantics (critical)
- journal
successful=COUNT(host_result='APPROVED');failed=COUNT(host_result='DECLINED');total= all rows. - Therefore "Parse Success Rate" and the "Successful/Failed" bars = transaction approval stats, NOT journal-parse health.
transactions/summaryis@Cacheable("txSummary")keyinstitutions:dateFrom:dateTo→ today's numbers can be stale.- All scoped by
InstitutionContext.resolveScope()in journal — results are per caller's institution.
Gotchas
- Downstream failures are caught and return empty → tab shows 0 / "No data" with no user error. Grep analytics logs:
JournalCoverage: failed to fetch. - Everything except open-gaps is
LocalDate.now()(today) — early-day emptiness is expected. - Gap rows only created by journal's daily 06:00 UTC gap-detection job.
Do NOT
- Do NOT claim analytics stores transaction/gap data — it does not; query journal.
- Do NOT treat "Parse Success Rate" as an ingest/parse metric — it is approval rate.
- Do NOT expect multi-day history on this tab —
dailyVolumeis today-only. - Do NOT assume
MSP_ADMIN/BCOS_ADMINis required —journal-coverageis any-authenticated. - Do NOT look for Kafka in the read path — it is a synchronous pull.
- Do NOT add write endpoints or resolve gaps from analytics — gap fetch is
PUT /api/journal/gaps/{id}/request-fetchon journal.