Skip to content

Catalog

Purpose

The largest context (12 entities). The Activity is the aggregate root: a bookable offering — show, movie, gym class, service — published by a company.

Around it sit:

Boundaries

  • In: everything needed to describe what’s bookable and where/when.
  • Out:
    • The reservation itself is in Bookings — a Booking points back at a Session here.
    • Pass entitlements that cover an activity are in Passespass_entitlement_template.activity_id references back here.
    • The actor: bookings are made by Company customer, not a raw User.

Entities

IDEntityRole
ENT-005ActivityThe bookable offering — aggregate root
ENT-012SessionA concrete occurrence at a date+time — what customers book
ENT-013Time slotRecurrence rule that materialises sessions
ENT-009CategoryTaxonomy node, company-scoped or platform-wide
ENT-010ContributorCompany-member credited on an activity (multi-role)
ENT-011LocationPhysical venue — embedded only, no top-level resource
ENT-014Time slot attendeeCustomer expected at a slot occurrence (post-fact billable)
ENT-015User activity favoritePer-user pin on an activity
ENT-006Activity extraAdd-on bought with a booking (towel, equipment, etc.)
ENT-007Activity linkExternal link from an activity (trailer, webpage)
ENT-008Activity partnerCo-presenter / co-organiser on the activity
ENT-043Contributor reviewClient’s 1–5 star rating for a contributor, gated on a confirmed booking

Backend implementation

  • Module: libs/features/activities/ — single feature lib covering all 11 entities.
  • Surface routing: activities-client.module.ts, activities-admin.module.ts. No super-admin surface.
  • Drizzle schema: libs/shared/data-access-db/src/lib/schema/activities.schema.ts (pgSchema('activities')).

Cross-context relationships

  • This context owns the activities.* Postgres schema (minus spheres and audit log, which logically belong to Spheres even though they share the file).
  • This context references:
    • Spheres via activity.sphere_id (FK, intra-schema, NOT NULL).
    • Companies via activity.company_id, location.company_id, category.company_id — cross-schema, no FK (see ADR).
    • Companies via contributor.member_idcompany_member (cross-schema, no FK; ADR applies).
    • Identity via user_activity_favorite.user_id.
    • Identity via contributor_review.target_user_id and contributor_review.reviewer_user_id (cross-schema soft refs, no FK; ADR applies).
    • Bookings via contributor_review.booking_id (cross-schema soft ref, no FK; ADR applies).
  • This context is referenced by:
    • Bookings via booking.session_id (the session) and booking.customer_id (customer).
    • Passes via pass_entitlement_template.activity_id.

Open questions

  • OPEN (assertion to add): when an activity is linked to a category, the service must check category.companyId IS NULL OR category.companyId = activity.companyId — currently nothing enforces this. See Activity Known gotchas.
  • Bookings’ feature library is co-located here (no separate libs/features/bookings/) — see Bookings.