Skip to content
This repository has been archived by the owner on Aug 14, 2024. It is now read-only.

feat(feedback): add page for feedback architecture #1313

Merged
merged 31 commits into from
Jun 26, 2024
Merged
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4c81d4c
feat(feedback): add a page for feedback architecture
aliu39 Jun 18, 2024
c3855f4
Camelcase for model name
aliu39 Jun 18, 2024
ae5ad5a
Add diagrams
aliu39 Jun 18, 2024
30a4abe
Add some whitespace
aliu39 Jun 18, 2024
ed571d7
Header capitalizion
aliu39 Jun 18, 2024
079d727
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
9b86a46
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
4b3e78b
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
b23ba08
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
fbd89ee
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
6c671c5
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
09c262f
Update src/docs/feedback-architecture.mdx
aliu39 Jun 24, 2024
977c626
Add to bottom of sidebar as 'User Feedback Architecture'
aliu39 Jun 24, 2024
79dcaec
Make diagrams light mode
aliu39 Jun 24, 2024
2f5f833
Tweak ##Creation sources wording
aliu39 Jun 24, 2024
d4c614d
Add links to envelope formats in Creation sources + some more tweaks
aliu39 Jun 24, 2024
e7eaa9e
Code-ify user_report
aliu39 Jun 24, 2024
ff89364
Reword mistakenly
aliu39 Jun 24, 2024
6738d24
Tweak diagrams: envelopes->envelope and rm widget/api from first graph
aliu39 Jun 24, 2024
d87a8fc
Reword user report endpoint
aliu39 Jun 24, 2024
222c37a
Merge branch 'master' into aliu/feedback-arch
aliu39 Jun 24, 2024
079470e
Add crash reports section
aliu39 Jun 24, 2024
8ea0346
Split up diagrams and finalize
aliu39 Jun 25, 2024
2be8544
Tweak feedback envelope
aliu39 Jun 25, 2024
9090d24
Update report diagram
aliu39 Jun 25, 2024
18f4d70
Merge branch 'aliu/feedback-arch' of https://github.com/getsentry/dev…
aliu39 Jun 25, 2024
35b6d6f
Update title
aliu39 Jun 25, 2024
e81a031
Add ff's
aliu39 Jun 25, 2024
638ddda
Use bullet points
aliu39 Jun 25, 2024
2801d44
Tweak ff descrip
aliu39 Jun 25, 2024
ec245b6
Final tweaks
aliu39 Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions src/docs/feedback-architecture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: User Feedback - Backend Architecture
---

**The goal of this doc is to give engineers an in-depth, systems-level understanding of User Feedback.**
It will
aliu39 marked this conversation as resolved.
Show resolved Hide resolved
1. describe the relevant ingestion pipelines, data models, and functions.
2. explain the difference between “feedback”, “user reports”, and “crash reports”, and why we built and need to support each.

## Creation sources
When broken down, there are **5** ways to create feedback 😵‍💫 in our system.
(But if it helps, 4 are very similar!) A good reference is the
`FeedbackCreationSource(Enum)` in [create_feedback.py](https://github.com/getsentry/sentry/blob/2b642e149c79b251e1c2f4339fc73d656347d74e/src/sentry/feedback/usecases/create_feedback.py#L33-L33).
The 4 ways _clients_ can create feedback are:

`NEW_FEEDBACK_ENVELOPE`: The new format created by the Replay team when adding
the [User Feedback Widget](https://docs.sentry.io/product/user-feedback/#user-feedback-widget)
to the JavaScript SDK. It allows adding more information, for example tags,
release, url, etc.

`USER_REPORT_ENVELOPE`: The older format with name/email/comments, that requires
`event_id` to link a Sentry error event.

`USER_REPORT_DJANGO_ENDPOINT`: [The Web API](https://docs.sentry.io/api/projects/submit-user-feedback/)

`CRASH_REPORT_EMBED_FORM`: The [crash report modal](https://docs.sentry.io/product/user-feedback/#crash-report-modal)

## How it's stored
aliu39 marked this conversation as resolved.
Show resolved Hide resolved
On the backend, each feedback submission in Sentry's UI is **an un-grouped issue occurrence**,
saved via the [issues platform](https://develop.sentry.dev/issue-platform/).
The entrypoint is [**`create_feedback_issue()`**](https://github.com/getsentry/sentry/blob/2b642e149c79b251e1c2f4339fc73d656347d74e/src/sentry/feedback/usecases/create_feedback.py#L184-L184),
which
1. filters feedback with empty or spam messages. Note **anonymous feedbacks are not filtered** (missing name and/or email).
2. sends to issues pipeline in a standardized format. To make sure it is never grouped, we use a random UUID for the fingerprint.

---

## Feedback events

The new and preferred way to send feedback from the SDK is as an [event item](https://develop.sentry.dev/sdk/envelopes/#full-examples),
in a MessagePack'ed envelope. The item type is the same as errors, but event
type = `"feedback"`. While user reports have an associated event,
**new feedback _is_ an event**. This offers 2 improvements:

1. Users can submit generic feedback without an error occurring. The point of this feature is to catch things Sentry can’t!
aliu39 marked this conversation as resolved.
Show resolved Hide resolved
2. Rather than waiting for the associated error to be ingested asynchronously, we immediately get access to context like the environment, platform, replay, user, tags...

The user's submission is wrapped in a context object:

```Python/Javascript
event[”contexts”][”feedback”] = {
"name": <user-provided>,
"contact_email": <user-provided>,
"message": <user-provided>,
"url": <referring web page>,
"source": <developer-provided, ex: "widget">
}

// all fields are technically optional, but recommended
// the widget can be configured to require a non-empty email and/or name
```

- This doc refers to the payload format (`event` in the pseudo-code above) as a “**feedback event”**.
- The feedback [widget](https://docs.sentry.io/platforms/javascript/user-feedback/#user-feedback-widget), which is installed by default, sends these envelopes.
- API: for SDK v8.0.0+, we use the `sendFeedback` function.
<br/><br/>

### Architecture diagram

![](https://mermaid.ink/svg/pako:eNp1Uk1vwjAM_StRTiBRca-mSWiwicOmaWWHqUFVSA1EtEmWDyYE_Pc5adFAYqe6zvPze7aPVOgaaE43lpstWUyZYt6FVfdbgPL2EFPMS-cCuApUbbRUvmR03KUYXd5FkIcseyQnRl9mC0ZPJEiseQaoV1zsyOe8r0M4fq67cmPKLx0smRjTSMG91Kpv8SPrDfgunrzPb-qxjPQdQe2h0SZqO5EPaHjykIIEWVdCKxdasINSqg04n617YRns0bRbDmPFH-7C_B0APRLuiIAG7IF47naxi7DAPVQXmioNI3LcfUh0-koFo70OLUSwFpRIg00q9K0KhQtzXlsoB2-XcLi8A0S5s2im8CihjSKdCiteDhgtYjB-wunutjo4YLRj-G-FaNvKbpyJg44odmm5rPF0jkwRwqjfQotEOYY1tzgUps6I48Hr4qAEzb0NMKLB1DiPqeS47Jbma944zEIt0cdrd4vpJM-_bUbyRw)
[diagram source](https://mermaid.live/edit#pako:eNp1Uk1vwjAM_StRTiBRca-mSWiwicOmaWWHqUFVSA1EtEmWDyYE_Pc5adFAYqe6zvPze7aPVOgaaE43lpstWUyZYt6FVfdbgPL2EFPMS-cCuApUbbRUvmR03KUYXd5FkIcseyQnRl9mC0ZPJEiseQaoV1zsyOe8r0M4fq67cmPKLx0smRjTSMG91Kpv8SPrDfgunrzPb-qxjPQdQe2h0SZqO5EPaHjykIIEWVdCKxdasINSqg04n617YRns0bRbDmPFH-7C_B0APRLuiIAG7IF47naxi7DAPVQXmioNI3LcfUh0-koFo70OLUSwFpRIg00q9K0KhQtzXlsoB2-XcLi8A0S5s2im8CihjSKdCiteDhgtYjB-wunutjo4YLRj-G-FaNvKbpyJg44odmm5rPF0jkwRwqjfQotEOYY1tzgUps6I48Hr4qAEzb0NMKLB1DiPqeS47Jbma944zEIt0cdrd4vpJM-_bUbyRw)

In Relay v24.5.1, we migrated feedback to its own kafka topic + consumer,
`ingest-feedback-events`. This decouples risk and ownership from errors
(`ingest-events`).
<br/>

### Attachments

We only use attachments for the widget’s screenshot feature, which allows users
to submit **at most 1 screenshot per feedback**. Attachments are another [item type](https://develop.sentry.dev/sdk/envelopes/#attachment)
in an envelope.
- SDK v8.0.0+, Relay v24.5.1+: Sends the feedback and attachment items in the same envelope.
- SDK < v8, all Relay versions: Send a separate envelope for each item.
aliu39 marked this conversation as resolved.
Show resolved Hide resolved

**The feedback pipeline does not process attachments**. Relay routes them to
a separate topic and storage, and the UI makes a separate request for them.

---

## User reports

The deprecated way of sending feedback is as a **user report**. This is a simple typed dict:

```Python/Javascript
user_report = {
"event_id": <required UUID str>,
"email": <optional str>,
"name": <optional str>,
"comments": <optional str>,
}
```
<br/>

### Architecture diagram

![](https://mermaid.ink/svg/pako:eNqNVO9r2zAQ_VcOQSGFhnwPYzDaZvRDt9J0H4YdjCJfYq22pOlHoLT933eSbHdL3LJPVi7vnt69u9MzE7pGtmR7y00DD1elKr0L2_xzjcrbpxgqvXQuoKtQ1UZL5YuSLXKoZJtJBHyazz_DS8m-Xj-U7AWCpJwVYr3l4hF-3Ix5Fo22_h_m4NDOdz12BArLXVP18E7XvCXsZQzCfQrCbQz2eOKjz9_l7IISXmrlitVwgjnYoEAqsLhDa9H2dzl-wCrKyNfFIIBrZFd5XY3KelnIPY7BKvkwyQK9IzcrwAN5C8Zqgc5hHQ2aZj-OJo53rxyLPjsDVAdstUEw0mArVQJwY4qfOlj4YkwrBY8ubAZdQ4aLcu6x5an36ZAgnIQYKWaFVHt0fs6956LpqBK3OU_sGZDApw4Osvr54KqG1FLICNfrG9TcfV-nwTmaj3fIpzJPB-ZDZXmAwbTc77TtYnTS6ESiK0HzEzq0M5rC3hAtRCBWJdJaJEvecClN0bo5ry0Ws2_D8XwzAaQyruOMrGk_eJfmQ4UtL2br-FlcUvMeG01V5Oz057hyvwNamdt4tJVjsbH-3tpkiFsEU1OtqQtTc2u083uLrpjd9acPbs7znapL0k_bZUz1S2_JOgpq6xL9sA_guYtrf8w6SiTKQc4bV-7txBL9j8JMwS4Y-d9xWdOT-FwqgJL5BjuCLOlYc0uySvVKOB68Xj8pwZbeBrxgWdqV5PTWdGy5462jKNaSbrjNb2x6al__AGUzAsk)
[diagram source](https://mermaid.live/edit#pako:eNqNVO9r2zAQ_VcOQSGFhnwPYzDaZvRDt9J0H4YdjCJfYq22pOlHoLT933eSbHdL3LJPVi7vnt69u9MzE7pGtmR7y00DD1elKr0L2_xzjcrbpxgqvXQuoKtQ1UZL5YuSLXKoZJtJBHyazz_DS8m-Xj-U7AWCpJwVYr3l4hF-3Ix5Fo22_h_m4NDOdz12BArLXVP18E7XvCXsZQzCfQrCbQz2eOKjz9_l7IISXmrlitVwgjnYoEAqsLhDa9H2dzl-wCrKyNfFIIBrZFd5XY3KelnIPY7BKvkwyQK9IzcrwAN5C8Zqgc5hHQ2aZj-OJo53rxyLPjsDVAdstUEw0mArVQJwY4qfOlj4YkwrBY8ubAZdQ4aLcu6x5an36ZAgnIQYKWaFVHt0fs6956LpqBK3OU_sGZDApw4Osvr54KqG1FLICNfrG9TcfV-nwTmaj3fIpzJPB-ZDZXmAwbTc77TtYnTS6ESiK0HzEzq0M5rC3hAtRCBWJdJaJEvecClN0bo5ry0Ws2_D8XwzAaQyruOMrGk_eJfmQ4UtL2br-FlcUvMeG01V5Oz057hyvwNamdt4tJVjsbH-3tpkiFsEU1OtqQtTc2u083uLrpjd9acPbs7znapL0k_bZUz1S2_JOgpq6xL9sA_guYtrf8w6SiTKQc4bV-7txBL9j8JMwS4Y-d9xWdOT-FwqgJL5BjuCLOlYc0uySvVKOB68Xj8pwZbeBrxgWdqV5PTWdGy5462jKNaSbrjNb2x6al__AGUzAsk)

### [`save_userreport()`](https://github.com/getsentry/sentry/blob/2b642e149c79b251e1c2f4339fc73d656347d74e/src/sentry/ingest/userreport.py#L28-L28)

Before it was extended to generic feedback, the [`UserReport` model](https://github.com/getsentry/sentry/blob/2b642e149c79b251e1c2f4339fc73d656347d74e/src/sentry/models/userreport.py#L9-L9)
was first used for crash reports. Therefore an associated event id is required, and
aliu39 marked this conversation as resolved.
Show resolved Hide resolved
we use it to set environment and group before saving the model to **Postgres**.
Then we shim the report to a **feedback event** and pass it to `create_feedback_issue()`.

If the event hasn’t reached eventstore (Snuba) by the time of ingest, we still
save the report, but leave the environment + group empty and skip feedback creation.

To ensure the skipped reports eventually get fixed and shimmed to feedback, we
added a post process job to the errors pipeline: [`link_event_to_user_report()`](https://github.com/getsentry/sentry/blob/2b642e149c79b251e1c2f4339fc73d656347d74e/src/sentry/tasks/post_process.py#L1387-L1387).
This is the 5th, automated way of creating feedback.
<br/>

### Envelopes

User reports are also sent to Relay in [envelopes](https://develop.sentry.dev/sdk/envelopes/#user-feedback).
This item type is mistakenly called “user feedback” in some of our docs, but the
item header will read "user_report".

The SDK function that sends these is `captureUserFeedback`.
<br/>

### Django endpoint

Before our envelope ingest service existed, older SDKs directly POST the report
to Sentry, with
`/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/user-feedback/`

See [https://docs.sentry.io/api/projects/submit-user-feedback/](https://docs.sentry.io/api/projects/submit-user-feedback/)
aliu39 marked this conversation as resolved.
Show resolved Hide resolved
<br/>

### Crash reports

The crash report modal is a Django view -- an HTML form your app can render when
a page crashes. This was the earliest way of collecting feedback, and is for
error-specific feedback. You can install it as an [SDK integration](https://docs.sentry.io/platforms/javascript/user-feedback/#crash-report-modal).
aliu39 marked this conversation as resolved.
Show resolved Hide resolved

URL: `/api/embed/error-page/`

Python Class: `error_page_embed.ErrorPageEmbedView`

Crash reports are also shimmed to feedback. The pipeline is very similar to the
user report endpoint.

---

## Email alerts

Email alerts are triggered in feedback issue’s post process pipeline. (Unrelated
to the task in the user report diagram.) It’s the same alerts as generic,
non-error issues, but we apply some feedback-specific filters. **We skip emails if:**

1. The feedback is [marked as spam](https://docs.sentry.io/product/user-feedback/#spam-detection-for-user-feedback) AND the `organizations.user-feedback-spam-filter-actions` feature flag is enabled.
2. The source is NOT a new feedback envelope / the widget, AND the “Crash Report Notifications” setting is disabled.
- in UI: Settings > Projects > (project slug) > User Feedback > “Enable Crash Report Notifications”
- project option in code: `sentry:feedback_user_report_notifications`
- default = true/enabled
Loading