Files
cgalo5758 efe3f1528d Restrict member surfaces to published products
Add lifecycle_status = 'published' to the public-catalog queries
(plans and add-ons listings) and reject checkout before any Stripe
call unless the product behind the price clears the shared member
gate (published + active + public). The currently-enrolled ladder
rung stays renderable even if its product is later drafted or
retired, fetched directly so members keep seeing what they are on.

Introduce a single evaluateMemberGate definition shared by the
catalog paths and the operator readiness panel so the surfaces
cannot disagree about what is publishable for members.
2026-08-22 12:58:05 -05:00

3.3 KiB

webhook-partition-maintenance Specification

Purpose

Keep the monthly RANGE partitions of core.webhook_events — the inbound event store shared by the Stripe and Discourse webhook receivers — provisioned ahead of need, so webhook ingestion never fails for lack of a partition. The baseline migration creates only the current and next two monthly partitions; this capability is the "application boot or a scheduler" creator that migration's contract promises.

Requirements

Requirement: Webhook event partitions are provisioned ahead of need

The system SHALL provide an idempotent ensure operation that creates monthly RANGE partitions of core.webhook_events (named core.webhook_events_YYYY_MM, month-start to next-month-start bounds in UTC) covering the current month plus at least the next three months. Running the operation when partitions already exist SHALL be a no-op (CREATE TABLE IF NOT EXISTS). The operation SHALL execute under a database role that holds CREATE on schema core; if the application's runtime role lacks that privilege, a migration SHALL grant it.

Scenario: Missing future partitions are created

  • WHEN the ensure operation runs in a month whose next three monthly partitions do not all exist
  • THEN the missing partitions are created with correct month boundaries
  • AND webhook inserts timestamped in any of those months succeed

Scenario: Ensure is idempotent

  • WHEN the ensure operation runs twice in succession
  • THEN the second run completes without error and creates nothing

Requirement: Boot pass ensures partitions without Temporal

The application boot sequence SHALL run the ensure operation before serving traffic, independent of whether Temporal is configured. A boot-pass failure SHALL be logged at warning level or higher and SHALL NOT abort startup.

Scenario: Temporal-less deployment stays covered across restarts

  • WHEN a deployment with no Temporal configuration restarts in a month for which no partition exists beyond the migration's initial three
  • THEN the boot pass creates the current and upcoming partitions and webhook ingestion continues to work

Scenario: Boot pass failure does not block startup

  • WHEN the ensure operation fails at boot (for example, a transient database error)
  • THEN the application logs the failure and continues starting up

Requirement: Recurring Temporal schedule keeps partitions extended

When Temporal is configured, the application SHALL register (create-or-update, describe-then-update) a recurring schedule that runs the ensure operation, with the interval configurable via a startup knob defaulting to 24 hours, and SHALL trigger one run immediately on registration. Schedule-spawned runs SHALL be resolvable through the schedule handle (schedule-spawned workflow IDs carry a timestamp suffix).

Scenario: Long-running deployment never exhausts partitions

  • WHEN a deployment runs without restart for longer than the partition lookahead window
  • THEN the scheduled ensure runs keep partitions created ahead of the current month
  • AND no webhook insert ever fails for lack of a partition

Scenario: Schedule registration is idempotent across restarts

  • WHEN the application boots repeatedly with Temporal configured
  • THEN the schedule is created once and subsequently updated in place, not duplicated