Files
Jakeandopencode aced0a1a3b Add MOT/insurance renewal hints, table service card, and favicon
- Renewal tracking: compute due/overdue status from the most recent
  mot/insurance event (renewal_months, renewal_due_soon_days settings),
  surfaced on the service card and dashboard.
- Service-status card metrics now render as a two-column label/value
  table with row separators instead of wrapping auto-fill grid cells.
- Add a bicycle favicon (favicon.svg) to base + login templates.

Co-Authored-By: opencode <opencode@users.noreply.github.com>
2026-09-10 10:01:17 +01:00

64 lines
1.8 KiB
Python

from functools import lru_cache
from pathlib import Path
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
BASE_DIR = Path(__file__).resolve().parent.parent
class Settings(BaseSettings):
# Core
data_dir: Path = Field(default=BASE_DIR / "data")
db_path: Path | None = None # defaults to <data_dir>/bike_admin.db when None
secret_key: str = Field(default="change-me", min_length=8) # CSRF/session HMAC
username: str = Field(default="admin", min_length=1)
password: str | None = None # REQUIRED on first run (see ensure_user)
# Hosting posture
is_production: bool = False # True => Secure cookies + stricter headers
bind_host: str = "127.0.0.1"
bind_port: int = 8000
trust_proxy: bool = True # honor X-Forwarded-For/Proto behind a reverse proxy
# Sessions
session_ttl_seconds: int = 7 * 24 * 3600
# Login throttling
login_max_attempts: int = 8
login_window_seconds: int = 300
# Service hint: flag a bike as "book soon" when it is this close to due.
service_due_soon_miles: int = 200
# Renewal hint: flag MOT/insurance as "due soon" when it falls due within
# this many days (default 60 days).
renewal_due_soon_days: int = 60
# Months a logged MOT/insurance event is valid before it falls due.
renewal_months: int = 12
# Event types (preset)
event_types: list[str] = [
"service",
"fuel",
"tyre",
"chain",
"brake",
"repair",
"mot",
"insurance",
"other",
]
model_config = SettingsConfigDict(env_prefix="BIKE_ADMIN_", env_file=".env", extra="ignore")
@property
def resolved_db_path(self) -> Path:
return self.db_path or (self.data_dir / "bike_admin.db")
@lru_cache
def get_settings() -> Settings:
return Settings()