The Jellyfin DisplayPreferences blobs rode the legacy user_settings key/value table under synthetic jellycompat:* keys, which forced the legacy settings API to carry a prefix carve-out in its otherwise-closed unknown-key gate. They are the compat subsystem's storage, not user settings: the contract neither validates nor resolves them. Move them to a dedicated jellycompat_displayprefs table in both backends, keyed by (prefs id, client) per user, with the blob stored as opaque text served back byte-for-byte (deliberately not jsonb, which would re-serialize it). The data-copy migrations — per-user SQLite V16 and a paired SQL + Go goose migration for Postgres — are transactional and harmless to re-run, and both drive their key parsing and row classification from the new internal/jellycompat/displayprefs package so the backends cannot diverge, following the internal/settingsmigrate precedent. A jellycompat:* row that does not parse as a DisplayPrefs key (only ever writable through the removed carve-out) is recorded in user_setting_migration_rejects rather than silently deleted. With the last non-settings tenant gone, the jellycompatSettingPrefix carve-out is deleted: the legacy settings endpoints now refuse jellycompat:* keys like any other unknown key and never surface them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
38 lines
1.6 KiB
SQL
38 lines
1.6 KiB
SQL
-- Dedicated home for Jellyfin DisplayPreferences blobs, which used to ride
|
|
-- user_settings under synthetic jellycompat:* keys. They are the jellycompat
|
|
-- subsystem's storage rather than user settings — the settings contract
|
|
-- neither validates nor resolves them — so rehoming them removes the last
|
|
-- non-settings tenant of the legacy key/value table and lets the legacy
|
|
-- settings API drop its jellycompat carve-out.
|
|
--
|
|
-- value is text, not jsonb, deliberately: the blob is opaque Jellyfin client
|
|
-- JSON served back byte-for-byte, and jsonb would re-serialize it (reordering
|
|
-- keys, normalizing numbers). This table stores what the client sent; it does
|
|
-- not interpret it. The per-user SQLite store carries the same table with
|
|
-- user_id omitted.
|
|
--
|
|
-- The data copy out of user_settings is the companion Go migration
|
|
-- (jellycompat_displayprefs_move in internal/database): the key parsing is
|
|
-- shared with the SQLite backend through internal/jellycompat/displayprefs,
|
|
-- which SQL cannot express without duplicating those rules.
|
|
|
|
-- +goose Up
|
|
-- +goose StatementBegin
|
|
CREATE TABLE public.jellycompat_displayprefs (
|
|
user_id integer NOT NULL,
|
|
prefs_id text NOT NULL,
|
|
client text NOT NULL,
|
|
value text NOT NULL,
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
CONSTRAINT jellycompat_displayprefs_pkey
|
|
PRIMARY KEY (user_id, prefs_id, client),
|
|
CONSTRAINT jellycompat_displayprefs_user_id_fkey
|
|
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
|
|
);
|
|
-- +goose StatementEnd
|
|
|
|
-- +goose Down
|
|
-- +goose StatementBegin
|
|
DROP TABLE IF EXISTS public.jellycompat_displayprefs;
|
|
-- +goose StatementEnd
|