Skip to content

Design release and scheduled publication model #314

@juliuskrah

Description

@juliuskrah

Problem

GITSTORE_ADMISSION_CONTROL__BRANCH_PATTERN should remain a narrow gate for which branch state is admitted into the catalog datastore. Broadening it to include release branches or tags risks correctness issues because the current datastore identity model is resource-oriented, not branch- or tag-scoped.

At the same time, GitStore needs a first-class way to support workflows such as:

  • products or variants that are drafted in Git but not yet publicly visible
  • release tags that promote a known commit from draft/candidate state to published state
  • scheduled campaigns such as Black Friday where products, variants, or prices become active during a defined window
  • storefront/public GraphQL queries that only expose resources that are ready, published, and active for the request time

Current Context

  • Branch admission is controlled by GITSTORE_ADMISSION_CONTROL__BRANCH_PATTERN.
  • Current safe policy is a single anchored branch such as ^refs/heads/main$.
  • Product/ProductVariant status already has condition concepts such as AdmissionAccepted, Published, Ready, ProductResolved, OptionsAccepted, and PricingAccepted.
  • ProductVariant pricing already supports scheduled price entries through validFromTime and validUntilTime.
  • Release-tag notification has been mentioned as related work, but release/publish semantics are not yet modeled as a separate catalog lifecycle layer. [Initiative] Git Event Publication and Admission Integration #169

Proposed Direction

Separate admission from publication:

  • Admission answers: "Is this valid catalog state that may be stored?"
  • Publication answers: "Is this stored state visible or active for a given audience and time?"

Keep normal catalog admission scoped to an authoritative branch, for example:

^refs/heads/main$

Do not treat tags as another normal admitted catalog ref. Instead, a tag should trigger a release/publish workflow that references a specific commit SHA already reachable from the admitted branch.

Candidate Model

Introduce a release/publication concept, for example a Git-backed Release resource or an API-created release record:

apiVersion: catalog.gitstore.dev/v1beta1
kind: CatalogRelease
metadata:
  name: black-friday-2026
spec:
  ref: refs/tags/v2026.11.27
  effectiveFrom: "2026-11-27T00:00:00Z" # Future date means schedule, otherwise immediate
  effectiveUntil: "2026-11-30T23:59:59Z"
  selector: # When omitted then apply to all eligible Resources reachable from metadata.revision
    matchLabels:
      campaign: black-friday

The release controller would:

  • Create the tag (Can also be created via regular git CLI)
    • When effectiveFrom is nil or in the past, tag is created immediately
    • When effectiveFrom is in the future, tag creation is scheduled
  • resolve the tag to a commit SHA.
  • verify the commit is reachable from the configured admitted branch
  • select candidate resources by explicit refs, labels, paths, or another well-defined selector
  • set or materialize publication state, such as Published=True
  • avoid overwriting normal admitted resource state with tag-specific state
  • expose release status and diagnostics when a tag is invalid, stale, or points outside the trusted branch

This is runtime behavior and should be split into a separate issue.

Scheduled Pricing

For ProductVariant pricing, reuse the existing PriceTemplate fields:

  • validFromTime
  • validUntilTime
  • priority
  • eligibility.constraints

The pricing resolver should select the active eligible price for the request time. This allows a variant to carry both normal pricing and Black Friday pricing without requiring a second admitted branch.

Open Design Questions

  • Should releases be Git-backed resources, API-created records, or both?
  • Should a release publish resources by label selector, explicit resource references, changed paths, or full commit snapshot?
  • Should publication state live on each resource status, in a separate materialized public view, or both?
  • How should public GraphQL distinguish draft/candidate reads from storefront reads? [Initiative] Pluggable Identity and Access Contract (AuthN/AuthZ/UserDir) #225
  • What is the exact safety rule for tags: must the tag target be reachable from main, or from the current configured admission branch pattern?
  • Should release tags be annotated-only, signed, or otherwise restricted?
  • How should scheduled publication interact with scheduled pricing windows?

Acceptance Criteria

  • A documented release/publication lifecycle exists and is distinct from branch admission.
  • Normal branch admission remains safe with a single anchored branch pattern.
  • Tags do not enter the datastore as competing branch-like catalog admissions.
  • A release tag can promote a known commit to published state without allowing arbitrary branch overwrite/delete side effects.
  • Storefront/public GraphQL are authorization gated out on unpublished, not-ready, or not-yet-active resources.
  • ProductVariant scheduled pricing can be evaluated using validFromTime, validUntilTime, priority, and eligibility rules.
  • Tests cover draft resource admission, release promotion, invalid tag target, scheduled activation, and scheduled expiration.

Metadata

Metadata

Assignees

No one assigned
    No fields configured for Feature.

    Projects

    Status
    Todo

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions