Technical Reference
Appointments

Appointments — Technical Reference

This page covers the data models, architecture, and future integration patterns behind the Appointments module.

Data Models

appointments

ColumnTypeDescription
iduuidPrimary key
workspace_iduuidFK → workspaces.id — tenant isolation (ON DELETE CASCADE)
titletextRequired. Short label for the appointment
descriptiontextOptional detailed notes or agenda
locationtextOptional location (physical address, Zoom link, etc.)
typetext'meeting', 'service', or 'other' (CHECK constraint, defaults to 'meeting')
start_timetimestamptzRequired. When the appointment begins (stored in UTC)
end_timetimestamptzRequired. When the appointment ends (stored in UTC, must be after start_time)
statustext'scheduled', 'completed', 'canceled', or 'no_show' (CHECK constraint, defaults to 'scheduled')
contact_iduuidRequired. FK → contacts.id (ON DELETE CASCADE)
assigned_touuidFK → user_profiles.id — assigned member (defaults to creator)
sourcetextIdentifies origin system (currently always 'manual', reserved for integrations)
external_idtextReserved for third-party integration IDs
external_urltextReserved for third-party booking page URLs
transaction_iduuidDormant FK → transactions.id (ON DELETE SET NULL)
created_byuuidFK → user_profiles.id — who created the appointment
updated_byuuidFK → user_profiles.id — who last modified the appointment
created_attimestamptzCreation timestamp
updated_attimestamptzLast modification timestamp

Foreign Key Constraints

The contact_id foreign key uses ON DELETE CASCADE. If a contact is deleted, all their appointments are automatically removed. This differs from Tasks (ON DELETE SET NULL) because an appointment without an associated contact has no operational context in the CRM.

Architecture

Derived Status (Assumed Past)

Appointments use an "assumed past" model. While the database schema includes a 'completed' status value, the UI rarely relies on it. Instead, the UI derives the "Past" state dynamically by comparing end_time against the current time (now).

If an appointment is not 'canceled' or 'no_show', and its end_time is in the past, it is displayed with a green "Past" badge regardless of whether the database status is 'scheduled' or 'completed'.

Smart Defaults and Validation

When initializing the appointment creation form, the UI sets smart defaults:

  • start_time: Tomorrow at 10:00 AM (local time)
  • end_time: Tomorrow at 11:00 AM (local time)

When a user modifies the start_time, the client-side logic automatically adjusts the end_time to preserve the current duration gap.

Both client-side and server-side validation enforce that end_time must be chronologically after start_time.

Live Contact Search

When creating an appointment from the Appointments page, the contact selection uses a live search picker:

  • Minimum 2 characters to trigger search
  • 300ms debounce
  • Performs an ILIKE search against first_name, last_name, and email

When creating from a Contact Detail page, this picker is replaced by a locked, read-only display of the current contact.

Future: Third-Party Integrations

The appointments schema is future-proofed for third-party scheduling integrations (like Calendly, Acuity, etc.) using an adapter pattern.

ColumnPurpose
sourceDistinguishes between 'manual' and future external sources (e.g., 'calendly')
external_idThe appointment's ID in the external system, used for webhook idempotency and deduplication
external_urlDirect link to the appointment in the external system's UI

A composite unique index on (workspace_id, source, external_id) prevents duplicate records from webhook retries while scoping the IDs to the specific source to avoid collisions between different providers.

Note: These columns are currently dormant and reserved for future development.

Security

RLS Policies

Appointments use standard workspace-scoped Row Level Security with no role restrictions:

OperationPolicy
SELECTAll workspace members
INSERTAll workspace members
UPDATEAll workspace members
DELETEAll workspace members

Unlike core entities (Deals, Companies) that restrict deletion to Admins, appointment deletion is available to all members to support daily operational workflows (e.g., a receptionist managing bookings).