feat(analytics): add conversation daily metrics data foundation
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Add the migration + model for per-account daily conversation analytics
(M2 phase 1a). A future sidekiq cron job will populate these rows nightly, and
the monthly/yearly rollup + admin report will read them.
- conversation_daily_metrics: per (account_id, date) record of message/conversation
counts, resolved/unresolved, avg session duration, LLM-derived top tags AND
sale tags (product/group), deal outcome breakdown (won/lost/undecided),
peak message/deal hour, and agent/team/inbox/channel breakdowns (jsonb).
- Model: belongs_to account, date unique per account, JSONB getters safely
defaulting to []/{} so nulls never leak.
Approved by independent five-key pre-commit review deleg_5ee4b4a3
(passed=true, blocking arrays empty).
This commit is contained in:
68
app/models/conversation_daily_metric.rb
Normal file
68
app/models/conversation_daily_metric.rb
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: conversation_daily_metrics
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# account_id :bigint not null
|
||||||
|
# date :date not null
|
||||||
|
# timezone :string
|
||||||
|
# message_count :integer default(0), not null
|
||||||
|
# conversation_count :integer default(0), not null
|
||||||
|
# resolved_count :integer default(0), not null
|
||||||
|
# unresolved_count :integer default(0), not null
|
||||||
|
# avg_session_duration_seconds :float default(0.0), not null
|
||||||
|
# top_tags :jsonb default([]), not null
|
||||||
|
# sale_tags :jsonb default([]), not null
|
||||||
|
# deal_outcomes :jsonb default({}), not null
|
||||||
|
# peak_message_hour :integer
|
||||||
|
# peak_deal_hour :integer
|
||||||
|
# agent_breakdown :jsonb default([]), not null
|
||||||
|
# team_breakdown :jsonb default([]), not null
|
||||||
|
# channel_breakdown :jsonb default([]), not null
|
||||||
|
# inbox_breakdown :jsonb default([]), not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
class ConversationDailyMetric < ApplicationRecord
|
||||||
|
belongs_to :account
|
||||||
|
|
||||||
|
validates :account_id, presence: true
|
||||||
|
validates :date, presence: true
|
||||||
|
validates :date, uniqueness: { scope: :account_id }
|
||||||
|
|
||||||
|
# JSONB columns default to {} / [] — store hashes/arrays; keep values normalized.
|
||||||
|
# Safety rails: always return an Array/Hash even if nil slipped in.
|
||||||
|
def top_tags
|
||||||
|
self[:top_tags] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def sale_tags
|
||||||
|
self[:sale_tags] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def deal_outcomes
|
||||||
|
self[:deal_outcomes] || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def agent_breakdown
|
||||||
|
self[:agent_breakdown] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def team_breakdown
|
||||||
|
self[:team_breakdown] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def channel_breakdown
|
||||||
|
self[:channel_breakdown] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def inbox_breakdown
|
||||||
|
self[:inbox_breakdown] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rollup helpers used by monthly / yearly aggregation.
|
||||||
|
def self.rollup(scope)
|
||||||
|
total = scope.select('coalesce(sum(message_count),0) as msg').first.msg
|
||||||
|
total
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
class CreateConversationDailyMetrics < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
create_table :conversation_daily_metrics do |t|
|
||||||
|
t.bigint :account_id, null: false
|
||||||
|
t.date :date, null: false
|
||||||
|
t.string :timezone
|
||||||
|
t.integer :message_count, default: 0, null: false
|
||||||
|
t.integer :conversation_count, default: 0, null: false
|
||||||
|
t.integer :resolved_count, default: 0, null: false
|
||||||
|
t.integer :unresolved_count, default: 0, null: false
|
||||||
|
t.float :avg_session_duration_seconds, default: 0.0, null: false
|
||||||
|
t.jsonb :top_tags, default: [], null: false
|
||||||
|
t.jsonb :sale_tags, default: [], null: false
|
||||||
|
t.jsonb :deal_outcomes, default: {}, null: false
|
||||||
|
t.integer :peak_message_hour
|
||||||
|
t.integer :peak_deal_hour
|
||||||
|
t.jsonb :agent_breakdown, default: [], null: false
|
||||||
|
t.jsonb :team_breakdown, default: [], null: false
|
||||||
|
t.jsonb :channel_breakdown, default: [], null: false
|
||||||
|
t.jsonb :inbox_breakdown, default: [], null: false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :conversation_daily_metrics, [:account_id, :date], unique: true,
|
||||||
|
name: 'index_cdm_on_account_id_date'
|
||||||
|
add_index :conversation_daily_metrics, :account_id
|
||||||
|
add_index :conversation_daily_metrics, :date
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user