Skip to content

Passes

Purpose

A pass is a pre-paid product a company sells to its customers: “10 yoga sessions valid 30 days”, “monthly unlimited”, “a 5-class punch card with a free towel”. A customer who buys one gets entitlements that the booking layer consumes — instead of paying-per-booking, the booking debits one entry from a covering pass.

The context has two tiers:

The customer tier is snapshotted at purchase from the template tier — later edits to the template don’t retroactively change what customers already have.

Boundaries

  • In: pass templates, price tiers, customer-held passes and their per-activity counters.
  • Out:
    • The booking that consumes an entitlement is in Bookings (booking.customer_entitlement_id).
    • Money for purchasing a pass goes through Payments (gateway-level) and Wallet (in-app balance).

Entities

IDEntityTierRole
ENT-029PassTemplateThe offer — name, validity, pricing config
ENT-031Pass entitlement templateTemplate”Activity X: N sessions” — one row per included activity
ENT-030Pass entitlement covered extraTemplateExtras included with each entitlement (e.g. a free towel)
ENT-032Pass priceTemplatePer-currency price tier of a pass
ENT-028Customer passCustomerA specific customer’s purchased instance — status, period, remaining
ENT-027Customer entitlementCustomer”This customer has K bookings left for activity X” — snapshot from template

Backend implementation

  • Module: libs/features/passes/
  • Surface routing: passes-client.module.ts (customer view of own passes) + passes-admin.module.ts (company manages templates, issues passes, adjusts).
  • Drizzle schema: libs/shared/data-access-db/src/lib/schema/passes.schema.ts (pgSchema('passes')).

Cross-context relationships

  • This context owns the passes.* Postgres schema.
  • This context references:
    • Catalog via pass_entitlement_template.activity_id (FK to activities.activities, cross-schema — allowed because RESTRICT-only and rare).
    • Companies via pass.company_id (no DB FK — cross-schema, see ADR).
    • Companies via customer_pass.customer_idcompany_customer.id (cross-schema).
  • This context is referenced by:
    • Bookingsbooking.customer_entitlement_id (ON DELETE SET NULL).

Open questions

  • The template/customer split means a pass redesign does not retroactively change existing customer instances. Validate that snapshot logic on edit is complete.
  • ON DELETE RESTRICT throughout the template-tier FK graph: a pass with active customer instances cannot be deleted, and an activity included in any entitlement template cannot be deleted.
  • OPEN: pass_entitlement_template (pass_id, activity_id) lacks UNIQUE at the DB level — see Pass entitlement template.