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.
This commit is contained in:
+30
-8
@@ -1,14 +1,20 @@
|
|||||||
---
|
---
|
||||||
id: ML-180
|
id: ML-180
|
||||||
title: Remove backup function from application
|
title: Remove backup function from application
|
||||||
status: To Do
|
status: Done
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: "2026-05-12 04:57"
|
created_date: "2026-05-12 04:57"
|
||||||
updated_date: "2026-05-12 10:25"
|
updated_date: "2026-05-15 06:11"
|
||||||
labels:
|
labels:
|
||||||
- api
|
- api
|
||||||
- ui
|
- ui
|
||||||
dependencies: []
|
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
|
## Description
|
||||||
@@ -23,12 +29,12 @@ Management scripts and tools superseded this functionality. It can be removed fr
|
|||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [ ] #1 The /backup and /api/v1/backup routes return 404
|
- [x] #1 The /backup and /api/v1/backup routes return 404
|
||||||
- [ ] #2 The Maintenance page no longer shows a Backup button in the Database section
|
- [x] #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
|
- [x] #3 `mix compile --warnings-as-errors` passes with no ArchiveController references
|
||||||
- [ ] #4 `mix test` passes with no ArchiveControllerTest references
|
- [x] #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)
|
- [x] #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] #6 `docs/architecture.md` no longer lists ArchiveController in the routes table
|
||||||
<!-- AC:END -->
|
<!-- AC:END -->
|
||||||
|
|
||||||
## Implementation Plan
|
## 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.
|
- **`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.
|
- No changes to `docs/project-conventions.md`, `docs/production-infrastructure.md`, `docs/available-tasks.md`, or README needed.
|
||||||
<!-- SECTION:PLAN:END -->
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -345,7 +345,6 @@ All authenticated routes live inside a single `live_session` with three `on_moun
|
|||||||
| `SessionController` | `/login`, `/sessions/create` | Login/logout |
|
| `SessionController` | `/login`, `/sessions/create` | Login/logout |
|
||||||
| `HealthController` | `/health` | Health check |
|
| `HealthController` | `/health` | Health check |
|
||||||
| `LastFmController` | `/auth/last_fm/callback` | Last.fm OAuth |
|
| `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) |
|
| `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 |
|
| `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 |
|
| `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 |
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -153,9 +153,6 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
|
|||||||
>
|
>
|
||||||
{gettext("Optimize")}
|
{gettext("Optimize")}
|
||||||
</.button>
|
</.button>
|
||||||
<.button href={~p"/backup"}>
|
|
||||||
{gettext("Backup")}
|
|
||||||
</.button>
|
|
||||||
</.button_group>
|
</.button_group>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ defmodule MusicLibraryWeb.Router do
|
|||||||
scope "/" do
|
scope "/" do
|
||||||
pipe_through :logged_in
|
pipe_through :logged_in
|
||||||
|
|
||||||
get "/backup", ArchiveController, :backup
|
|
||||||
|
|
||||||
get "/assets/:transform_payload", AssetController, :show
|
get "/assets/:transform_payload", AssetController, :show
|
||||||
|
|
||||||
live_session :default,
|
live_session :default,
|
||||||
@@ -138,7 +136,6 @@ defmodule MusicLibraryWeb.Router do
|
|||||||
post "/errors/:id/resolve", ErrorController, :resolve
|
post "/errors/:id/resolve", ErrorController, :resolve
|
||||||
post "/errors/:id/unresolve", ErrorController, :unresolve
|
post "/errors/:id/unresolve", ErrorController, :unresolve
|
||||||
get "/assets/:transform_payload", AssetController, :show
|
get "/assets/:transform_payload", AssetController, :show
|
||||||
get "/backup", ArchiveController, :backup
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if Application.compile_env(:music_library, :monitoring_routes) do
|
if Application.compile_env(:music_library, :monitoring_routes) do
|
||||||
|
|||||||
@@ -362,7 +362,6 @@ msgid "Album"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/record_components.ex
|
#: lib/music_library_web/components/record_components.ex
|
||||||
#: lib/music_library_web/live/maintenance_live/index.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Backup"
|
msgid "Backup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -362,7 +362,6 @@ msgid "Album"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/record_components.ex
|
#: lib/music_library_web/components/record_components.ex
|
||||||
#: lib/music_library_web/live/maintenance_live/index.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Backup"
|
msgid "Backup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user