rsvp_resource_policy: per-resource booking policy, access control, and lead time

Submitted by admin on
Status
Priority
High

Context

ADR-0037 (2026-05-24). Resources need configurable booking policy, per-node access control (view and booking), and lead time enforcement. Supersedes the "Resource reservation role gating" backlog card (field_required_position_roles design).

D7 equivalent: Content Access module for per-node role restrictions. This is the D11 pattern using five fields on rsvp_resource + node access system + validation constraints.

Decided

  • Sub-module: rsvp_resource_policy — fields, constraints, and node access realm all in one sub-module
  • Anonymous view: login always required to view any rsvp_resource node. field_view_roles gates authenticated users only; anonymous → redirect to login via hook_node_access() on the bundle
  • Bypass + lead time: bypass-eligible users are exempt from lead time enforcement. Coordinators can make same-day bookings on Restricted resources

Five fields to add to rsvp_resource

FieldTypeNotes field_booking_policylist_stringopen | moderated | restricted — default: moderated field_request_lead_timeintegerBusiness days; only used when policy = restricted field_bypass_rolesentity_reference (user_role, unlimited)Roles that auto-confirm regardless of policy. Empty = coordinator+ default (ADR-0029) field_required_booking_rolesentity_reference (user_role, unlimited)Roles eligible to book. Empty = any community member field_view_rolesentity_reference (user_role, unlimited)Roles that can view the resource. Empty = any authenticated user

Decision tree on reservation create

  1. View access: authenticated AND (field_view_roles empty OR user holds a listed role) → else 403
  2. Booking access: field_required_booking_roles empty OR user holds a listed role → else 403
  3. Conflict check: ReservationConflict constraint (always runs)
  4. Bypass check: user holds a field_bypass_roles role (or coordinator+ if field is empty) → auto-confirm, skip lead time
  5. Lead time check: ReservationLeadTime constraint (only if policy = restricted AND user is not bypass-eligible)
  6. Policy = open → auto-confirm
  7. Policy = moderated or restricted → tentative → coordinator queue

Code to write

  • ReservationLeadTime validation constraint in rsvp_system_module/src/Plugin/Validation/Constraint/ — sibling of ReservationConflict. Checks business-day lead time; bypass-eligible users exempt
  • Update hook_node_presave in rsvp_reservation_widget.module to read field_bypass_roles from the resource (falling back to coordinator+ when empty)
  • hook_node_access() in rsvp_resource_policy sub-module: anonymous → always deny view on rsvp_resource bundle; authenticated + field_view_roles → role check
  • Access check for booking eligibility (field_required_booking_roles) before reservation form renders

Recipe: rsvp_resource_policy

  • New recipe in rsvp-recipes/recipes/rsvp_resource_policy/
  • Depends on rsvp_resources base recipe
  • Adds all five field storage + instance configs to rsvp_resource
  • Form display: policy field group, lead time shown conditionally via #states API
  • Not included in rsvp_full_stack — opt-in

Related

  • ADR-0037 — Full design and decision rationale
  • ADR-0017 — rsvp_reservation architecture, ReservationConflict pattern
  • ADR-0029 — Coordinator bypass (platform default preserved when field_bypass_roles is empty)