From 91763f4bf410a35e19c03bbbca7851d47e8387d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Tue, 18 Aug 2026 02:23:31 +0000 Subject: [PATCH] kiosk: builds record when the profile expires ios provisioning profiles last a year and the app stops launching when one expires - it does not degrade, it refuses to start. that date drives the re-sign queue and the reminder, and per BUSINESS-MODEL.md the annual re-sign is the product rather than an upsell. free to add today, a migration after the first publish. --- db/schema.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/db/schema.ts b/db/schema.ts index 7848e07..69ede39 100644 --- a/db/schema.ts +++ b/db/schema.ts @@ -88,6 +88,18 @@ export const kioskBuilds = pgTable( /** Survives retention. Replaces the `.keep` file the standalone service used. */ pinned: boolean('pinned').notNull().default(false), builtAt: timestamp('built_at', { withTimezone: true }).notNull(), + /** + * When this build's provisioning profile expires — the date the app STOPS LAUNCHING. + * + * iOS profiles are valid for a year, and on expiry the app does not degrade, it refuses to start. + * Every installed copy needs re-signing before then, which is why the commercial shape is a + * subscription rather than a one-off: the annual re-sign IS the product (BUSINESS-MODEL.md §6). + * + * So this is the most operationally important date in the table — it drives "which builds go dark + * this month", the reminder, and the re-sign queue. Nullable because an unsigned or debug build has + * no profile and therefore no expiry. + */ + profileExpiresAt: timestamp('profile_expires_at', { withTimezone: true }), publishedAt: timestamp('published_at', { withTimezone: true }).notNull().defaultNow(), }, (table) => [