OptionalcustomerId?: stringExternal id; required when type='CUSTOMER'.
Optionaldescription?: stringOptionaleffectiveFrom?: InstantWhen this version becomes effective. Defaults to now() at the DB
layer when omitted. Pass a future Temporal.Instant to schedule a
change (e.g. Reg E 30-day notice).
Optionallabel?: stringOptionalmatcher?: MatcherOptionaltype?: "ADMIN" | "CUSTOMER"
Admin-tier CRUD over
product_activation_rule. Accepts any rule type (admin-global, admin-for-customer, or customer).Identity / version split:
product_activation_ruleholds scope columns(routeId, customerId, type)plus acurrentVersionIdpointer; every mutable field (matcher, status, priority, value, label, description) lives onproduct_activation_rule_versionand is append-only. Editing means inserting a new version row and re-pointingcurrentVersionIdin one transaction.Duplicate-matcher detection (no two non-deleted rules in the same scope with the same JCS-canonical matcher) is enforced by the partial unique index
product_activation_rule_unique_tupleon(route_id, customer_id, type, matcher_hash) NULLS NOT DISTINCT WHERE deleted_at IS NULL.matcherHashis denormalized onto the identity row so the index can live there; service code maintains identity.matcherHash = currentVersion.matcherHash on every version bump and translates the resulting unique-violation back intoDUPLICATE_MATCHER.