Public instance has no accounts, so all user state was GLOBAL in DB — new users saw/overwrote each other's (and Jan's) favorites, watched badges and blacklists (bug 2026-06-10). Add device_id (VARCHAR 64) to 9 state tables with composite PK (device_id, entity_id); app sends X-Device-Id header (get_device_id dep). All favorites/scene-favorites/blacklist/watch + scene&movie list/detail (is_favorite, watched, blacklist-hide) now filter by device. Existing rows backfilled to 'legacy-shared'; POST /me/adopt-legacy reassigns them to the caller once. Old clients (no header) map to legacy-shared so they keep working until OTA updates. Migration 0022: add col, backfill, composite PK. Verified on prod: 967 progress rows preserved, device isolation holds (new device sees none of legacy state). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
29 lines
1.3 KiB
Python
29 lines
1.3 KiB
Python
"""Per-device scoping stanu usera (favorites / play-progress / blacklisty).
|
|
|
|
Publiczna instancja Goon nie ma kont. Wcześniej cały stan usera był GLOBALNY w DB →
|
|
nowi użytkownicy widzieli/nadpisywali ulubione, watched-badge i blacklisty Jana
|
|
(bug 2026-06-08). Apka generuje raz UUID instalacji (SecureStore) i wysyła go w
|
|
nagłówku `X-Device-Id`; backend scope'uje wszystkie tabele stanu po `device_id`.
|
|
|
|
Stare wiersze (sprzed migracji) mają `device_id = LEGACY_DEVICE`. Klient bez nagłówka
|
|
(stara wersja apki przed OTA) trafia również na LEGACY_DEVICE — czyli dostaje dawną
|
|
współdzieloną pulę, dopóki nie zaktualizuje bundla. Endpoint `/me/adopt-legacy`
|
|
przepina LEGACY rows na konkretne device (Jan robi to raz po update).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import Header
|
|
|
|
# Sentinel dla wierszy sprzed device-scopingu + klientów bez nagłówka.
|
|
LEGACY_DEVICE = "legacy-shared"
|
|
|
|
|
|
def get_device_id(
|
|
x_device_id: Annotated[str | None, Header(alias="X-Device-Id")] = None,
|
|
) -> str:
|
|
"""Zwraca device_id z nagłówka `X-Device-Id` (przycięty do 64 znaków).
|
|
Brak/empty → LEGACY_DEVICE (kompat ze starymi klientami)."""
|
|
v = (x_device_id or "").strip()
|
|
return v[:64] if v else LEGACY_DEVICE
|