Files
stackpilot/backend/models/setting.py
T
menzeljandClaude Opus 4.8 84ef3df59e Phase 7: scheduled (recurring) backups (0.7.0)
- BackupSchedule model + schedule_service: next-run calc (hourly/daily/weekly,
  UTC), background scheduler loop (lifespan), run-one with retention pruning
  (keep newest N per stack on the destination), backup_failed notify event.
- routers/schedules.py: schedules CRUD + run-now; registered in main.py.
- Frontend: api/schedules.ts + Settings → Scheduled backups (list with next/last
  run + status, enable/disable, run-now, delete; add form with stack/destination/
  frequency/time/weekday/retention/volumes).

Rough-verified only (per request): py_compile, frontend tsc build, app import
(95 routes), next-run math sanity. Full live run to be tested after deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 22:02:52 +00:00

88 lines
2.0 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from typing import Optional
from sqlmodel import Field, SQLModel
def _now() -> datetime:
return datetime.now(timezone.utc)
# Notification event names ----------------------------------------------------
EVENT_UPDATE_AVAILABLE = "update_available"
EVENT_STACK_START = "stack_start"
EVENT_STACK_STOP = "stack_stop"
EVENT_STACK_ERROR = "stack_error"
EVENT_PULL_FAILED = "pull_failed"
EVENT_BACKUP_FAILED = "backup_failed"
ALL_EVENTS = [
EVENT_UPDATE_AVAILABLE,
EVENT_STACK_START,
EVENT_STACK_STOP,
EVENT_STACK_ERROR,
EVENT_PULL_FAILED,
EVENT_BACKUP_FAILED,
]
WEBHOOK_TYPES = ["ntfy", "discord", "slack", "gotify", "generic"]
class Setting(SQLModel, table=True):
"""Simple key/value store for runtime-tunable settings (JSON-encoded value)."""
key: str = Field(primary_key=True)
value: str # JSON-encoded
class Webhook(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
url: str
type: str = "generic" # one of WEBHOOK_TYPES
events: str = ",".join(ALL_EVENTS) # comma-separated subscribed events
enabled: bool = True
created_at: datetime = Field(default_factory=_now)
# --- API schemas ---
class WebhookCreate(SQLModel):
name: str
url: str
type: str = "generic"
events: list[str] = ALL_EVENTS
enabled: bool = True
class WebhookUpdate(SQLModel):
name: Optional[str] = None
url: Optional[str] = None
type: Optional[str] = None
events: Optional[list[str]] = None
enabled: Optional[bool] = None
class WebhookRead(SQLModel):
id: int
name: str
url: str
type: str
events: list[str]
enabled: bool
created_at: datetime
class SettingsRead(SQLModel):
update_check_interval_minutes: int
env_webhook_count: int
available_events: list[str]
webhook_types: list[str]
class SettingsUpdate(SQLModel):
update_check_interval_minutes: Optional[int] = None