Seating Module Guide

Seating is the event-operations module that manages table planning and guest placement for Tov+.

5 min read

Purpose

Seating is the event-operations module that manages table planning and guest placement for Tov+.

It provides:

  • occasion-level installation through the module platform
  • event-level enablement for events that actually need seating
  • planner-managed seating plans, zones, tables, and assignments
  • guest-safe lookup of a guest's own published table or seat
  • vendor-safe read access for published plans when explicit permission exists

Seating is not a frontend-only layout helper. It is a real module with server-side validation, persistence artifacts, and permission-aware APIs.

Scope model

Seating is installed once per occasion and enabled per event.

That means:

  • the occasion installation owns the default module posture
  • each event enablement controls whether guest publication is allowed through publish_to_guests
  • every seating plan belongs to exactly one event
  • v1 supports one seating plan per event

The current install config uses table_naming_strategy.

The current event enablement config uses publish_to_guests.

Seating plan model

The module stores four seating-specific entity types:

  • seating_plans
  • seating_zones
  • seating_tables
  • seating_assignments

The generic module platform still owns:

  • occasion installation records
  • event enablement records
  • centralized permissions

Each seating plan stores:

  • occasion scope and event scope
  • module installation and enablement linkage
  • plan_key
  • display name
  • optional planner notes
  • lifecycle status
  • publication timestamps and publisher metadata

Statuses are:

  • draft
  • published

Table and seat model

The baseline model supports tables plus optional seat positions.

Current behavior:

  • tables are the core seating location
  • each table has a capacity
  • seat assignment is optional through seat_number and seat_label
  • planners can seat a guest at a table without specifying an exact seat
  • planners can also capture explicit seat positions when they need finer control

This keeps v1 operationally usable while preserving a clean path to richer spatial layout later.

Zone model

The baseline also supports zones.

Zones exist to group tables into simple sections such as:

  • main hall
  • family section
  • patio
  • vendor mezzanine

Current behavior:

  • a zone belongs to one seating plan
  • a table may reference one zone or no zone
  • guests do not receive full zone listings
  • vendors only see zone data when they already have permission to view the published plan

Zones solve immediate operational grouping without forcing a full floorplan system into this task.

Assignment behavior

Assignments map one actor to one table within one seating plan.

The baseline rules are:

  • one actor may only have one assignment per seating plan
  • duplicate seat numbers on the same table are rejected
  • seat numbers above table capacity are rejected
  • table over-capacity is rejected
  • declined invitees are rejected for assignment
  • pending invitees remain assignable

Planner changes after publication are allowed, but any structural or assignment edit demotes the plan back to draft. The planner must publish again before guests or vendors consume the updated arrangement.

Actor eligibility

Seating is event-scoped, so eligibility is resolved per event.

The current candidate model includes only actors of type:

  • person
  • household
  • group

When RSVP invitations and responses exist, candidate selection is narrowed to event-invited actors. RSVP posture is then attached as:

  • attending
  • pending
  • declined
  • not_tracked

The practical baseline is:

  • invited and pending actors can still be seated
  • declined actors cannot be seated
  • if no RSVP data exists, the module falls back to broader actor availability

The planner view also exposes group_labels derived from parent memberships so households and groups are easier to keep together manually.

Planner flow

Planner routes are:

  • GET /v1/occasions/:occasion_id/seating
  • POST /v1/occasions/:occasion_id/seating/plans
  • POST /v1/occasions/:occasion_id/seating/plans/:seating_plan_id/zones
  • PATCH /v1/occasions/:occasion_id/seating/zones/:seating_zone_id
  • POST /v1/occasions/:occasion_id/seating/plans/:seating_plan_id/tables
  • PATCH /v1/occasions/:occasion_id/seating/tables/:seating_table_id
  • POST /v1/occasions/:occasion_id/seating/plans/:seating_plan_id/assignments
  • DELETE /v1/occasions/:occasion_id/seating/assignments/:seating_assignment_id
  • POST /v1/occasions/:occasion_id/seating/plans/:seating_plan_id/publish

The planner dashboard route is:

  • /occasions/:occasionId/seating

The planner UI supports:

  • selecting an enabled event
  • creating a seating plan when the event has none yet
  • creating zones and tables
  • assigning, moving, and unassigning actors
  • seeing capacity state and unassigned actors
  • publishing the current seating plan

Guest flow

Guest route:

  • GET /v1/guest/occasions/:occasion_slug/seating

Guest app route:

  • /seating

Guest visibility rules are:

  • the guest token must resolve to the same occasion
  • the event must already be accessible to that token
  • the seating plan must be published
  • the event enablement must set publish_to_guests = true
  • the guest only receives assignments for the resolved guest actor or invitation-unit actor

Guests do not receive unrelated seating assignments, the full table roster, or unpublished drafts.

Vendor flow

Vendor route:

  • GET /v1/vendors/occasions/:occasion_id/seating

Vendor visibility rules are:

  • an active vendor actor is required
  • the actor must belong to the occasion
  • the plan must already be published
  • centralized authorization must allow resource:seating_plan:view

This is intentionally a seam rather than a full vendor workspace feature. It preserves the contract needed for venue, hall, and catering workflows later.

Permissions and visibility

Planner management uses centralized permission actions:

  • seating:list
  • seating:create
  • seating:update
  • seating:publish

Vendor reads use:

  • resource:seating_plan:view

Guest access is token-based and filtered server-side instead of sharing the planner response shape.

Unauthorized planner or vendor requests are rejected with the normal centralized authorization behavior. Guest requests with the wrong token or wrong occasion are rejected without exposing unrelated seating data.

Module-platform integration

Seating is a real shared module definition.

It currently declares:

  • occasion installation scope
  • event enablement scope
  • dependency on the actor domain
  • planner, guest, and vendor surfaces
  • install and enablement schemas

The server requires a real installation for occasion-scoped reads and writes, and a real event enablement for event-scoped plan creation.

Future publishing seam

This task does not implement printable exports yet, but the current model preserves the seam for:

  • seating chart exports
  • printable table lists
  • guest signage
  • vendor-ready floorplan derivatives

Later publishing work can build on the existing plan, zone, table, and assignment records instead of inventing a parallel seating representation.