Fas 1a punkt 2: release_gates tabell + go/no-go-vy
This commit is contained in:
@@ -17,3 +17,4 @@ export * from "./seasons.js";
|
||||
export * from "./subscriptions.js";
|
||||
export * from "./analytics.js";
|
||||
export * from "./platform.js";
|
||||
export * from "./releaseGates.js";
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Release gates schema (spec §17).
|
||||
* Configurable go/no-go criteria evaluated against analytics events.
|
||||
*/
|
||||
import { boolean, doublePrecision, index, integer, pgEnum, pgTable, text, timestamp, uuid, varchar } from "drizzle-orm/pg-core";
|
||||
import { createdAt, updatedAt } from "./_shared.js";
|
||||
import {
|
||||
RELEASE_GATE_CATEGORIES,
|
||||
RELEASE_GATE_COMPARISONS,
|
||||
RELEASE_GATE_STATUSES,
|
||||
tuple,
|
||||
} from "@app/shared-types";
|
||||
|
||||
export const releaseGateCategoryEnum = pgEnum(
|
||||
"release_gate_category",
|
||||
tuple(RELEASE_GATE_CATEGORIES),
|
||||
);
|
||||
export const releaseGateComparisonEnum = pgEnum(
|
||||
"release_gate_comparison",
|
||||
tuple(RELEASE_GATE_COMPARISONS),
|
||||
);
|
||||
export const releaseGateStatusEnum = pgEnum(
|
||||
"release_gate_status",
|
||||
tuple(RELEASE_GATE_STATUSES),
|
||||
);
|
||||
|
||||
export const releaseGates = pgTable(
|
||||
"release_gates",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
gateKey: varchar("gate_key", { length: 64 }).notNull().unique(),
|
||||
category: releaseGateCategoryEnum("category").notNull(),
|
||||
nameSv: text("name_sv").notNull(),
|
||||
nameEn: text("name_en").notNull(),
|
||||
descriptionSv: text("description_sv"),
|
||||
descriptionEn: text("description_en"),
|
||||
/** Target threshold (0–1 for ratios, absolute count for counts). */
|
||||
targetValue: doublePrecision("target_value").notNull(),
|
||||
comparison: releaseGateComparisonEnum("comparison").notNull(),
|
||||
/** How many days of analytics events to include in the evaluation. */
|
||||
evaluationWindowDays: integer("evaluation_window_days").notNull().default(7),
|
||||
/** Latest computed value, if any. */
|
||||
lastValue: doublePrecision("last_value"),
|
||||
lastEvaluatedAt: timestamp("last_evaluated_at", { withTimezone: true }),
|
||||
status: releaseGateStatusEnum("status").notNull().default("pending"),
|
||||
/** True if this gate blocks a broad launch until passed. */
|
||||
blocking: boolean("blocking").notNull().default(false),
|
||||
/** Free-form admin notes (e.g., why a gate was waived). */
|
||||
notes: text("notes"),
|
||||
createdAt: createdAt(),
|
||||
updatedAt: updatedAt(),
|
||||
},
|
||||
(t) => [
|
||||
index("release_gates_category_idx").on(t.category),
|
||||
index("release_gates_status_idx").on(t.status),
|
||||
],
|
||||
);
|
||||
Reference in New Issue
Block a user