Implement initial scan tracking for one-time setup

- Add SystemSettings model to track setup completion status
- Create SystemSettingsService for managing setup flags
- Modify fastapi_app startup to check and set initial_scan_completed flag
- Anime folder scanning now only runs on first startup
- Update DATABASE.md with new system_settings table documentation
- Add unit test for SystemSettingsService functionality

This ensures expensive one-time operations like scanning the entire anime
directory only occur during initial setup, not on every application restart.
This commit is contained in:
2026-01-21 19:22:50 +01:00
parent 35c82e68b7
commit bf3cfa00d5
8 changed files with 383 additions and 45 deletions

View File

@@ -543,3 +543,52 @@ class UserSession(Base, TimestampMixin):
def revoke(self) -> None:
"""Revoke this session."""
self.is_active = False
class SystemSettings(Base, TimestampMixin):
"""SQLAlchemy model for system-wide settings and state.
Stores application-level configuration and state flags that persist
across restarts. Used to track initialization status and setup completion.
Attributes:
id: Primary key (single row expected)
initial_scan_completed: Whether the initial anime folder scan has been completed
initial_nfo_scan_completed: Whether the initial NFO scan has been completed
initial_media_scan_completed: Whether the initial media scan has been completed
last_scan_timestamp: Timestamp of the last completed scan
created_at: Creation timestamp (from TimestampMixin)
updated_at: Last update timestamp (from TimestampMixin)
"""
__tablename__ = "system_settings"
# Primary key (only one row should exist)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True
)
# Setup/initialization tracking
initial_scan_completed: Mapped[bool] = mapped_column(
Boolean, nullable=False, default=False, server_default="0",
doc="Whether the initial anime folder scan has been completed"
)
initial_nfo_scan_completed: Mapped[bool] = mapped_column(
Boolean, nullable=False, default=False, server_default="0",
doc="Whether the initial NFO scan has been completed"
)
initial_media_scan_completed: Mapped[bool] = mapped_column(
Boolean, nullable=False, default=False, server_default="0",
doc="Whether the initial media scan has been completed"
)
last_scan_timestamp: Mapped[Optional[datetime]] = mapped_column(
DateTime(timezone=True), nullable=True,
doc="Timestamp of the last completed scan"
)
def __repr__(self) -> str:
return (
f"<SystemSettings(id={self.id}, "
f"initial_scan_completed={self.initial_scan_completed}, "
f"initial_nfo_scan_completed={self.initial_nfo_scan_completed}, "
f"initial_media_scan_completed={self.initial_media_scan_completed})>"
)