Reporting Data Model

Introduction

The N2ACD reporting database complements the real-time N2ACD SMS database by providing the following information:

All database tables referenced can be found in the n2reporting database of N2ACD. Depending on the deployment model, this database will be co-located on the reporting application node, or hosted on separate database servers.

The n2reporting database is a PostgreSQL database. All N2ACD reporting tables are created in the n2acd database schema. If other N-Squared products are installed and use the same reporting node, they will have their own schema.

EDR Database Tables

N2ACD_EDR

The n2acd.n2acd_edr table stores the EDRs in a JSON format closely aligned with the raw text EDR format. EDRs generated by real-time platform (whether from ACD, or the SRF) and determined to be for the ACD service will be present in this table.

This table is partitioned.

Column Name Type Purpose
event_timestamp timestamp The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR.
session_id text The session ID as provided by n2svcd. This will be a long text string and may not be unique.
first_instance_guid text The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for.
type text The type of EDR, indicating whether this is a INAP, SIP or ACD EDR, or any other sort of EDR.
edr JSON A postgres JSON field that gives the EDR content as key/value pairs.
edr_content_checksum bigint The CRC32 checksum of the original EDR string. This will be provided by NiFi to PostgreSQL as part of the store process.
insert_collisions smallint A counter that tracks the number of times this EDR was inserted into the database. The data processing pipeline is designed to support replaying data processing even in the case the data already exists. This column is a simple tracking mechanism for tracking whether an EDR has been processed multiple times.
creation_date timestamp When this record was first created in the database. This is an auditing field and determines the time delay between the EDR event timestamp, and the date/time it was inserted into the database.

A session_id is a long string that determines the n2svcd processes involved in the session that generates the EDR. Taking an EDR such as:

2022-05-15 21:30:47.948<6cb1eb0b47dc~SIGTRAN~1652650168~7f16d4a4,6cb1eb0b47dc~ACD SCP~1652650168~0b960fef,6cb1eb0b47dc~ACD Logic~1652650168~0b8a08fb>ACD|CUST_ID=7|CUST_NAME=Test Set 2 0800100100 Customer|FLOW_ID=8|FLOW_NAME=Test Set 2 0800100100 Flow|FLOW_VERSION=1|NODES=AT-1

The EDR is broken down as follows:

SUMMARISED_EDR

The n2acd.summarised_edr table aggregates information from multiple EDRs to give a single view of a single voice call made to a service number.

This table is partitioned.

Column Name Type Purpose
call_id text This is the instance ID of the N2SVCD “SCP” or “SIP” app that handled the call. It matches the last part of the session ID from the InitialDP (or INVITE) EDR related to this call.
called text The service number dialled by the caller, normalised by the real time call control layer of N2ACD.
calling text The calling party, normalised by the real time call control player of N2ACD.
calling_presentation_restricted boolean If true, the calling party number should be considered presentation restricted (i.e. not shared).
completion_state text A simple flag - one of abandon, answer, decline, hangup, problem, release or unconditional that indicates how the call ended. See the related documentation for more information on each state.
creation_date timestamp When this record was first created in the database. This is an auditing field and determines how long after the first EDR from the call was processed.
cust_id integer The N2ACD customer ID, for the record in the N2ACD database of the customer that owned the service number at the time the call was made.
decline_code integer Defines how the call ended toward the A party if the call did not end with an A - B party connection. This is also used for the release call ‘cause’ field from INAP. It is not nessarily the same as the last decline code returned when attempting a B party connection.
executed_node_list JSON The list of nodes that were processed as part of the call this EDR represents. This is a JSON array, with each element of the array being a map of the form {"id": "1", "exit": 2, "type": "KEY" } where KEY is the node type key, id is the ID of the node in the operations map as shown in the screens, and exit is the one-based index index taken by the node (the first exit of the node is exit 1).
first_event_timestamp timestamp The time that the first event could be found related to this ACD voice call. This will be the event_timestamp of the earliest EDR seen with the given first_instance_guid.
first_instance_guid text The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the n2acd_edr table.
flow_id integer The ID of the flow used to execute this call.
flow_name text The name of the flow used to execute this call - as given by the EDR.
last_event_timestamp timestamp The date/time of the last EDR that was matched to this record. This will always be the latest date/time seen - not the date/time of the latest EDR processed.
last_updated timestamp The timestamp for the last time this summarised EDR record was updated.
service text The service the EDR is for. For ACD calls, this is ACD. If EDR processing captures an EDR stream for a call scenario that is not handled by ACD (e.g. a freephone call that was received for a ported number, and hence triggered a port-out response, not an ACD processing response) this field will not be set, or set to a value other than ACD (e.g. ACD-NP).
service_node text The hostname, as given by the ACD EDR that handled the call.
talk_dsm integer The call talk time, as calculated by the service. This is the time the caller spent on the line talking (after the all is answered).

SUMMARISED_EDR_HOLDING

The n2acd.summarised_edr_holding table is structured exactly the same as the SUMMARISED_EDR table. It is used for the storage of EDRs that are not yet considered complete. EDRs are transferred from SUMMARISED_EDR_HOLDING to SUMMARISED_EDR automatically once they are considered completed.

To query both tables and retrieve a single view of all summarised EDRs, use the view n2acd.gather_summarised_edrs.

SUMMARISED_EDR_B_PARTY

The n2acd.summarised_edr_b_party table lists key information for every B-party interaction event captured by an EDR - such as attempt terminate requests, and answer requests.

This table is partitioned.

Column Name Type Purpose
event_timestamp timestamp The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR.
first_instance_guid text The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the summarised_edr and n2acd_edr tables.
dra text The destination address (phone number/SIP URI) that was attempted during an attempt termination request. If this is not null, then decline_code will be null
decline_code text The result of the last attempt terminate. This will be a SCP BCSM event such as oCalledPartyBusy_leg2, oNoAnswer_leg2, oAbandon_leg1, or routeSelectFailure_leg2. SIP events are similar. If this is not null, then dra will be null.

To connect records in this table, it is important to order by the event_timestamp and link the record with the DRA with the record with the decline_code (if there is one). For example, the following query will list each EDR from the summarised_edr table and each attempted connection to a b-party:

with bparty_info AS (
	SELECT DISTINCT
		edrs.first_instance_guid
		, rank() OVER (PARTITION BY edrs.first_instance_guid ORDER BY event_timestamp DESC) AS rank
		, dra
		, b.decline_code
		, completion_state
	FROM
		n2acd.summarised_edr edrs
		JOIN n2acd.summarised_edr_b_party b USING (first_instance_guid)
),
bparties AS (
	SELECT
		first_instance_guid
		, rank() OVER (PARTITION BY first_instance_guid ORDER BY rank ASC) AS rank
		, rank() OVER (PARTITION BY first_instance_guid ORDER BY rank DESC) AS counter
		, rank AS old_rank
		, dra
		, completion_state
	FROM
		bparty_info
	WHERE
		dra IS NOT NULL
),
last_bparty AS (
	SELECT
		bparties.first_instance_guid
		, bparties.counter
		, bparties.dra
		-- The result of the call. We use the DRA decline code in preference.
		--  "No_Answer" if the network indicated that the no answer timer fired.
		--  "Busy" if the network reported a busy event.
		--  "Abandon" if the caller hung up before the call was answered.
		--  "Answer" if the network reported that the call was answered.
		--  "Disconnect" if the last interaction in the call was an announcement
		--  "Other" otherwise.
		, (CASE
			when decline_code = 'oCalledPartyBusy_leg2' THEN 'Busy'
			when decline_code = 'oNoAnswer_leg2' THEN 'No_Answer'
			when decline_code = 'routeSelectFailure_leg2' THEN 'Other'
			when bparties.completion_state = 'abandon' THEN 'Abandon'
			when bparties.completion_state = 'answer' THEN 'Answer'
			when bparties.completion_state = 'release' THEN 'Disconnect'
			else 'Other'
		END) as completion_state
	FROM
		bparties
		LEFT JOIN bparty_info bparty_resp ON bparties.first_instance_guid = bparty_resp.first_instance_guid AND bparties.old_rank = bparty_resp.rank + 1 AND bparty_resp.DRA IS NULL
	WHERE
		bparties.rank = 1
)
SELECT * FROM last_bparty;

SUMMARISED_EDR_SRP_INTERACTIONS

The n2acd.summarised_edr_srp_interactions table lists key information for every SRF interaction event captured by an EDR.

This table is partitioned.

Column Name Type Purpose
event_timestamp timestamp The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR.
first_instance_guid text The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the summarised_edr and n2acd_edr tables.
digits text If the SRF interaction requested user input, this field captures the digits input by the user. In the case where the user input was for an ACD PIN node, this field will store ? not the actual input digits.
error text If the source EDR captures an error during the user interaction (e.g. the user didn’t input a value correctly) this field captures that error.
message_ids integer array A list of message IDs requested for to be played by ACD. This is the INAP message_ids list, not a list of files played by the SRF.
event text One of response, prompt, or play. If response then digits or error will be non-null. The prompt and play distinguish between different interaction requests.

To connect records in this table, it is important to order by the event_timestamp and link the record with the prompt or play with the subsequent response record. For example, the following query will list each EDR from the summarised_edr table with a summarised SRP interaction string:

WITH srp_details AS (
	SELECT
		i.first_instance_guid,
		event_timestamp,
		i.event,
		rank() over (partition by i.first_instance_guid order by event_timestamp) AS r,
		CASE
			WHEN event = 'prompt' THEN array_to_string(message_ids, ',') || '^'
			WHEN event = 'play' THEN array_to_string(message_ids, ',')
			ELSE (
				CASE
					WHEN digits IS NOT NULL AND digits != '' THEN replace(digits, '?', '*')
					WHEN error ilike 'abandoned' THEN 'Z'
					WHEN error is not null THEN 'X'
					ELSE ''
				END
			)
		END AS prompt
	FROM
		n2acd.summarised_edr_srp_interactions i
), srp_details_linked AS (
	SELECT
		req.first_instance_guid,
		req.event_timestamp,
		CASE
			WHEN resp.prompt IS NULL THEN req.prompt
			-- this here ensures we don't get ^ - i.e. we indicate no entry of digits, with ^X, which
			-- respects the requirements of the report
			WHEN RIGHT(req.prompt, 1) = '^' AND resp.prompt = '' THEN req.prompt || 'X'
			ELSE req.prompt || resp.prompt
		END AS prompt
	FROM
		(SELECT * FROM srp_details WHERE event != 'response') req
		LEFT JOIN (SELECT * FROM srp_details WHERE event = 'response') resp ON req.first_instance_guid = resp.first_instance_guid AND resp.r = req.r + 1
)
SELECT
	l.first_instance_guid,
	STRING_AGG(prompt, ',' ORDER BY event_timestamp) AS interaction
FROM
	srp_details_linked l
GROUP BY
	l.first_instance_guid;

N2ACD Service Data

If the report extraction process is installed and enabled, the reporting database will store copies of service data as point-in-time extracts from the SMS service database.

Each extract from the N2ACD SMS service database is tagged with a consistent nifi_insert_timestamp field. For each extract run, the value of this field is the same across all database tables.

CUSTOMER

The customer table stores data on each N2ACD Customer and is derived from the n2acd.customer database table. The view latest_customer provides only the data from the latest extract.

Column Name Type Purpose
nifi_insert_timestamp timestamp The date/time the service data was extracted.
customer_id integer The unique ID of the customer. Matches the EDR field CUST_ID
parent_customer_id integer An optional reference to the parent customer of this customer, if this customer is not a top level customer.
customer_name text The unique name of the customer.
customer_reference text The non-unique customer reference. This may be null.
are_services_disabled boolean If all service numbers for the customer are disabled, this will be true. Normally this is false.
are_service_schedules_overridden boolean If this field is true, and the field service.schedule_override_flow_id is set for a service number for this customer, then that override flow will be active for that service.
are_alternative_termination_numbers_active boolean If the customer has an alternative number set, and this boolean flag is true, then those alternative numbers are active.
profile JSON The customer’s profile.

SERVICE

The service table stores data on each N2ACD service number and is derived from the n2acd.service database table. The latest_service view is all the data extracted in the latest extract by NiFi.

Column Name Type Purpose
nifi_insert_timestamp timestamp The date/time the service data was extracted.
service_id integer The unique ID of the service.
customer_id integer The unique ID of the customer the service currently belongs to.
digits text The freephone service number.
is_disabled boolean If true, this service number is disabled and calls to it will be rejected by the platform.
is_schedule_overridden boolean If this field is true, and the field schedule_override_flow_id is set for this service number , then that override flow will be active for that service.
bar_payphone_callers boolean If this field is true, any calls made from payphones to this service number will be rejected.
bar_cellphone_callers boolean If this field is true, any calls made from cellphones to this service number will be rejected.
follow_me_number text If this service number has a follow me number, this will not be null.
toll_free_beeps_required boolean If this service number has the Toll Free Beeps flag set, this will be true.
pin text The PIN for the service number (for self service via management systems). This may be null.
ignore_barring_list boolean If true, the barring list (whether acting as a whitelist or blacklist) for the service number will actually be ignored.
allow_barring_list_digits boolean If true, the barring list will act as a whitelist, not a blacklist.
profile JSON The service’s profile.

FLOW

The flow table stores data on each N2ACD flow and is derived from the n2acd.flow database table. A flow itself does not hold much information - the actual flow design is stored on the flow_version table. The flow table is effectively only a name.

The latest_flow view is all the flows from the last NiFi extract.

Column Name Type Purpose
nifi_insert_timestamp timestamp The date/time the service data was extracted.
flow_id integer The unique ID of the flow.
flow_name text The unique name for the flow (within the customer’s flow list).
customer_id integer The unique ID of the customer the flow currently belongs to.
external_id integer For external management systems, this external_id field defines a unique ID (within the customer’s flow list) by which this flow can be referred.

FLOW_VERSION

The flow_version table stores data on each N2ACD flow version and is derived from the n2acd.flow_version database table. The latest_flow_version view is all the flow data from the last NiFi extract.

Column Name Type Purpose
nifi_insert_timestamp timestamp The date/time the service data was extracted.
flow_version_id integer The unique ID of the flow version.
flow_json JSON The JSON definition of the operations of the flow.
version integer The version number (starting from 1 and incrementing on each saved flow version) of the flow version.
flow_id integer The ID of the flow that this JSON is for.

FLOW_VERSION_SCHEDULE

The flow_version_schedule table stores data on each schedule - i.e. when a flow version will be executed for a service number. The latest_flow_version_schedule view is all the flow scheduling data from the last NiFi extract.

Column Name Type Purpose
nifi_insert_timestamp timestamp The date/time the service data was extracted.
flow_version_schedule_id integer The unique ID of the flow version schedule record.
service_id integer The service number that this schedule record is for.
flow_version_id integer The flow version that is scheduled.
active_from integer The date/time that the linked flow version will start being active for the linked service number.