Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- **Ecto prefix configuration** - Support namespacing through PostgreSQL schemas, also called "prefixes" in Ecto.
- Excluding the `prefix` configuration will use primary schema (usually public).

## [1.0.2] - 2025-12-28

### Fixed
Expand Down Expand Up @@ -50,4 +53,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Igniter installer** - `mix fyi.install` for one-command setup
- **Emoji support** - Per-event, pattern-based, and default emoji configuration
- **App name identification** - Identify events when multiple apps share channels

8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mix fyi.install
```

This will:

1. Add `FYI.Application` to your supervision tree
2. Create a migration for the `fyi_events` table
3. Print instructions to add the `/fyi` route to your router
Expand All @@ -63,6 +64,7 @@ config :fyi,
app_name: "MyApp",
persist_events: true,
repo: MyApp.Repo,
prefix: "fyi", # optional
sinks: [
{FYI.Sink.SlackWebhook, %{url: System.get_env("SLACK_WEBHOOK_URL")}},
{FYI.Sink.Telegram, %{
Expand Down Expand Up @@ -92,11 +94,13 @@ Messages will include the app name: `[MyApp] *purchase.created* by user_123`
Add emojis to your notifications in three ways (in priority order):

**1. Per-event override:**

```elixir
FYI.emit("error.critical", %{message: "DB down"}, emoji: "🚨")
```

**2. Pattern-based mapping:**

```elixir
config :fyi,
emojis: %{
Expand All @@ -108,6 +112,7 @@ config :fyi,
```

**3. Default fallback:**

```elixir
config :fyi, emoji: "📣"
```
Expand All @@ -117,6 +122,7 @@ Messages will show as: `💰 [MyApp] *purchase.created* by user_123`
### Routing

Routes use simple glob matching:

- `purchase.*` matches `purchase.created`, `purchase.updated`, etc.
- `*` at the end matches any suffix

Expand All @@ -135,6 +141,7 @@ FYI.emit("error.critical", %{message: "DB connection failed"}, emoji: "🚨", ta
```

Options:

- `:actor` - who triggered the event (user_id, email, etc.)
- `:source` - where the event originated (e.g., "api", "web", "worker")
- `:tags` - additional metadata map for filtering
Expand Down Expand Up @@ -195,6 +202,7 @@ end
```

Visit `/fyi` to see the event inbox with:

- Activity histogram with time-based tooltips
- Real-time event updates (requires PubSub config)
- Time range filtering (5 minutes to all time)
Expand Down
4 changes: 3 additions & 1 deletion lib/fyi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ defmodule FYI do
config :fyi,
persist_events: true,
repo: MyApp.Repo,
prefix: "fyi", # optional
sinks: [
{FYI.Sink.SlackWebhook, %{url: System.get_env("SLACK_WEBHOOK_URL")}},
{FYI.Sink.Telegram, %{
Expand Down Expand Up @@ -122,6 +123,7 @@ defmodule FYI do

defp persist_event(event) do
repo = Application.get_env(:fyi, :repo)
prefix = Application.get_env(:fyi, :prefix)

if repo do
attrs = %{
Expand All @@ -134,7 +136,7 @@ defmodule FYI do
inserted_at: event.occurred_at
}

case repo.insert(%FYI.Schema.Event{} |> struct(attrs)) do
case repo.insert(%FYI.Schema.Event{} |> struct(attrs), prefix: prefix) do
{:ok, _} -> :ok
{:error, changeset} -> {:error, changeset}
end
Expand Down
11 changes: 7 additions & 4 deletions lib/fyi/web/inbox_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ if Code.ensure_loaded?(Phoenix.LiveView) do

defp load_events(socket) do
repo = Application.get_env(:fyi, :repo)
prefix = Application.get_env(:fyi, :prefix)

if repo && Code.ensure_loaded?(Event) do
import Ecto.Query
Expand Down Expand Up @@ -833,7 +834,7 @@ if Code.ensure_loaded?(Phoenix.LiveView) do
query
end

events = repo.all(query)
events = repo.all(query, prefix: prefix)
assign(socket, :events, events)
else
assign(socket, :events, [])
Expand All @@ -842,6 +843,7 @@ if Code.ensure_loaded?(Phoenix.LiveView) do

defp load_event_types(socket) do
repo = Application.get_env(:fyi, :repo)
prefix = Application.get_env(:fyi, :prefix)

if repo && Code.ensure_loaded?(Event) do
import Ecto.Query
Expand All @@ -852,11 +854,11 @@ if Code.ensure_loaded?(Phoenix.LiveView) do
distinct: true,
order_by: [asc: e.name]
)
|> repo.all()
|> repo.all(prefix: prefix)

total_count =
from(e in Event, select: count(e.id))
|> repo.one()
|> repo.one(prefix: prefix)

socket
|> assign(:event_types, types)
Expand Down Expand Up @@ -1016,9 +1018,10 @@ if Code.ensure_loaded?(Phoenix.LiveView) do

defp load_event_detail(socket, id) do
repo = Application.get_env(:fyi, :repo)
prefix = Application.get_env(:fyi, :prefix)

if repo && Code.ensure_loaded?(Event) do
case repo.get(Event, id) do
case repo.get(Event, id, prefix: prefix) do
nil -> assign(socket, :selected_event, nil)
event -> assign(socket, :selected_event, event)
end
Expand Down