From 1f60b821050e17505f61369f1f64a13025c6b409 Mon Sep 17 00:00:00 2001 From: Simon Byford Date: Thu, 30 Jul 2026 12:01:42 +0100 Subject: [PATCH 1/2] Add A/B test model --- dotcom-rendering/src/frontend/feFront.ts | 2 ++ dotcom-rendering/src/types/front.ts | 25 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/dotcom-rendering/src/frontend/feFront.ts b/dotcom-rendering/src/frontend/feFront.ts index edcf604da20..61e411e46ee 100644 --- a/dotcom-rendering/src/frontend/feFront.ts +++ b/dotcom-rendering/src/frontend/feFront.ts @@ -9,6 +9,7 @@ import type { StarRating, } from '../types/content'; import type { FooterType } from '../types/footer'; +import type { Test } from '../types/front'; import type { FENavType } from '../types/frontend'; import type { FETagType } from '../types/tag'; import type { Territory } from '../types/territory'; @@ -205,6 +206,7 @@ export type FEFrontCard = { href?: string; embedUri?: string; newsletterData?: Newsletter; + tests?: Test[]; }; header: { isVideo: boolean; diff --git a/dotcom-rendering/src/types/front.ts b/dotcom-rendering/src/types/front.ts index d1763598525..6fc6bba2350 100644 --- a/dotcom-rendering/src/types/front.ts +++ b/dotcom-rendering/src/types/front.ts @@ -170,3 +170,28 @@ export type TreatType = { */ pageId?: string; }; + +enum VariantId { + A, + B, +} + +export type VariantMeta = { + id: VariantId; + meta: { + [key: string]: unknown; + }; +}; + +export type Test = { + testUuid: string; + variantMeta: VariantMeta[]; + createdByName: string; + createdByEmail: string; + startDate?: number; + expiryDate?: number; + frontsThisTestCanRunOn: string[]; + hasManuallyEndedOnThisTrail: boolean; + manuallyEndedOnThisTrailByName?: string; + manuallyEndedOnThisTrailByEmail?: string; +}; From 4204395d066e9664525ceefeb36a675d6dc16b94 Mon Sep 17 00:00:00 2001 From: Simon Byford Date: Thu, 30 Jul 2026 12:06:44 +0100 Subject: [PATCH 2/2] `make gen-schemas` --- .../src/frontend/schemas/feFront.json | 202 ++++++++++++++++++ .../src/frontend/schemas/feTagPage.json | 72 +++++++ 2 files changed, 274 insertions(+) diff --git a/dotcom-rendering/src/frontend/schemas/feFront.json b/dotcom-rendering/src/frontend/schemas/feFront.json index 08703e95381..838de79b39b 100644 --- a/dotcom-rendering/src/frontend/schemas/feFront.json +++ b/dotcom-rendering/src/frontend/schemas/feFront.json @@ -634,6 +634,71 @@ "successDescription", "theme" ] + }, + "tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "testUuid": { + "type": "string" + }, + "variantMeta": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/VariantId" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "id", + "meta" + ] + } + }, + "createdByName": { + "type": "string" + }, + "createdByEmail": { + "type": "string" + }, + "startDate": { + "type": "number" + }, + "expiryDate": { + "type": "number" + }, + "frontsThisTestCanRunOn": { + "type": "array", + "items": { + "type": "string" + } + }, + "hasManuallyEndedOnThisTrail": { + "type": "boolean" + }, + "manuallyEndedOnThisTrailByName": { + "type": "string" + }, + "manuallyEndedOnThisTrailByEmail": { + "type": "string" + } + }, + "required": [ + "createdByEmail", + "createdByName", + "frontsThisTestCanRunOn", + "hasManuallyEndedOnThisTrail", + "testUuid", + "variantMeta" + ] + } } }, "required": [ @@ -1469,6 +1534,71 @@ "successDescription", "theme" ] + }, + "tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "testUuid": { + "type": "string" + }, + "variantMeta": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/VariantId" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "id", + "meta" + ] + } + }, + "createdByName": { + "type": "string" + }, + "createdByEmail": { + "type": "string" + }, + "startDate": { + "type": "number" + }, + "expiryDate": { + "type": "number" + }, + "frontsThisTestCanRunOn": { + "type": "array", + "items": { + "type": "string" + } + }, + "hasManuallyEndedOnThisTrail": { + "type": "boolean" + }, + "manuallyEndedOnThisTrailByName": { + "type": "string" + }, + "manuallyEndedOnThisTrailByEmail": { + "type": "string" + } + }, + "required": [ + "createdByEmail", + "createdByName", + "frontsThisTestCanRunOn", + "hasManuallyEndedOnThisTrail", + "testUuid", + "variantMeta" + ] + } } }, "required": [ @@ -2304,6 +2434,71 @@ "successDescription", "theme" ] + }, + "tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "testUuid": { + "type": "string" + }, + "variantMeta": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/VariantId" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "id", + "meta" + ] + } + }, + "createdByName": { + "type": "string" + }, + "createdByEmail": { + "type": "string" + }, + "startDate": { + "type": "number" + }, + "expiryDate": { + "type": "number" + }, + "frontsThisTestCanRunOn": { + "type": "array", + "items": { + "type": "string" + } + }, + "hasManuallyEndedOnThisTrail": { + "type": "boolean" + }, + "manuallyEndedOnThisTrailByName": { + "type": "string" + }, + "manuallyEndedOnThisTrailByEmail": { + "type": "string" + } + }, + "required": [ + "createdByEmail", + "createdByName", + "frontsThisTestCanRunOn", + "hasManuallyEndedOnThisTrail", + "testUuid", + "variantMeta" + ] + } } }, "required": [ @@ -3201,6 +3396,13 @@ "url" ] }, + "VariantId": { + "type": "number", + "enum": [ + 0, + 1 + ] + }, "FEFrontCardStyle": { "enum": [ "Analysis", diff --git a/dotcom-rendering/src/frontend/schemas/feTagPage.json b/dotcom-rendering/src/frontend/schemas/feTagPage.json index b1e8e5a3b35..72982590de6 100644 --- a/dotcom-rendering/src/frontend/schemas/feTagPage.json +++ b/dotcom-rendering/src/frontend/schemas/feTagPage.json @@ -477,6 +477,71 @@ "successDescription", "theme" ] + }, + "tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "testUuid": { + "type": "string" + }, + "variantMeta": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/VariantId" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "id", + "meta" + ] + } + }, + "createdByName": { + "type": "string" + }, + "createdByEmail": { + "type": "string" + }, + "startDate": { + "type": "number" + }, + "expiryDate": { + "type": "number" + }, + "frontsThisTestCanRunOn": { + "type": "array", + "items": { + "type": "string" + } + }, + "hasManuallyEndedOnThisTrail": { + "type": "boolean" + }, + "manuallyEndedOnThisTrailByName": { + "type": "string" + }, + "manuallyEndedOnThisTrailByEmail": { + "type": "string" + } + }, + "required": [ + "createdByEmail", + "createdByName", + "frontsThisTestCanRunOn", + "hasManuallyEndedOnThisTrail", + "testUuid", + "variantMeta" + ] + } } }, "required": [ @@ -1429,6 +1494,13 @@ } ] }, + "VariantId": { + "type": "number", + "enum": [ + 0, + 1 + ] + }, "FEFrontCardStyle": { "enum": [ "Analysis",