diff --git a/config/config.exs b/config/config.exs
index 8e86d530..ca85aaca 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -68,6 +68,11 @@ config :logger, :console,
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
+config :error_tracker,
+ repo: MusicLibrary.Repo,
+ otp_app: :music_library,
+ enabled: true
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
diff --git a/lib/music_library_web/components/layouts/app.html.heex b/lib/music_library_web/components/layouts/app.html.heex
index b0b1eac5..64855d2e 100644
--- a/lib/music_library_web/components/layouts/app.html.heex
+++ b/lib/music_library_web/components/layouts/app.html.heex
@@ -25,6 +25,9 @@
{gettext("Dev dashboard")}
+
+ {gettext("Errors")}
+
{gettext("Logout")}
diff --git a/lib/music_library_web/router.ex b/lib/music_library_web/router.ex
index c4ecbe45..873a9c7b 100644
--- a/lib/music_library_web/router.ex
+++ b/lib/music_library_web/router.ex
@@ -1,5 +1,6 @@
defmodule MusicLibraryWeb.Router do
use MusicLibraryWeb, :router
+ use ErrorTracker.Web, :router
import MusicLibraryWeb.Auth, only: [require_logged_in: 2, require_api_token: 2]
@@ -72,6 +73,8 @@ defmodule MusicLibraryWeb.Router do
scope "/dev" do
pipe_through [:browser, :logged_in]
+ error_tracker_dashboard("/errors")
+
live_dashboard "/dashboard",
metrics: MusicLibraryWeb.Telemetry,
metrics_history: {MusicLibraryWeb.Telemetry.Storage, :metrics_history, []},
diff --git a/mix.exs b/mix.exs
index d7f79bec..1748ccbf 100644
--- a/mix.exs
+++ b/mix.exs
@@ -50,6 +50,7 @@ defmodule MusicLibrary.MixProject do
{:floki, ">= 0.30.0", only: :test},
{:mox, "~> 1.2", only: :test},
{:phoenix_live_dashboard, "~> 0.8.3"},
+ {:error_tracker, "~> 0.5.1"},
{:recon, "~> 2.5"},
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
diff --git a/mix.lock b/mix.lock
index d9722137..c0270348 100644
--- a/mix.lock
+++ b/mix.lock
@@ -11,6 +11,7 @@
"ecto_sqlite3": {:hex, :ecto_sqlite3, "0.18.0", "dd25010d7b536bb00857f3bf47193f293619b0c30538bf912d4bd82861d25fba", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "e42ef8252e22c6f65e5421289f9e5ceffd1a4a7e01cb2818d5eab78205d3cce7"},
"ecto_sqlite3_extras": {:hex, :ecto_sqlite3_extras, "1.2.2", "36e60b561a11441d15f26c791817999269fb578b985162207ebb08b04ca71e40", [:mix], [{:exqlite, ">= 0.13.2", [hex: :exqlite, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "2b66ba7246bb4f7e39e2578acd4a0e4e4be54f60ff52d450a01be95eeb78ff1e"},
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
+ "error_tracker": {:hex, :error_tracker, "0.5.1", "b3a13f5d7bd3b370520b58751d6e48387ad0a5386cacee03cd383db0d5eae1f0", [:mix], [{:ecto, "~> 3.11", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, ">= 0.0.0", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:myxql, ">= 0.0.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:phoenix_ecto, "~> 4.6", [hex: :phoenix_ecto, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "a51c05a27559237b7eabbadc799b433cbed606a6fd26daa5268d8311eeb5484c"},
"esbuild": {:hex, :esbuild, "0.8.2", "5f379dfa383ef482b738e7771daf238b2d1cfb0222bef9d3b20d4c8f06c7a7ac", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "558a8a08ed78eb820efbfda1de196569d8bfa9b51e8371a1934fbb31345feda7"},
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
"exqlite": {:hex, :exqlite, "0.27.1", "73fc0b3dc3b058a77a2b3771f82a6af2ddcf370b069906968a34083d2ffd2884", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "79ef5756451cfb022e8013e1ed00d0f8f7d1333c19502c394dc16b15cfb4e9b4"},
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index 5b26d0ed..936e4e65 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -123,7 +123,7 @@ msgstr ""
msgid "Login"
msgstr ""
-#: lib/music_library_web/components/layouts/app.html.heex:29
+#: lib/music_library_web/components/layouts/app.html.heex:32
#, elixir-autogen, elixir-format
msgid "Logout"
msgstr ""
@@ -514,3 +514,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "A->Z"
msgstr ""
+
+#: lib/music_library_web/components/layouts/app.html.heex:29
+#, elixir-autogen, elixir-format
+msgid "Errors"
+msgstr ""
diff --git a/priv/repo/migrations/20250101170610_add_error_tracker.exs b/priv/repo/migrations/20250101170610_add_error_tracker.exs
new file mode 100644
index 00000000..a63a31f9
--- /dev/null
+++ b/priv/repo/migrations/20250101170610_add_error_tracker.exs
@@ -0,0 +1,7 @@
+defmodule MusicLibrary.Repo.Migrations.AddErrorTracker do
+ use Ecto.Migration
+ def up, do: ErrorTracker.Migration.up(version: 4)
+
+ # We specify `version: 1` in `down`, to ensure we remove all migrations.
+ def down, do: ErrorTracker.Migration.down(version: 1)
+end