From 8391cf275a214e1ff63ca0071116fb13fae676bd Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Fri, 15 May 2026 07:13:33 +0100 Subject: [PATCH] ML-180: remove backup download feature Delete ArchiveController, its routes, the maintenance UI backup button, and the test file. Management scripts and Litestream supersede this functionality. --- ...Remove-backup-function-from-application.md | 38 +++++++++++++++---- docs/architecture.md | 1 - .../controllers/archive_controller.ex | 23 ----------- .../live/maintenance_live/index.ex | 3 -- lib/music_library_web/router.ex | 3 -- priv/gettext/default.pot | 1 - priv/gettext/en/LC_MESSAGES/default.po | 1 - .../controllers/archive_controller_test.exs | 17 --------- 8 files changed, 30 insertions(+), 57 deletions(-) rename backlog/{tasks => completed}/ml-180 - Remove-backup-function-from-application.md (78%) delete mode 100644 lib/music_library_web/controllers/archive_controller.ex delete mode 100644 test/music_library_web/controllers/archive_controller_test.exs diff --git a/backlog/tasks/ml-180 - Remove-backup-function-from-application.md b/backlog/completed/ml-180 - Remove-backup-function-from-application.md similarity index 78% rename from backlog/tasks/ml-180 - Remove-backup-function-from-application.md rename to backlog/completed/ml-180 - Remove-backup-function-from-application.md index fcfac1fa..d54a3684 100644 --- a/backlog/tasks/ml-180 - Remove-backup-function-from-application.md +++ b/backlog/completed/ml-180 - Remove-backup-function-from-application.md @@ -1,14 +1,20 @@ --- id: ML-180 title: Remove backup function from application -status: To Do +status: Done assignee: [] created_date: "2026-05-12 04:57" -updated_date: "2026-05-12 10:25" +updated_date: "2026-05-15 06:11" labels: - api - ui dependencies: [] +modified_files: + - lib/music_library_web/router.ex + - lib/music_library_web/controllers/archive_controller.ex + - lib/music_library_web/live/maintenance_live/index.ex + - test/music_library_web/controllers/archive_controller_test.exs + - docs/architecture.md --- ## Description @@ -23,12 +29,12 @@ Management scripts and tools superseded this functionality. It can be removed fr -- [ ] #1 The /backup and /api/v1/backup routes return 404 -- [ ] #2 The Maintenance page no longer shows a Backup button in the Database section -- [ ] #3 `mix compile --warnings-as-errors` passes with no ArchiveController references -- [ ] #4 `mix test` passes with no ArchiveControllerTest references -- [ ] #5 The record format `:backup` type still works (record_component format labels still show "Backup" for backup-format records) -- [ ] #6 `docs/architecture.md` no longer lists ArchiveController in the routes table +- [x] #1 The /backup and /api/v1/backup routes return 404 +- [x] #2 The Maintenance page no longer shows a Backup button in the Database section +- [x] #3 `mix compile --warnings-as-errors` passes with no ArchiveController references +- [x] #4 `mix test` passes with no ArchiveControllerTest references +- [x] #5 The record format `:backup` type still works (record_component format labels still show "Backup" for backup-format records) +- [x] #6 `docs/architecture.md` no longer lists ArchiveController in the routes table ## Implementation Plan @@ -136,3 +142,19 @@ None required. No migrations, no environment variables, no service provisioning. - **`docs/architecture.md`**: Remove the `ArchiveController` row from the routes table. No other architecture docs need changes. - No changes to `docs/project-conventions.md`, `docs/production-infrastructure.md`, `docs/available-tasks.md`, or README needed. + +## Final Summary + + + +Removed the in-app database backup download feature: + +1. **Router** (`lib/music_library_web/router.ex`): Removed `get "/backup", ArchiveController, :backup` from both the `:logged_in` pipeline and the `:api` scope. +2. **Controller** (`lib/music_library_web/controllers/archive_controller.ex`): Deleted — module only contained `backup/2` and a private `database_path/0` helper. +3. **Maintenance UI** (`lib/music_library_web/live/maintenance_live/index.ex`): Removed the `<.button href={~p"/backup"}>` element from the Database section. +4. **Tests** (`test/music_library_web/controllers/archive_controller_test.exs`): Deleted. +5. **Docs** (`docs/architecture.md`): Removed the `ArchiveController` row from the controller routes table. + +All 982 tests pass. No ArchiveController references remain. The `:backup` record format atom and `format_label(:backup)` are intentionally untouched (they represent a record format type, not the backup download feature). + + diff --git a/docs/architecture.md b/docs/architecture.md index c606a900..920f9273 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -345,7 +345,6 @@ All authenticated routes live inside a single `live_session` with three `on_moun | `SessionController` | `/login`, `/sessions/create` | Login/logout | | `HealthController` | `/health` | Health check | | `LastFmController` | `/auth/last_fm/callback` | Last.fm OAuth | -| `ArchiveController` | `/backup`, `/api/v1/backup` | Database backup download (API route requires token) | | `AssetController` | `/assets/:transform_payload`, `/public/assets/:transform_payload`, `/api/v1/assets/:transform_payload` | Serve images with transforms (public route for emails, API route requires token) | | `CollectionController` | `/api/v1/collection/*`, `POST /api/v1/collection/:record_id/scrobble` | JSON API for collection queries (search with `?q=`, returns 4 cover sizes), and scrobbling records from Presto | | `ErrorController` | `/api/v1/errors`, `/api/v1/errors/:id`, `/api/v1/errors/:id/mute`, `/api/v1/errors/:id/unmute`, `/api/v1/errors/:id/resolve`, `/api/v1/errors/:id/unresolve` | JSON API for production error queries and mutations (requires Bearer token); POST endpoints for mute/unmute/resolve/unresolve | diff --git a/lib/music_library_web/controllers/archive_controller.ex b/lib/music_library_web/controllers/archive_controller.ex deleted file mode 100644 index 2a66145f..00000000 --- a/lib/music_library_web/controllers/archive_controller.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule MusicLibraryWeb.ArchiveController do - use MusicLibraryWeb, :controller - - # The database path is configuration controlled, and not derived from any - # user input, so we can safely skip the check. - # sobelow_skip ["Traversal.SendDownload"] - def backup(conn, _params) do - MusicLibrary.Repo.vacuum() - - database_path = database_path() - current_time = DateTime.utc_now() - file_name = "music_library_#{DateTime.to_unix(current_time)}.db" - - send_download(conn, {:file, database_path}, - filename: file_name, - content_type: "application/x-sqlite3" - ) - end - - defp database_path do - Application.get_env(:music_library, MusicLibrary.Repo)[:database] - end -end diff --git a/lib/music_library_web/live/maintenance_live/index.ex b/lib/music_library_web/live/maintenance_live/index.ex index baf940a4..ae45d49a 100644 --- a/lib/music_library_web/live/maintenance_live/index.ex +++ b/lib/music_library_web/live/maintenance_live/index.ex @@ -153,9 +153,6 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do > {gettext("Optimize")} - <.button href={~p"/backup"}> - {gettext("Backup")} - diff --git a/lib/music_library_web/router.ex b/lib/music_library_web/router.ex index 44bb5cf3..79cd3a61 100644 --- a/lib/music_library_web/router.ex +++ b/lib/music_library_web/router.ex @@ -63,8 +63,6 @@ defmodule MusicLibraryWeb.Router do scope "/" do pipe_through :logged_in - get "/backup", ArchiveController, :backup - get "/assets/:transform_payload", AssetController, :show live_session :default, @@ -138,7 +136,6 @@ defmodule MusicLibraryWeb.Router do post "/errors/:id/resolve", ErrorController, :resolve post "/errors/:id/unresolve", ErrorController, :unresolve get "/assets/:transform_payload", AssetController, :show - get "/backup", ArchiveController, :backup end if Application.compile_env(:music_library, :monitoring_routes) do diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 0b73b53b..ad572749 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -362,7 +362,6 @@ msgid "Album" msgstr "" #: lib/music_library_web/components/record_components.ex -#: lib/music_library_web/live/maintenance_live/index.ex #, elixir-autogen, elixir-format msgid "Backup" msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 54e971b5..f084d296 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -362,7 +362,6 @@ msgid "Album" msgstr "" #: lib/music_library_web/components/record_components.ex -#: lib/music_library_web/live/maintenance_live/index.ex #, elixir-autogen, elixir-format msgid "Backup" msgstr "" diff --git a/test/music_library_web/controllers/archive_controller_test.exs b/test/music_library_web/controllers/archive_controller_test.exs deleted file mode 100644 index b6d94cb6..00000000 --- a/test/music_library_web/controllers/archive_controller_test.exs +++ /dev/null @@ -1,17 +0,0 @@ -defmodule MusicLibraryWeb.ArchiveControllerTest do - use MusicLibraryWeb.ConnCase - - describe "GET /backup" do - test "returns a sqlite database file", %{conn: conn} do - conn = get(conn, "/backup") - - assert response(conn, 200) - assert get_resp_header(conn, "content-type") |> hd() =~ "application/x-sqlite3" - - [content_disposition] = get_resp_header(conn, "content-disposition") - assert content_disposition =~ "attachment" - assert content_disposition =~ "music_library_" - assert content_disposition =~ ".db" - end - end -end