diff --git a/bincio/serve/server.py b/bincio/serve/server.py
index 9003d02..2c86469 100644
--- a/bincio/serve/server.py
+++ b/bincio/serve/server.py
@@ -517,38 +517,57 @@ async def admin_rebuild(
return JSONResponse({"ok": True})
+def _wipe_user_activities(user_dir: Path) -> int:
+ """Delete all extracted activity files and caches for a user.
+
+ Removes activities/ (JSON + GeoJSON + timeseries), edits/, originals/,
+ _merged/, index.json, athlete.json, and the dedup cache.
+ Leaves the user directory itself intact (account remains in the DB).
+ Returns the number of files deleted.
+ """
+ import shutil
+ deleted = 0
+
+ for subdir in ("activities", "edits", "originals"):
+ d = user_dir / subdir
+ if d.exists():
+ for f in d.rglob("*"):
+ if f.is_file():
+ deleted += 1
+ shutil.rmtree(d)
+
+ for name in ("_merged", ):
+ d = user_dir / name
+ if d.exists():
+ shutil.rmtree(d)
+
+ for name in ("index.json", "athlete.json", ".bincio_cache.json"):
+ f = user_dir / name
+ if f.exists():
+ f.unlink()
+ deleted += 1
+
+ return deleted
+
+
@app.delete("/api/admin/users/{handle}/activities")
async def admin_delete_activities(
handle: str,
bincio_session: Optional[str] = Cookie(default=None),
) -> JSONResponse:
- """Delete all activity JSON files for a user and wipe the merged cache."""
+ """Delete all activity data for a user and wipe the merged cache."""
_require_admin(bincio_session)
user_dir = _get_data_dir() / handle
if not user_dir.is_dir():
raise HTTPException(404, f"No data directory for user '{handle}'")
- deleted = 0
- activities_dir = user_dir / "activities"
- if activities_dir.is_dir():
- for f in activities_dir.glob("*.json"):
- f.unlink()
- deleted += 1
-
- # Wipe merged cache, top-level index, and dedup cache so re-uploads aren't blocked
- import shutil
- merged_dir = user_dir / "_merged"
- if merged_dir.exists():
- shutil.rmtree(merged_dir)
- for name in ("index.json", ".bincio_cache.json"):
- f = user_dir / name
- if f.exists():
- f.unlink()
-
+ deleted = _wipe_user_activities(user_dir)
_trigger_rebuild(handle)
return JSONResponse({"ok": True, "deleted": deleted})
+
+
# ── Write API (ported from bincio edit, auth-gated) ───────────────────────────
def _user_data_dir(handle: str) -> Path:
diff --git a/site/src/pages/admin/index.astro b/site/src/pages/admin/index.astro
index c67ac33..1789631 100644
--- a/site/src/pages/admin/index.astro
+++ b/site/src/pages/admin/index.astro
@@ -33,10 +33,11 @@ import Base from '../../layouts/Base.astro';
@@ -124,7 +125,8 @@ import Base from '../../layouts/Base.astro';
+ title="Wipe all activities, originals, edits and images — account is kept"
+ >Reset data