From 676a86b5144643e7c174f8dc10b049d7e11ee93f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 25 May 2026 00:42:20 -0400 Subject: [PATCH] =?UTF-8?q?fc3k:=20/api/admin=20tags=20prune-unused=20endp?= =?UTF-8?q?oint=20=E2=80=94=20Tier-A=20preview-then-commit=20flow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/app/api/admin.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index a5e0f6c..cefc181 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -179,3 +179,22 @@ async def tag_usage_count(tag_id: int): ) ) return jsonify({"count": count}) + + +@admin_bp.route("/tags/prune-unused", methods=["POST"]) +async def tags_prune_unused(): + """Tier-A: dry-run preview list IS the prompt. UI calls with + dry_run=true first, shows the list, operator clicks button to + re-call with dry_run=false.""" + from ..services.cleanup_service import prune_unused_tags + + body = await request.get_json(silent=True) or {} + dry_run = bool(body.get("dry_run", False)) + + async with get_session() as session: + result = await session.run_sync( + lambda sync_sess: prune_unused_tags( + sync_sess, dry_run=dry_run, + ) + ) + return jsonify(result)