feat(settings): add log retention settings page

Sysadmin/admin-only settings page for configuring how long device log
history is kept before pruning. GET/PUT /api/settings/log-retention,
new LogRetentionSettings page, nav entry, and route.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 18:33:40 +03:00
co-authored by Claude Sonnet 5
parent acd1896788
commit dff1a35560
6 changed files with 171 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
from typing import Optional
class LogRetentionSettings(BaseModel):
days: int = 180
class LogRetentionSettingsUpdate(BaseModel):
days: Optional[int] = None
+31
View File
@@ -0,0 +1,31 @@
from shared.firebase import get_db
from settings.log_retention_models import LogRetentionSettings, LogRetentionSettingsUpdate
COLLECTION = "admin_settings"
DOC_ID = "log_retention"
def get_log_retention() -> LogRetentionSettings:
"""Get log retention settings from Firestore. Creates defaults if not found."""
db = get_db()
doc = db.collection(COLLECTION).document(DOC_ID).get()
if doc.exists:
return LogRetentionSettings(**doc.to_dict())
defaults = LogRetentionSettings()
db.collection(COLLECTION).document(DOC_ID).set(defaults.model_dump())
return defaults
def update_log_retention(data: LogRetentionSettingsUpdate) -> LogRetentionSettings:
"""Update log retention settings. Only provided fields are updated."""
db = get_db()
doc_ref = db.collection(COLLECTION).document(DOC_ID)
doc = doc_ref.get()
existing = doc.to_dict() if doc.exists else LogRetentionSettings().model_dump()
update_data = data.model_dump(exclude_none=True)
existing.update(update_data)
normalized = LogRetentionSettings(**existing)
doc_ref.set(normalized.model_dump())
return normalized
+19
View File
@@ -4,8 +4,10 @@ from auth.dependencies import require_permission, require_roles
from auth.models import Role
from settings.models import MelodySettings, MelodySettingsUpdate
from settings.public_features_models import PublicFeaturesSettings, PublicFeaturesSettingsUpdate
from settings.log_retention_models import LogRetentionSettings, LogRetentionSettingsUpdate
from settings import service
from settings import public_features_service
from settings import log_retention_service
router = APIRouter(prefix="/api/settings", tags=["settings"])
@@ -40,3 +42,20 @@ async def update_public_features(
_user: TokenPayload = Depends(require_roles(Role.sysadmin, Role.admin)),
):
return public_features_service.update_public_features(body)
# ── Log Retention Settings (sysadmin / admin only) ───────────────────────────
@router.get("/log-retention", response_model=LogRetentionSettings)
async def get_log_retention(
_user: TokenPayload = Depends(require_roles(Role.sysadmin, Role.admin)),
):
return log_retention_service.get_log_retention()
@router.put("/log-retention", response_model=LogRetentionSettings)
async def update_log_retention(
body: LogRetentionSettingsUpdate,
_user: TokenPayload = Depends(require_roles(Role.sysadmin, Role.admin)),
):
return log_retention_service.update_log_retention(body)