Skip to content

Recurrence

The core stores concrete, dated slots. Recurrence - repeating availability ("every Tuesday 10:00-11:00") - is an optional layer that materializes those concrete slots. It will ship separately, as yoyaku_recur, and this page is the design it will be built to; nothing of it exists yet.

Why materialize rather than store a rule

Bookings attach to concrete slots, and the BookingManager is oblivious to a slot's origin. So recurrence adds cleanly: what it needs on the slot is one nullable string naming the rule a slot came from, and a submodule adds a base field of its own without the engine knowing.

flowchart LR
    RULE[RecurrenceRule<br/>yoyaku_recur] -->|generator + cron| GEN[Materialize slots]
    GEN --> S1[Slot 2026-07-07]
    GEN --> S2[Slot 2026-07-14]
    GEN --> S3[Slot 2026-07-21]
    S1 --> C1[tariffs + bookings]
    S2 --> C2[tariffs + bookings]
    Note[slot names its rule] -.-> S1

Bonus of materializing versus storing a pure RRULE:

  • Per-occurrence overrides are trivial - skip a date or bump one day's capacity by editing that single slot.
  • Open-ended recurrence is handled by a rolling-horizon cron that keeps a window of future slots materialized (the Smart Date Recur approach). The engine only ever sees concrete slots.

What yoyaku_recur will add

  • A RecurrenceRule entity (RRULE + a default tariff template + horizon).
  • A generator service + cron that creates/updates slots and stamps each one with the id of the rule it came from.
  • A policy for already-booked generated slots when a rule changes - the one decision recurrence defers, and it lives entirely in the submodule.

Nothing is reserved for it

The engine stores nothing on a slot on this layer's behalf. A field that only the generator writes and only the generator reads belongs to the generator, and the submodule adds it when it is built.