@12-apps/prisma 6.5.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/prisma",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"description": "Prisma host: the multi-file schema folder, the plugin migration seam, and the shared PrismaClient singleton with its audit / append-only extensions",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@12-apps/audit": "^5.7.1",
|
|
71
71
|
"@12-apps/auth": "^2.19.0",
|
|
72
|
-
"@12-apps/discounts": "^1.
|
|
72
|
+
"@12-apps/discounts": "^1.13.0",
|
|
73
73
|
"@12-apps/entitlements": "^3.10.0",
|
|
74
74
|
"@12-apps/entity-lifecycle": "^4.13.0",
|
|
75
75
|
"@12-apps/eslint-config": "^1.22.0",
|
|
@@ -77,11 +77,11 @@
|
|
|
77
77
|
"@12-apps/i18n": "^1.3.0",
|
|
78
78
|
"@12-apps/jobs": "^4.5.0",
|
|
79
79
|
"@12-apps/mcp": "^3.16.0",
|
|
80
|
-
"@12-apps/notifications": "^4.
|
|
80
|
+
"@12-apps/notifications": "^4.9.0",
|
|
81
81
|
"@12-apps/onboarding": "^2.7.0",
|
|
82
|
-
"@12-apps/payments-backend": "^4.
|
|
82
|
+
"@12-apps/payments-backend": "^4.26.0",
|
|
83
83
|
"@12-apps/product-research": "^2.10.0",
|
|
84
|
-
"@12-apps/rbac": "^4.
|
|
84
|
+
"@12-apps/rbac": "^4.14.0",
|
|
85
85
|
"@12-apps/realtime": "^2.6.0",
|
|
86
86
|
"@12-apps/report-builder": "^5.14.0",
|
|
87
87
|
"@12-apps/shift": "^3.4.0",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- @12-apps/discounts: the WEEKLY schedule (FUT-996).
|
|
2
|
+
--
|
|
3
|
+
-- "Toda sexta, das 16:00 às 20:00" — a recurring window INSIDE the campaign
|
|
4
|
+
-- `[starts_at, ends_at)`, which until now was the only scheduling a rule had.
|
|
5
|
+
--
|
|
6
|
+
-- ── PURELY ADDITIVE, AND THAT IS THE POINT ────────────────────────────────
|
|
7
|
+
-- One nullable column, no backfill, no CHECK to widen, nothing dropped. NULL
|
|
8
|
+
-- means "always, within the campaign window", which is exactly what every
|
|
9
|
+
-- existing row already means — so this migration cannot change the price of
|
|
10
|
+
-- anything, and the release carrying it needs none of the expand/contract
|
|
11
|
+
-- ceremony a destructive DDL would (see the host's CLAUDE.md on why a
|
|
12
|
+
-- `DROP COLUMN` takes production down for the length of a healthcheck).
|
|
13
|
+
--
|
|
14
|
+
-- Replay-safe like its predecessor: `IF NOT EXISTS` throughout.
|
|
15
|
+
--
|
|
16
|
+
-- ── WHY JSON RATHER THAN A FOURTH TABLE ───────────────────────────────────
|
|
17
|
+
-- The recurrence is not SQL-queryable in any useful way. The admin grid's
|
|
18
|
+
-- vigência filter already punts on comparing two nullable timestamps against
|
|
19
|
+
-- `now()` and rides as a separate parameter the store resolves, so a schedule
|
|
20
|
+
-- table would buy queryability that nothing asks for — while adding a third
|
|
21
|
+
-- `include` to `loadDiscountRules`, which is on the storefront's hottest read
|
|
22
|
+
-- (a whole menu page's badge preview walks it once per request).
|
|
23
|
+
--
|
|
24
|
+
-- The trade is stated plainly: the database cannot check this column's SHAPE.
|
|
25
|
+
-- `assertSchedule` in `src/server/validate.ts` is the only gate in front of it,
|
|
26
|
+
-- and the evaluator is deliberately tolerant of a row that got past it — a
|
|
27
|
+
-- malformed window covers NOTHING rather than everything, so the failure mode
|
|
28
|
+
-- of a bad blob is a promotion that does not fire, never a cart priced at zero.
|
|
29
|
+
--
|
|
30
|
+
-- Shape, for a reader with only the database in front of them:
|
|
31
|
+
--
|
|
32
|
+
-- {"windows":[{"days":[4],"from":"16:00","to":"20:00"}]}
|
|
33
|
+
--
|
|
34
|
+
-- * `days` — Monday-first, 0..6. NOT `Date#getDay()`'s Sunday-first axis.
|
|
35
|
+
-- * `from`/`to` — "HH:MM", 24-hour, in the STORE's timezone, half-open
|
|
36
|
+
-- [from, to) exactly as [starts_at, ends_at) is.
|
|
37
|
+
-- * `to` < `from` means the window runs past midnight (a bar shutting at
|
|
38
|
+
-- 02:00), which is the most common happy hour there is.
|
|
39
|
+
|
|
40
|
+
ALTER TABLE "discounts" ADD COLUMN IF NOT EXISTS "schedule" JSONB;
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"20260821120000_shift_kind_host_vocabulary",
|
|
38
38
|
"20260821140000_discounts_package_owned",
|
|
39
39
|
"20260824120000_payments_pending_verification",
|
|
40
|
-
"20260826170000_locale_preferences"
|
|
40
|
+
"20260826170000_locale_preferences",
|
|
41
|
+
"20260830120000_discount_weekly_schedule"
|
|
41
42
|
]
|
|
42
43
|
}
|
|
@@ -79,6 +79,29 @@ model Discount {
|
|
|
79
79
|
// either side = open-ended.
|
|
80
80
|
startsAt DateTime? @map("starts_at")
|
|
81
81
|
endsAt DateTime? @map("ends_at")
|
|
82
|
+
// The WEEKLY schedule INSIDE that window (FUT-996) — "toda sexta, das 16:00
|
|
83
|
+
// às 20:00", "segunda e terça à tarde". NULL = always, within
|
|
84
|
+
// [starts_at, ends_at), which is what every row predating the feature means.
|
|
85
|
+
//
|
|
86
|
+
// {"windows":[{"days":[4],"from":"16:00","to":"20:00"}]}
|
|
87
|
+
//
|
|
88
|
+
// `days` is Monday-first 0..6 — the axis every hours surface uses, and NOT
|
|
89
|
+
// `Date#getDay()`'s Sunday-first one. `from`/`to` are "HH:MM" in the STORE's
|
|
90
|
+
// timezone, half-open [from, to) exactly as the campaign window is, and a
|
|
91
|
+
// `to` earlier than `from` runs past midnight rather than being invalid.
|
|
92
|
+
//
|
|
93
|
+
// JSON rather than a fourth table because the recurrence is not usefully
|
|
94
|
+
// SQL-queryable (the grid's vigência filter already cannot express the
|
|
95
|
+
// campaign window either), and a fourth table would put a third `include` on
|
|
96
|
+
// the storefront's hottest read. The cost is that the DATABASE cannot check
|
|
97
|
+
// this shape: `assertSchedule` is the only gate, and the evaluator treats a
|
|
98
|
+
// malformed window as covering NOTHING, so a bad blob is a promotion that
|
|
99
|
+
// does not fire rather than a cart priced wrong.
|
|
100
|
+
//
|
|
101
|
+
// A recurring window is a WALL-CLOCK fact, so it is only meaningful against
|
|
102
|
+
// the store's own timezone. The engine never reads one: a host resolves the
|
|
103
|
+
// instant into a weekday and a minute-of-day and passes those in.
|
|
104
|
+
schedule Json? @map("schedule")
|
|
82
105
|
// Minimum PRE-DISCOUNT cart subtotal, in cents. Always compared against the
|
|
83
106
|
// untouched subtotal, never a running total — which is what makes the result
|
|
84
107
|
// independent of the order the discounts are applied in.
|