refactor(settings): remove the preview-feature opt-ins

The per-account preview switch was kept for the topic overview pages,
which were dropped before they shipped. Its one flag was stored, served
and backed up, and read by nothing; the column-reader audit listed it as
a pending consumer that will not come.

Removed completely:

- `/api/settings/preview-features` (GET, PATCH) is retired: it answers
  410 Gone with `meta.errorCode: route.retired` and `removedIn: 1.46.0`,
  and the contract publishes it under Retired. The route, its validation
  schema, the `PreviewFeatures` OpenAPI schemas and the settings module
  are deleted.
- Migration 0485 drops `users.preview_features_json` under a bounded lock
  wait, with the retry marker.
- The backup no longer writes the field. A file from v1.44 or v1.45 that
  carries it still restores: the schema accepts it and no codec reads it,
  so nothing is refused or written for it. The backup-parity goldens
  lose the field and apply one setting fewer.
- The data-wipe plan entry and the sharing-surface actor entry go with
  the route (frozen count 273 -> 272).

No client build reads the route: neither iOS repository nor any local
checkout references it.
This commit is contained in:
Marc-André Bombeck committed 2026-10-25 00:44:15 +02:00
1 parent f3b9329fb2
commit 2ae23f4ca8
26 files changed
+125 -437

No files matched your search

@@ -111,6 +111,21 @@ describe("admitAccountSettings", () => {
expect(admitAccountSettings({}, ctx)).toEqual({ data: {}, refused: [] });
});
it("accepts and ignores the retired preview-feature opt-ins of an older file", async () => {
// Written by v1.44 and v1.45, whose column v1.46 dropped. The file must
// still restore, so the field is neither refused nor written.
const { accountSettingsBackupSchema } =
await import("@/lib/export/account-settings-backup-schema");
const entry = accountSettingsBackupSchema.parse({
timezone: "Europe/Berlin",
previewFeaturesJson: { topics: true },
});
expect(admitAccountSettings(entry, ctx)).toEqual({
data: { timezone: "Europe/Berlin" },
refused: [],
});
});
it("refuses a language, unit or time zone this release does not know", () => {
const { data, refused } = admitAccountSettings(
{
@@ -66,6 +66,9 @@ export const accountSettingsBackupSchema = z
moodTagLayoutJson: z.unknown().optional(),
documentsLayoutJson: z.unknown().optional(),
moduleListLayoutJson: z.unknown().optional(),
// Retired in v1.46.0 with its column (the preview-feature opt-ins). A file
// written by v1.44 or v1.45 still carries it; it is accepted and ignored,
// because no codec reads it, so such a file restores everything else.
previewFeaturesJson: z.unknown().optional(),
activityGoalsJson: z.unknown().optional(),
reportSelectionJson: z.unknown().optional(),
@@ -539,7 +539,6 @@ const ACCOUNT_SETTING_CODECS = {
moodTagLayoutJson: json("moodTagLayoutJson"),
documentsLayoutJson: json("documentsLayoutJson"),
moduleListLayoutJson: json("moduleListLayoutJson"),
previewFeaturesJson: json("previewFeaturesJson"),
activityGoalsJson: activityGoals,
reportSelectionJson: json("reportSelectionJson"),
globalExcludedInjectionSites: excludedSites,