Working metrics for all forms of interactions and updated .env.example
This commit is contained in:
11
.env.example
11
.env.example
@@ -27,3 +27,14 @@ S3_VIRTUAL_HOST=false
|
||||
|
||||
# Email (Brevo)
|
||||
BREVO_API_KEY=your-brevo-api-key
|
||||
|
||||
# ClickHouse (analytics / metrics)
|
||||
# single connection URL (overrides all individual vars below)
|
||||
CLICKHOUSE_URL=http://default:password@localhost:8123/mixer_metrics
|
||||
# individual vars (used when CLICKHOUSE_URL is not set)
|
||||
CLICKHOUSE_HOST=localhost
|
||||
CLICKHOUSE_PORT=8123
|
||||
CLICKHOUSE_DATABASE=mixer_metrics
|
||||
CLICKHOUSE_USERNAME=default
|
||||
CLICKHOUSE_PASSWORD=
|
||||
CLICKHOUSE_SCHEME=http
|
||||
|
||||
@@ -33,7 +33,8 @@ defmodule Mixer.Metrics do
|
||||
# Event types
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@type event_type :: :view | :like | :unlike | :comment | :share
|
||||
@type event_type ::
|
||||
:view | :post | :comment | :like | :unlike | :share | :delete_post | :delete_comment
|
||||
|
||||
@type track_opt ::
|
||||
{:user_id, binary() | nil}
|
||||
@@ -70,6 +71,33 @@ defmodule Mixer.Metrics do
|
||||
@spec track_share(binary(), [track_opt()]) :: :ok
|
||||
def track_share(tweet_id, opts \\ []), do: enqueue("share", tweet_id, opts)
|
||||
|
||||
@doc """
|
||||
Track a new top-level tweet being published.
|
||||
|
||||
The event is recorded against the new tweet's own ID.
|
||||
"""
|
||||
@spec track_post(binary(), [track_opt()]) :: :ok
|
||||
def track_post(tweet_id, opts \\ []), do: enqueue("post", tweet_id, opts)
|
||||
|
||||
@doc """
|
||||
Track a top-level tweet being deleted.
|
||||
|
||||
The event is recorded against the deleted tweet's ID.
|
||||
Note: cascade-deleted comments are not individually tracked — only the
|
||||
explicit user-initiated destroy action emits this event.
|
||||
"""
|
||||
@spec track_delete_post(binary(), [track_opt()]) :: :ok
|
||||
def track_delete_post(tweet_id, opts \\ []), do: enqueue("delete_post", tweet_id, opts)
|
||||
|
||||
@doc """
|
||||
Track a comment (reply) being deleted.
|
||||
|
||||
The event is recorded against the *parent* tweet's ID so that
|
||||
`get_summary/1` can reflect net comment activity on a tweet.
|
||||
"""
|
||||
@spec track_delete_comment(binary(), [track_opt()]) :: :ok
|
||||
def track_delete_comment(tweet_id, opts \\ []), do: enqueue("delete_comment", tweet_id, opts)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Query helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -8,13 +8,16 @@ defmodule Mixer.Metrics.PostEvent do
|
||||
|
||||
## Event types
|
||||
|
||||
| event_type | Description |
|
||||
|-------------|------------------------------------------|
|
||||
| `"view"` | A tweet was displayed to a user |
|
||||
| `"like"` | A user liked a tweet |
|
||||
| `"unlike"` | A user removed their like from a tweet |
|
||||
| `"comment"` | A user replied to a tweet |
|
||||
| `"share"` | A user shared / reposted a tweet |
|
||||
| event_type | `tweet_id` refers to | Description |
|
||||
|--------------------|-----------------------|-------------------------------------------------|
|
||||
| `"view"` | the viewed tweet | Tweet detail page was loaded |
|
||||
| `"post"` | the new tweet | A new top-level tweet was published |
|
||||
| `"comment"` | the parent tweet | A reply was posted; count against the parent |
|
||||
| `"like"` | the liked tweet | A user liked a tweet |
|
||||
| `"unlike"` | the unliked tweet | A user removed their like |
|
||||
| `"share"` | the shared tweet | A user shared / reposted a tweet |
|
||||
| `"delete_post"` | the deleted tweet | A top-level tweet was deleted by its author |
|
||||
| `"delete_comment"` | the parent tweet | A reply was deleted; count against the parent |
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
@@ -32,7 +32,7 @@ defmodule Mixer.Posts.Tweet do
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:read, :destroy]
|
||||
defaults [:read]
|
||||
|
||||
read :following_feed do
|
||||
filter expr(
|
||||
@@ -67,25 +67,48 @@ defmodule Mixer.Posts.Tweet do
|
||||
end
|
||||
end
|
||||
|
||||
# Track a "comment" metric event whenever a reply is posted. We record
|
||||
# the event against the *parent* tweet so that `get_summary/1` and
|
||||
# `get_bulk_summaries/1` can count how many comments each tweet received.
|
||||
# Track post / comment creation metrics.
|
||||
# Root tweets emit a "post" event recorded against their own ID.
|
||||
# Replies emit a "comment" event recorded against the parent tweet ID so
|
||||
# that `get_summary/1` can count how many replies a tweet has received.
|
||||
change fn changeset, context ->
|
||||
case Ash.Changeset.get_attribute(changeset, :parent_tweet_id) do
|
||||
nil ->
|
||||
changeset
|
||||
parent_tweet_id = Ash.Changeset.get_attribute(changeset, :parent_tweet_id)
|
||||
user_id = context.actor && context.actor.id
|
||||
|
||||
parent_tweet_id ->
|
||||
Ash.Changeset.after_action(changeset, fn _changeset, tweet ->
|
||||
Mixer.Metrics.track_comment(
|
||||
parent_tweet_id,
|
||||
user_id: context.actor && context.actor.id
|
||||
)
|
||||
if parent_tweet_id do
|
||||
Mixer.Metrics.track_comment(parent_tweet_id, user_id: user_id)
|
||||
else
|
||||
Mixer.Metrics.track_post(tweet.id, user_id: user_id)
|
||||
end
|
||||
|
||||
{:ok, tweet}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
# Explicit destroy so we can attach a metrics hook. The policy and cascade
|
||||
# behaviour are identical to the previous default :destroy action.
|
||||
destroy :destroy do
|
||||
require_atomic? false
|
||||
|
||||
change fn changeset, context ->
|
||||
# Capture the record's identity *before* deletion — after the action
|
||||
# completes the row no longer exists.
|
||||
tweet_id = changeset.data.id
|
||||
parent_tweet_id = changeset.data.parent_tweet_id
|
||||
user_id = context.actor && context.actor.id
|
||||
|
||||
Ash.Changeset.after_action(changeset, fn _changeset, result ->
|
||||
if parent_tweet_id do
|
||||
Mixer.Metrics.track_delete_comment(parent_tweet_id, user_id: user_id)
|
||||
else
|
||||
Mixer.Metrics.track_delete_post(tweet_id, user_id: user_id)
|
||||
end
|
||||
|
||||
{:ok, result}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
update :update do
|
||||
|
||||
Reference in New Issue
Block a user