feat: chat auto-archive owner digest notifications (#24643)

Depends on #24642

Adds per-owner digest notifications onto the chat auto-archive
subsystem.

Each tick's archived rows are grouped by owner, the top 25 titles per
owner are rendered into a new `Chats Auto-Archived` notification
template, and any remainder surfaces as `and N more`. Each digest is
per-tick, so users with large amounts of purgeable data may get multiple
notifications in sequence (one per user per tick).

The template body branches on `retention_days`: when retention is
disabled (`retention_days=0`), users are told archived chats are kept
indefinitely rather than falsely claiming imminent deletion.

### Changes
- migration `000XXX_chat_auto_archive_notification_template` adds new
notification template
- `dbpurge`: threads `notifications.Enqueuer` through `New`; and
enqueues notification message.
- `cli/server.go`: passes `options.NotificationsEnqueuer` into
`dbpurge.New`.
- `coderd/notifications/events.go`: new `TemplateChatAutoArchiveDigest`
UUID.
- `coderd/inboxnotifications.go`: inbox registration.
- Docs: adds a `Notifications` section to `chat-auto-archive.md`.

> 🤖
This commit is contained in:
Cian Johnston
2026-04-28 08:56:36 +01:00
committed by GitHub
parent bf66f63ac5
commit 70d6efa311
25 changed files with 1341 additions and 103 deletions
+5
View File
@@ -62,3 +62,8 @@ var (
TemplateTaskPaused = uuid.MustParse("2a74f3d3-ab09-4123-a4a5-ca238f4f65a1")
TemplateTaskResumed = uuid.MustParse("843ee9c3-a8fb-4846-afa9-977bec578649")
)
// Chat-related events.
var (
TemplateChatAutoArchiveDigest = uuid.MustParse("764031be-4863-4220-867b-6ce1a1b7a5f5")
)
@@ -1332,6 +1332,89 @@ func TestNotificationTemplates_Golden(t *testing.T) {
Data: map[string]any{},
},
},
{
// Default branch: multiple visible chats, retention enabled,
// no overflow. Body phrasing is number-neutral so this also
// covers the n>1 grammar shape without a dedicated branch in
// the template.
name: "TemplateChatAutoArchiveDigest",
id: notifications.TemplateChatAutoArchiveDigest,
payload: types.MessagePayload{
UserName: "Bobby",
UserEmail: "bobby@coder.com",
UserUsername: "bobby",
Labels: map[string]string{},
Data: map[string]any{
"auto_archive_days": "90",
"retention_days": "30",
"archived_chats": []map[string]any{
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
},
},
},
},
{
// Pins the n=1 rendering so future edits to the body cannot
// reintroduce a count-conditional that breaks the singular
// case. The list-introduction sentence and retention sentence
// both use plural-form pronouns ("them", "they") that read
// naturally for a single item.
name: "TemplateChatAutoArchiveDigestSingular",
id: notifications.TemplateChatAutoArchiveDigest,
payload: types.MessagePayload{
UserName: "Bobby",
UserEmail: "bobby@coder.com",
UserUsername: "bobby",
Labels: map[string]string{},
Data: map[string]any{
"auto_archive_days": "90",
"retention_days": "30",
"archived_chats": []map[string]any{
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
},
},
},
},
{
// Covers the retention_days="0" indefinite-retention branch.
name: "TemplateChatAutoArchiveDigestRetentionZero",
id: notifications.TemplateChatAutoArchiveDigest,
payload: types.MessagePayload{
UserName: "Bobby",
UserEmail: "bobby@coder.com",
UserUsername: "bobby",
Labels: map[string]string{},
Data: map[string]any{
"auto_archive_days": "90",
"retention_days": "0",
"archived_chats": []map[string]any{
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
},
},
},
},
{
// Covers the additional_archived_count overflow sentence.
name: "TemplateChatAutoArchiveDigestOverflow",
id: notifications.TemplateChatAutoArchiveDigest,
payload: types.MessagePayload{
UserName: "Bobby",
UserEmail: "bobby@coder.com",
UserUsername: "bobby",
Labels: map[string]string{},
Data: map[string]any{
"auto_archive_days": "90",
"retention_days": "30",
"archived_chats": []map[string]any{
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
},
"additional_archived_count": "6",
},
},
},
}
// We must have a test case for every notification_template. This is enforced below:
@@ -0,0 +1,5 @@
// Package notificationsmock contains a mocked implementation of the
// notifications.Enqueuer interface for use in tests.
package notificationsmock
//go:generate mockgen -destination ./notificationsmock.go -package notificationsmock github.com/coder/coder/v2/coderd/notifications Enqueuer
@@ -0,0 +1,82 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/coder/coder/v2/coderd/notifications (interfaces: Enqueuer)
//
// Generated by this command:
//
// mockgen -destination ./notificationsmock.go -package notificationsmock github.com/coder/coder/v2/coderd/notifications Enqueuer
//
// Package notificationsmock is a generated GoMock package.
package notificationsmock
import (
context "context"
reflect "reflect"
uuid "github.com/google/uuid"
gomock "go.uber.org/mock/gomock"
)
// MockEnqueuer is a mock of Enqueuer interface.
type MockEnqueuer struct {
ctrl *gomock.Controller
recorder *MockEnqueuerMockRecorder
isgomock struct{}
}
// MockEnqueuerMockRecorder is the mock recorder for MockEnqueuer.
type MockEnqueuerMockRecorder struct {
mock *MockEnqueuer
}
// NewMockEnqueuer creates a new mock instance.
func NewMockEnqueuer(ctrl *gomock.Controller) *MockEnqueuer {
mock := &MockEnqueuer{ctrl: ctrl}
mock.recorder = &MockEnqueuerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockEnqueuer) EXPECT() *MockEnqueuerMockRecorder {
return m.recorder
}
// Enqueue mocks base method.
func (m *MockEnqueuer) Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
m.ctrl.T.Helper()
varargs := []any{ctx, userID, templateID, labels, createdBy}
for _, a := range targets {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Enqueue", varargs...)
ret0, _ := ret[0].([]uuid.UUID)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Enqueue indicates an expected call of Enqueue.
func (mr *MockEnqueuerMockRecorder) Enqueue(ctx, userID, templateID, labels, createdBy any, targets ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]any{ctx, userID, templateID, labels, createdBy}, targets...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Enqueue", reflect.TypeOf((*MockEnqueuer)(nil).Enqueue), varargs...)
}
// EnqueueWithData mocks base method.
func (m *MockEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
m.ctrl.T.Helper()
varargs := []any{ctx, userID, templateID, labels, data, createdBy}
for _, a := range targets {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "EnqueueWithData", varargs...)
ret0, _ := ret[0].([]uuid.UUID)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EnqueueWithData indicates an expected call of EnqueueWithData.
func (mr *MockEnqueuerMockRecorder) EnqueueWithData(ctx, userID, templateID, labels, data, createdBy any, targets ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]any{ctx, userID, templateID, labels, data, createdBy}, targets...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnqueueWithData", reflect.TypeOf((*MockEnqueuer)(nil).EnqueueWithData), varargs...)
}
@@ -0,0 +1,92 @@
From: system@coder.com
To: bobby@coder.com
Subject: Chats auto-archived after 90 days of inactivity
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
Date: Fri, 11 Oct 2024 09:03:06 +0000
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
MIME-Version: 1.0
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
Hi Bobby,
The following chats were automatically archived:
"Onboarding kickoff" (last active 3 months ago)
"Quarterly planning draft" (last active 4 months ago)
You can restore any of them from the Agents page within 30 days, after whic=
h they will be permanently deleted.
View chats: http://test.com/agents?archived=3Darchived
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<!doctype html>
<html lang=3D"en">
<head>
<meta charset=3D"UTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
=3D1.0" />
<title>Chats auto-archived after 90 days of inactivity</title>
</head>
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
; background: #f8fafc;">
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
n: left; font-size: 14px; line-height: 1.5;">
<div style=3D"text-align: center;">
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
er Logo" style=3D"height: 40px;" />
</div>
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
argin: 8px 0 32px; line-height: 1.5;">
Chats auto-archived after 90 days of inactivity
</h1>
<div style=3D"line-height: 1.5;">
<p>Hi Bobby,</p>
<p>The following chats were automatically archived:</p>
<ul>
<li>&ldquo;Onboarding kickoff&rdquo; (last active 3 months ago)<br>
</li>
<li>&ldquo;Quarterly planning draft&rdquo; (last active 4 months ago)<br>
</li>
</ul>
<p>You can restore any of them from the Agents page within 30 days, after w=
hich they will be permanently deleted.</p>
</div>
<div style=3D"text-align: center; margin-top: 32px;">
=20
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
View chats
</a>
=20
</div>
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
<p>&copy;&nbsp;2024&nbsp;Coder. All rights reserved&nbsp;-&nbsp;<a =
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
ttp://test.com</a></p>
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
r: #2563eb; text-decoration: none;">Click here to manage your notification =
settings</a></p>
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
: none;">Stop receiving emails like this</a></p>
</div>
</div>
</body>
</html>
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
@@ -0,0 +1,96 @@
From: system@coder.com
To: bobby@coder.com
Subject: Chats auto-archived after 90 days of inactivity
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
Date: Fri, 11 Oct 2024 09:03:06 +0000
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
MIME-Version: 1.0
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
Hi Bobby,
The following chats were automatically archived:
"Onboarding kickoff" (last active 3 months ago)
"Quarterly planning draft" (last active 4 months ago)
...and 6 more.
You can restore any of them from the Agents page within 30 days, after whic=
h they will be permanently deleted.
View chats: http://test.com/agents?archived=3Darchived
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<!doctype html>
<html lang=3D"en">
<head>
<meta charset=3D"UTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
=3D1.0" />
<title>Chats auto-archived after 90 days of inactivity</title>
</head>
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
; background: #f8fafc;">
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
n: left; font-size: 14px; line-height: 1.5;">
<div style=3D"text-align: center;">
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
er Logo" style=3D"height: 40px;" />
</div>
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
argin: 8px 0 32px; line-height: 1.5;">
Chats auto-archived after 90 days of inactivity
</h1>
<div style=3D"line-height: 1.5;">
<p>Hi Bobby,</p>
<p>The following chats were automatically archived:</p>
<ul>
<li>&ldquo;Onboarding kickoff&rdquo; (last active 3 months ago)<br>
</li>
<li>&ldquo;Quarterly planning draft&rdquo; (last active 4 months ago)<br>
</li>
</ul>
<p>&hellip;and 6 more.</p>
<p>You can restore any of them from the Agents page within 30 days, after w=
hich they will be permanently deleted.</p>
</div>
<div style=3D"text-align: center; margin-top: 32px;">
=20
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
View chats
</a>
=20
</div>
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
<p>&copy;&nbsp;2024&nbsp;Coder. All rights reserved&nbsp;-&nbsp;<a =
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
ttp://test.com</a></p>
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
r: #2563eb; text-decoration: none;">Click here to manage your notification =
settings</a></p>
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
: none;">Stop receiving emails like this</a></p>
</div>
</div>
</body>
</html>
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
@@ -0,0 +1,92 @@
From: system@coder.com
To: bobby@coder.com
Subject: Chats auto-archived after 90 days of inactivity
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
Date: Fri, 11 Oct 2024 09:03:06 +0000
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
MIME-Version: 1.0
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
Hi Bobby,
The following chats were automatically archived:
"Onboarding kickoff" (last active 3 months ago)
"Quarterly planning draft" (last active 4 months ago)
You can restore any of them from the Agents page; archived chats are kept i=
ndefinitely.
View chats: http://test.com/agents?archived=3Darchived
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<!doctype html>
<html lang=3D"en">
<head>
<meta charset=3D"UTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
=3D1.0" />
<title>Chats auto-archived after 90 days of inactivity</title>
</head>
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
; background: #f8fafc;">
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
n: left; font-size: 14px; line-height: 1.5;">
<div style=3D"text-align: center;">
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
er Logo" style=3D"height: 40px;" />
</div>
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
argin: 8px 0 32px; line-height: 1.5;">
Chats auto-archived after 90 days of inactivity
</h1>
<div style=3D"line-height: 1.5;">
<p>Hi Bobby,</p>
<p>The following chats were automatically archived:</p>
<ul>
<li>&ldquo;Onboarding kickoff&rdquo; (last active 3 months ago)<br>
</li>
<li>&ldquo;Quarterly planning draft&rdquo; (last active 4 months ago)<br>
</li>
</ul>
<p>You can restore any of them from the Agents page; archived chats are kep=
t indefinitely.</p>
</div>
<div style=3D"text-align: center; margin-top: 32px;">
=20
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
View chats
</a>
=20
</div>
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
<p>&copy;&nbsp;2024&nbsp;Coder. All rights reserved&nbsp;-&nbsp;<a =
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
ttp://test.com</a></p>
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
r: #2563eb; text-decoration: none;">Click here to manage your notification =
settings</a></p>
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
: none;">Stop receiving emails like this</a></p>
</div>
</div>
</body>
</html>
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
@@ -0,0 +1,89 @@
From: system@coder.com
To: bobby@coder.com
Subject: Chats auto-archived after 90 days of inactivity
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
Date: Fri, 11 Oct 2024 09:03:06 +0000
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
MIME-Version: 1.0
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
Hi Bobby,
The following chats were automatically archived:
"Onboarding kickoff" (last active 3 months ago)
You can restore any of them from the Agents page within 30 days, after whic=
h they will be permanently deleted.
View chats: http://test.com/agents?archived=3Darchived
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<!doctype html>
<html lang=3D"en">
<head>
<meta charset=3D"UTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
=3D1.0" />
<title>Chats auto-archived after 90 days of inactivity</title>
</head>
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
; background: #f8fafc;">
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
n: left; font-size: 14px; line-height: 1.5;">
<div style=3D"text-align: center;">
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
er Logo" style=3D"height: 40px;" />
</div>
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
argin: 8px 0 32px; line-height: 1.5;">
Chats auto-archived after 90 days of inactivity
</h1>
<div style=3D"line-height: 1.5;">
<p>Hi Bobby,</p>
<p>The following chats were automatically archived:</p>
<ul>
<li>&ldquo;Onboarding kickoff&rdquo; (last active 3 months ago)<br>
</li>
</ul>
<p>You can restore any of them from the Agents page within 30 days, after w=
hich they will be permanently deleted.</p>
</div>
<div style=3D"text-align: center; margin-top: 32px;">
=20
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
View chats
</a>
=20
</div>
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
<p>&copy;&nbsp;2024&nbsp;Coder. All rights reserved&nbsp;-&nbsp;<a =
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
ttp://test.com</a></p>
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
r: #2563eb; text-decoration: none;">Click here to manage your notification =
settings</a></p>
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
: none;">Stop receiving emails like this</a></p>
</div>
</div>
</body>
</html>
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
@@ -0,0 +1,39 @@
{
"_version": "1.1",
"msg_id": "00000000-0000-0000-0000-000000000000",
"payload": {
"_version": "1.2",
"notification_name": "Chats Auto-Archived",
"notification_template_id": "00000000-0000-0000-0000-000000000000",
"user_id": "00000000-0000-0000-0000-000000000000",
"user_email": "bobby@coder.com",
"user_name": "Bobby",
"user_username": "bobby",
"actions": [
{
"label": "View chats",
"url": "http://test.com/agents?archived=archived"
}
],
"labels": {},
"data": {
"archived_chats": [
{
"last_activity_humanized": "3 months ago",
"title": "Onboarding kickoff"
},
{
"last_activity_humanized": "4 months ago",
"title": "Quarterly planning draft"
}
],
"auto_archive_days": "90",
"retention_days": "30"
},
"targets": null
},
"title": "Chats auto-archived after 90 days of inactivity",
"title_markdown": "Chats auto-archived after 90 days of inactivity",
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
}
@@ -0,0 +1,40 @@
{
"_version": "1.1",
"msg_id": "00000000-0000-0000-0000-000000000000",
"payload": {
"_version": "1.2",
"notification_name": "Chats Auto-Archived",
"notification_template_id": "00000000-0000-0000-0000-000000000000",
"user_id": "00000000-0000-0000-0000-000000000000",
"user_email": "bobby@coder.com",
"user_name": "Bobby",
"user_username": "bobby",
"actions": [
{
"label": "View chats",
"url": "http://test.com/agents?archived=archived"
}
],
"labels": {},
"data": {
"additional_archived_count": "6",
"archived_chats": [
{
"last_activity_humanized": "3 months ago",
"title": "Onboarding kickoff"
},
{
"last_activity_humanized": "4 months ago",
"title": "Quarterly planning draft"
}
],
"auto_archive_days": "90",
"retention_days": "30"
},
"targets": null
},
"title": "Chats auto-archived after 90 days of inactivity",
"title_markdown": "Chats auto-archived after 90 days of inactivity",
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\n...and 6 more.\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\n...and 6 more.\n\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
}
@@ -0,0 +1,39 @@
{
"_version": "1.1",
"msg_id": "00000000-0000-0000-0000-000000000000",
"payload": {
"_version": "1.2",
"notification_name": "Chats Auto-Archived",
"notification_template_id": "00000000-0000-0000-0000-000000000000",
"user_id": "00000000-0000-0000-0000-000000000000",
"user_email": "bobby@coder.com",
"user_name": "Bobby",
"user_username": "bobby",
"actions": [
{
"label": "View chats",
"url": "http://test.com/agents?archived=archived"
}
],
"labels": {},
"data": {
"archived_chats": [
{
"last_activity_humanized": "3 months ago",
"title": "Onboarding kickoff"
},
{
"last_activity_humanized": "4 months ago",
"title": "Quarterly planning draft"
}
],
"auto_archive_days": "90",
"retention_days": "0"
},
"targets": null
},
"title": "Chats auto-archived after 90 days of inactivity",
"title_markdown": "Chats auto-archived after 90 days of inactivity",
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page; archived chats are kept indefinitely.",
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page; archived chats are kept indefinitely."
}
@@ -0,0 +1,35 @@
{
"_version": "1.1",
"msg_id": "00000000-0000-0000-0000-000000000000",
"payload": {
"_version": "1.2",
"notification_name": "Chats Auto-Archived",
"notification_template_id": "00000000-0000-0000-0000-000000000000",
"user_id": "00000000-0000-0000-0000-000000000000",
"user_email": "bobby@coder.com",
"user_name": "Bobby",
"user_username": "bobby",
"actions": [
{
"label": "View chats",
"url": "http://test.com/agents?archived=archived"
}
],
"labels": {},
"data": {
"archived_chats": [
{
"last_activity_humanized": "3 months ago",
"title": "Onboarding kickoff"
}
],
"auto_archive_days": "90",
"retention_days": "30"
},
"targets": null
},
"title": "Chats auto-archived after 90 days of inactivity",
"title_markdown": "Chats auto-archived after 90 days of inactivity",
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
}