Skip to main content

AI Brief: hbf-reports

NestJS service that generates PDF analytics reports for organizations, delivers them by email on a cron schedule (weekly/monthly), and exposes an HTTP API for on-demand export and report schedule management.

What This Repo Does

hbf-reports pulls analytics data from hbf-core, renders it into multi-section A4 PDF documents using pdfkit (with echarts SVG charts), and either emails them to configured recipients or streams them back to the HTTP caller. Report schedules are persisted in MySQL via TypeORM. Two cron jobs fire automatically: one every Monday at midnight (weekly reports) and one on the 1st of each month at 00:05 (monthly reports).

Tech Stack

  • Language: TypeScript
  • Framework: NestJS 9
  • Key dependencies: pdfkit, pdfkit-table, svg-to-pdfkit, echarts, nodemailer, typeorm, mysql2, @helvia/hbf-core-api, @nestjs/schedule

Entry Points

  • Main: src/main.ts
  • Config: src/env.validation.ts — class-validator schema for all env vars
  • ORM config: ormconfig.ts — TypeORM datasource for migration CLI

Key Directories

DirectoryPurpose
src/reports/scheduled_reports/CRUD for report schedules + weekly/monthly send logic
src/reports/exports/On-demand export endpoint (streams PDF back to caller)
src/generate_graphs/GenerateGraphsService — orchestrates PDF page layout and chart embedding
src/resource_modules/pdf/DrawPdfService + template drawers for each section; table renderer
src/resource_modules/charts/GenerateChartsService — echarts wrappers for pie, line, bar, stacked, gauge, vertical-bar
src/resource_modules/scheduler/SchedulerService — registers weekly and monthly cron jobs
src/hbf-core/HbfCoreService — analytics data fetcher (summary, live chat, decision trees, interviews, CSAT, missed questions, user feedback)
src/clients/HTTP client and core API client
src/utils/transform/Data transformers: core API response -> chart/table format
src/migrations/TypeORM migration: initial schema
fonts/NotoSans font files (Regular, Medium, SemiBold) for PDF rendering

Scheduled Report Types

reports_schedule.type is the discriminator for every scheduled report. The service currently supports:

  • ANALYTICS_PDF: the legacy PDF analytics schedule. config must be null/omitted and sections drives the rendered PDF content.
  • SESSION_XLSX: scheduled session export. config may contain session-export filters: tags: string[], deploymentIds: string[], containsFallback, containsFeedback, containsLiveChat, containsCSATSurvey, containsUserInteraction, isRegex, matchFullWord.
  • SURVEY_CSV: scheduled survey export. config.sourceActivityName is required and config.surveyType is limited to INTERVIEW | LIVECHAT | USER_FEEDBACK; config.separator is limited to ,, ;, or \t.

reports_schedule.tenants remains a shared filter for all three types. For SURVEY_CSV, the DTO and console UX enforce single-tenant scheduling because activity lookup is tenant-scoped.

Scheduled Export Flow

ReportsService.handleScheduledReports() is the type dispatcher for cron-triggered and manual run-now exports. It creates a reports_exports row in STARTED, resolves the organization once, then switches on report.type:

  • ANALYTICS_PDF -> runAnalyticsPdfExport()
  • SESSION_XLSX -> runSessionExport()
  • SURVEY_CSV -> runSurveyExport()

The analytics path renders a PDF via GenerateGraphsService. The session and survey paths call HbfCoreService export wrappers, convert the returned file to an email attachment, and then mark the export row COMPLETED.

Export Row Semantics

reports_exports intentionally distinguishes upstream client errors from upstream server errors:

  • 4xx from hbf-core session/survey export endpoints are treated as a completed run with no attachment. The runner logs a warning, sets status = COMPLETED, sets finishedAt, and skips email delivery.
  • Empty/undefined export results are treated the same as the 4xx path: COMPLETED, no attachment, no email.
  • 5xx, network failures, and unknown exceptions are rethrown from the runner. The outer handleScheduledReports() catch only logs the failure, so the already-created reports_exports row remains at STARTED. This matches the existing analytics-PDF failure semantics.

Report Sections

Reports are composed of configurable sections (Sections enum in create-scheduled-report.dto.ts):

SectionPages drawn
SUMMARYEngagement (pie), Sessions (line), Interactions (bar), Users (line)
AUTOMATED_ANSWERSUsage (table)
LIVECHATUsage (bar), Missed Chats (pie), Response Times (stacked-line), Duration (line)
DECISION_TREESUsage (pie)
INTERVIEWSUsage (pie), Successful/Failed (pie)
USER_FEEDBACKOverall feedback (pie), Live Chat feedback (pie), Agent feedback (table)
MISSED_QUESTIONSTotal (pie), Top questions (table), Total per day (bar)
CSATOverall score (gauge), Sections score (vertical-bar), Score over time (marks-line), Responses over time (stacked-bar x2)

External Dependencies

  • Analytics: hbf-core REST API (CORE_URL, CORE_TOKEN)
  • Database: MySQL/MariaDB via TypeORM (DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_NAME)
  • Email: SMTP via nodemailer (EMAIL_HOST, EMAIL_PORT, EMAIL_SECURE, EMAIL_USERNAME, EMAIL_PASSWORD, EMAIL_FROM_ADDRESS, EMAIL_FROM_NAME)
  • Console link in emails: CONSOLE_URL
  • APM: Elastic APM (optional, ELASTIC_APM_ACTIVE)

Running Locally

npm install
cp .env.sample .env # fill all values
npm run start:dev # watch mode, APM disabled

Tests

npm test              # Jest unit tests (spec files in src/)
npm run test:e2e # e2e suite
npm run test:cov # coverage report