> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Ishaq74/concordia/llms.txt
> Use this file to discover all available pages before exploring further.

# Booking & Reservation System

> Service booking system with availability scheduling, reservation management, and status workflows

# Booking & Reservation System

Concordia's booking system enables customers to reserve services with providers through an availability-based scheduling system with status management and cancellation policies.

## Overview

The booking system consists of two main components:

* **Availability Schedules** (`services_availability.schema.ts`) - Provider defines when they're available
* **Bookings** (`services_bookings.schema.ts`) - Customer reservations of specific time slots

## Availability Management

From `src/database/schemas/services_availability.schema.ts`:

```typescript theme={null}
export const servicesAvailability = pgTable("services_availability", {
  id: text("id").primaryKey(),
  serviceId: text("service_id").notNull(),
  dayOfWeek: integer("day_of_week").notNull(), // 0 (dim) → 6 (sam)
  startTime: text("start_time").notNull(),
  endTime: text("end_time").notNull(),
  isAvailable: boolean("is_available").notNull().default(true),
  createdAt: timestamp("created_at").defaultNow().notNull(),
}, (table) => [
  uniqueIndex("idx_services_availability_unique").on(
    table.serviceId,
    table.dayOfWeek,
    table.startTime,
  ),
]);
```

### Availability Fields

<ParamField path="id" type="text" required>
  Unique availability entry identifier
</ParamField>

<ParamField path="serviceId" type="text" required>
  Reference to the service listing
</ParamField>

<ParamField path="dayOfWeek" type="integer" required>
  Day of the week using numeric representation:

  * `0` = Sunday
  * `1` = Monday
  * `2` = Tuesday
  * `3` = Wednesday
  * `4` = Thursday
  * `5` = Friday
  * `6` = Saturday
</ParamField>

<ParamField path="startTime" type="text" required>
  Start time in 24-hour HH:MM format

  Example: `"09:00"`, `"14:30"`
</ParamField>

<ParamField path="endTime" type="text" required>
  End time in 24-hour HH:MM format

  Example: `"17:00"`, `"18:30"`
</ParamField>

<ParamField path="isAvailable" type="boolean" default={true}>
  Whether this time slot is currently available for booking

  Set to `false` to temporarily block a recurring time slot without deleting it
</ParamField>

<ParamField path="createdAt" type="timestamp" required>
  When this availability entry was created
</ParamField>

### Unique Constraint

The schema enforces uniqueness on `(serviceId, dayOfWeek, startTime)` to prevent duplicate time slots:

<Warning>
  You cannot create two availability entries with the same service, day, and start time. This prevents scheduling conflicts.
</Warning>

### Recurring Weekly Schedule

Availability entries define a recurring weekly schedule. For example:

```json theme={null}
[
  {
    "serviceId": "service-123",
    "dayOfWeek": 1,
    "startTime": "09:00",
    "endTime": "12:00",
    "isAvailable": true
  },
  {
    "serviceId": "service-123",
    "dayOfWeek": 1,
    "startTime": "14:00",
    "endTime": "17:00",
    "isAvailable": true
  },
  {
    "serviceId": "service-123",
    "dayOfWeek": 3,
    "startTime": "09:00",
    "endTime": "17:00",
    "isAvailable": true
  }
]
```

This creates:

* **Monday**: Available 9am-12pm and 2pm-5pm
* **Wednesday**: Available 9am-5pm

<Info>
  Multiple availability windows per day are supported, perfect for providers with lunch breaks or split schedules.
</Info>

## Booking Management

From `src/database/schemas/services_bookings.schema.ts`:

```typescript theme={null}
export const servicesBookings = pgTable("services_bookings", {
  id: text("id").primaryKey(),
  serviceId: text("service_id").notNull(),
  customerId: text("customer_id").notNull(),
  providerId: text("provider_id").notNull(),
  bookingDate: text("booking_date").notNull(),
  bookingTime: text("booking_time").notNull(),
  durationMinutes: integer("duration_minutes").notNull(),
  totalPrice: text("total_price"),
  currency: text("currency").default("EUR"),
  status: text("status").notNull().default("pending"),
  customerMessage: text("customer_message"),
  providerResponse: text("provider_response"),
  cancelledAt: timestamp("cancelled_at"),
  completedAt: timestamp("completed_at"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
```

### Core Booking Fields

<ParamField path="id" type="text" required>
  Unique booking identifier
</ParamField>

<ParamField path="serviceId" type="text" required>
  Reference to the service being booked
</ParamField>

<ParamField path="customerId" type="text" required>
  User ID of the customer making the booking
</ParamField>

<ParamField path="providerId" type="text" required>
  User ID of the service provider
</ParamField>

### Schedule Details

<ParamField path="bookingDate" type="text" required>
  Date of the service in YYYY-MM-DD format

  Example: `"2026-03-15"`
</ParamField>

<ParamField path="bookingTime" type="text" required>
  Start time of the service in HH:MM format

  Example: `"14:00"`
</ParamField>

<ParamField path="durationMinutes" type="integer" required>
  Duration of the booked service in minutes

  Example: `90` for 1.5 hours
</ParamField>

<Note>
  The combination of `bookingDate`, `bookingTime`, and `durationMinutes` defines the exact time slot reserved.
</Note>

### Payment Information

<ParamField path="totalPrice" type="text">
  Final price as a string for decimal precision

  Example: `"75.00"`
</ParamField>

<ParamField path="currency" type="text" default="EUR">
  ISO 4217 currency code

  Example: `"EUR"`, `"USD"`, `"GBP"`
</ParamField>

### Booking Status

<ParamField path="status" type="text" default="pending">
  Current booking status with possible values:

  * `pending` - Awaiting provider confirmation
  * `confirmed` - Provider has confirmed the booking
  * `completed` - Service has been delivered
  * `cancelled` - Booking was cancelled
  * `no_show` - Customer didn't show up
</ParamField>

### Communication

<ParamField path="customerMessage" type="text">
  Optional message from customer to provider

  Example: `"I need wheelchair access. Is that available?"`
</ParamField>

<ParamField path="providerResponse" type="text">
  Provider's response to the booking or customer message

  Example: `"Yes, we have wheelchair access. See you at 2pm!"`
</ParamField>

### Lifecycle Timestamps

<ParamField path="cancelledAt" type="timestamp">
  When the booking was cancelled (if applicable)

  Only set when status transitions to `cancelled`
</ParamField>

<ParamField path="completedAt" type="timestamp">
  When the service was marked as completed

  Set when status transitions to `completed`
</ParamField>

<ParamField path="createdAt" type="timestamp" required>
  When the booking was initially created
</ParamField>

<ParamField path="updatedAt" type="timestamp" required>
  Last modification time, automatically updated
</ParamField>

## Booking Status Workflow

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending : Customer books
    pending --> confirmed : Provider accepts
    pending --> cancelled : Customer/provider cancels
    confirmed --> completed : Service delivered
    confirmed --> cancelled : Cancellation
    confirmed --> no_show : Customer absent
    completed --> [*]
    cancelled --> [*]
    no_show --> [*]
```

### Status Transitions

<ParamField path="pending → confirmed">
  Provider accepts the booking request

  Typically within 24-48 hours of booking
</ParamField>

<ParamField path="pending → cancelled">
  Either party cancels before confirmation

  Sets `cancelledAt` timestamp
</ParamField>

<ParamField path="confirmed → completed">
  Service successfully delivered

  Sets `completedAt` timestamp, enables review
</ParamField>

<ParamField path="confirmed → cancelled">
  Cancellation after confirmation

  May have policy implications (see cancellation policies)
</ParamField>

<ParamField path="confirmed → no_show">
  Customer didn't attend appointment

  Provider marks as no-show
</ParamField>

## Cancellation Policies

From `services_listings.schema.ts`, services define cancellation rules:

```typescript theme={null}
export const servicesListings = pgTable("services_listings", {
  // ... other fields
  bookingAdvanceHours: integer("booking_advance_hours"),
  cancellationHours: integer("cancellation_hours"),
});
```

<ParamField path="bookingAdvanceHours" type="integer">
  Minimum hours in advance required for booking

  Example: `24` means customers must book at least 1 day ahead
</ParamField>

<ParamField path="cancellationHours" type="integer">
  Hours before service when free cancellation is allowed

  Example: `48` means free cancellation up to 2 days before
</ParamField>

### Example Policy Enforcement

```typescript theme={null}
function canCancelFree(booking, service) {
  const bookingDateTime = new Date(`${booking.bookingDate}T${booking.bookingTime}`);
  const hoursUntilBooking = (bookingDateTime - new Date()) / (1000 * 60 * 60);
  
  return hoursUntilBooking >= service.cancellationHours;
}

function canBookNow(bookingDate, bookingTime, service) {
  const requestedDateTime = new Date(`${bookingDate}T${bookingTime}`);
  const hoursUntilBooking = (requestedDateTime - new Date()) / (1000 * 60 * 60);
  
  return hoursUntilBooking >= service.bookingAdvanceHours;
}
```

## Database Indexes

From the schema files:

### Availability Indexes

```sql theme={null}
CREATE INDEX idx_services_availability_service ON services_availability(service_id);
```

Optimizes queries for all availability slots for a service.

### Booking Indexes

```sql theme={null}
CREATE INDEX idx_services_bookings_service ON services_bookings(service_id);
CREATE INDEX idx_services_bookings_customer ON services_bookings(customer_id);
CREATE INDEX idx_services_bookings_provider ON services_bookings(provider_id);
CREATE INDEX idx_services_bookings_status ON services_bookings(status);
CREATE INDEX idx_services_bookings_date ON services_bookings(booking_date);
```

<Info>
  Indexes support efficient queries for:

  * All bookings for a service
  * Customer's booking history
  * Provider's booking calendar
  * Bookings by status for dashboards
  * Bookings by date for calendar views
</Info>

## Integration with Services

From `services_listings.schema.ts`, the relationship is defined:

```typescript theme={null}
export const servicesListingsRelations = relations(servicesListings, ({ one, many }) => ({
  // ... other relations
  availability: many(servicesAvailability),
  bookings: many(servicesBookings),
}));
```

Each service can have:

* Multiple availability windows (recurring weekly schedule)
* Multiple bookings (past and future reservations)

## Booking Flow Example

### 1. Provider Sets Availability

```typescript theme={null}
// Provider defines Monday 9am-5pm availability
const availability = {
  id: generateId(),
  serviceId: "service-123",
  dayOfWeek: 1, // Monday
  startTime: "09:00",
  endTime: "17:00",
  isAvailable: true,
};
```

### 2. Customer Requests Booking

```typescript theme={null}
// Customer books for Monday, March 15, 2026 at 2pm
const booking = {
  id: generateId(),
  serviceId: "service-123",
  customerId: "customer-456",
  providerId: "provider-789",
  bookingDate: "2026-03-15",
  bookingTime: "14:00",
  durationMinutes: 60,
  totalPrice: "50.00",
  currency: "EUR",
  status: "pending",
  customerMessage: "First time customer, looking forward to it!",
};
```

### 3. Provider Confirms

```typescript theme={null}
// Provider accepts booking
booking.status = "confirmed";
booking.providerResponse = "Confirmed! See you on Monday at 2pm.";
booking.updatedAt = new Date();
```

### 4. Service Completed

```typescript theme={null}
// After service delivery
booking.status = "completed";
booking.completedAt = new Date();
booking.updatedAt = new Date();

// Customer can now leave a review
```

## Conflict Prevention

To prevent double-booking:

1. **Check availability** - Verify day/time matches an active availability entry
2. **Check existing bookings** - Ensure no overlapping confirmed bookings
3. **Consider duration** - Account for service duration when checking conflicts

```typescript theme={null}
function hasConflict(newBooking, existingBookings) {
  const newStart = new Date(`${newBooking.bookingDate}T${newBooking.bookingTime}`);
  const newEnd = new Date(newStart.getTime() + newBooking.durationMinutes * 60000);
  
  return existingBookings.some(existing => {
    if (existing.status !== 'confirmed') return false;
    
    const existingStart = new Date(`${existing.bookingDate}T${existing.bookingTime}`);
    const existingEnd = new Date(existingStart.getTime() + existing.durationMinutes * 60000);
    
    return (newStart < existingEnd && newEnd > existingStart);
  });
}
```

## Best Practices

### For Providers

1. **Set realistic availability** - Only mark times you can reliably serve customers
2. **Use `isAvailable: false`** - Temporarily block slots without deleting recurring schedule
3. **Respond promptly** - Confirm or decline bookings within 24 hours
4. **Communicate clearly** - Use `providerResponse` for important details

### For Booking System

1. **Validate against availability** - Check day/time matches provider schedule
2. **Prevent double-booking** - Lock slots or use transactions
3. **Enforce policies** - Respect `bookingAdvanceHours` and `cancellationHours`
4. **Send notifications** - Email/notify on booking, confirmation, cancellation
5. **Enable reviews** - Only allow reviews for `completed` bookings

### For Customers

1. **Book in advance** - Respect `bookingAdvanceHours` requirement
2. **Provide details** - Use `customerMessage` for special requests
3. **Cancel early** - Follow `cancellationHours` policy for free cancellation
4. **Leave reviews** - Help other customers after `completed` bookings
