← back to Jill Website

DATABASE.md

284 lines

# Database Schema and Models Documentation

## Overview

This project uses PostgreSQL as the database for storing property information and guest inquiries. The database includes proper constraints, indexes, and error handling.

## Database Connection

### Configuration

Database connection is configured through environment variables in `.env` file:

```env
DB_HOST=localhost
DB_PORT=5432
DB_NAME=jill_website
DB_USER=postgres
DB_PASSWORD=your_password_here
```

### Connection Module

Located in `src/config/database.ts`, provides:

- **getPool()**: Returns a singleton PostgreSQL connection pool
- **testConnection()**: Tests database connectivity
- **closePool()**: Closes the connection pool gracefully

### Error Handling

- Connection errors are logged and cause process exit
- Connection timeouts are set to 2 seconds
- Idle connections timeout after 30 seconds
- Pool maintains up to 20 concurrent connections

## Database Schema

### Inquiries Table

Stores guest inquiry information submitted through the contact form.

```sql
CREATE TABLE inquiries (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  email VARCHAR(255) NOT NULL,
  phone VARCHAR(50) NOT NULL,
  check_in_date DATE NOT NULL,
  check_out_date DATE NOT NULL,
  guest_count INTEGER NOT NULL CHECK (guest_count > 0),
  message TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT valid_dates CHECK (check_out_date > check_in_date)
);
```

**Indexes:**
- `idx_inquiries_email`: Fast email lookups
- `idx_inquiries_check_in`: Availability queries
- `idx_inquiries_created_at`: Recent inquiries sorting

**Constraints:**
- Guest count must be positive
- Check-out date must be after check-in date
- All fields are required

### Properties Table

Stores luxury property information including amenities and images.

```sql
CREATE TABLE properties (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL UNIQUE,
  description TEXT NOT NULL,
  amenities JSONB NOT NULL,
  images JSONB NOT NULL,
  airbnb_url VARCHAR(500) NOT NULL,
  capacity INTEGER CHECK (capacity > 0),
  bedrooms INTEGER CHECK (bedrooms >= 0),
  bathrooms NUMERIC(3,1) CHECK (bathrooms >= 0),
  size_sqm NUMERIC(10,2) CHECK (size_sqm >= 0),
  price_per_night NUMERIC(10,2) CHECK (price_per_night >= 0),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

**Indexes:**
- `idx_properties_name`: Fast property name lookups

**Constraints:**
- Property name must be unique
- Capacity must be positive
- Numeric fields cannot be negative
- Amenities and images stored as JSONB arrays

## Models

### InquiryModel

Located in `src/models/Inquiry.ts`

**Interface:**
```typescript
interface Inquiry {
  id?: number;
  name: string;
  email: string;
  phone: string;
  check_in_date: Date;
  check_out_date: Date;
  guest_count: number;
  message: string;
  created_at?: Date;
  updated_at?: Date;
}
```

**Methods:**
- `create(inquiry)`: Creates new inquiry with validation
- `findById(id)`: Retrieves inquiry by ID
- `findAll(limit, offset)`: Lists all inquiries with pagination
- `update(id, inquiry)`: Updates existing inquiry
- `delete(id)`: Deletes inquiry by ID

**Validation:**
- Name, email, phone, message required
- Email format validation (regex)
- Date validation (check-out after check-in)
- Guest count must be at least 1

### PropertyModel

Located in `src/models/Property.ts`

**Interface:**
```typescript
interface Property {
  id?: number;
  name: string;
  description: string;
  amenities: string[];
  images: string[];
  airbnb_url: string;
  capacity?: number;
  bedrooms?: number;
  bathrooms?: number;
  size_sqm?: number;
  price_per_night?: number;
  created_at?: Date;
  updated_at?: Date;
}
```

**Methods:**
- `create(property)`: Creates new property with validation
- `findById(id)`: Retrieves property by ID
- `findAll(limit, offset)`: Lists all properties with pagination
- `update(id, property)`: Updates existing property
- `delete(id)`: Deletes property by ID

**Validation:**
- Name, description, amenities, images, airbnb_url required
- At least one amenity and image required
- All image URLs must be valid
- Airbnb URL must be valid
- Numeric fields must be non-negative

## Database Migrations

### Running Migrations

```bash
npm run migrate
```

### Migration Files

Located in `src/migrations/`:

- `001_create_tables.sql`: Creates inquiries and properties tables with indexes
- `migrate.ts`: Migration runner script

### Migration Process

1. Tests database connection
2. Reads all `.sql` files in migrations directory
3. Executes files in alphabetical order
4. Logs success/failure for each migration
5. Closes connection pool on completion

## Usage Examples

### Creating an Inquiry

```typescript
import { InquiryModel } from './models/Inquiry';

const inquiryModel = new InquiryModel();

const newInquiry = await inquiryModel.create({
  name: 'John Doe',
  email: 'john@example.com',
  phone: '+1-555-0123',
  check_in_date: new Date('2025-02-01'),
  check_out_date: new Date('2025-02-08'),
  guest_count: 4,
  message: 'Looking to book Casita del Sol for a week'
});
```

### Creating a Property

```typescript
import { PropertyModel } from './models/Property';

const propertyModel = new PropertyModel();

const newProperty = await propertyModel.create({
  name: 'Casita del Sol',
  description: 'First floor oceanfront villa with private entrance',
  amenities: ['Saltwater Pool', 'Beach Access', 'Full Kitchen', 'WiFi'],
  images: [
    'https://example.com/image1.jpg',
    'https://example.com/image2.jpg'
  ],
  airbnb_url: 'https://airbnb.com/rooms/12345',
  capacity: 4,
  bedrooms: 1,
  bathrooms: 1.5,
  size_sqm: 76,
  price_per_night: 250
});
```

### Testing Connection

```typescript
import { testConnection } from './config/database';

try {
  await testConnection();
  console.log('Database connected successfully');
} catch (error) {
  console.error('Database connection failed:', error);
}
```

## Error Handling

All model methods include comprehensive error handling:

- Validation errors throw detailed messages
- Database errors are caught and logged
- Error messages include original error details
- Connection errors trigger automatic reconnection

## Type Safety

All models are fully typed with TypeScript interfaces, providing:

- Compile-time type checking
- IDE autocomplete support
- Clear API documentation
- Prevention of runtime type errors

## Setup Instructions

1. Install PostgreSQL on your system
2. Create database: `createdb jill_website`
3. Copy `.env.example` to `.env` and configure credentials
4. Run migrations: `npm run migrate`
5. Test connection in your application

## Performance Considerations

- Connection pooling (max 20 connections)
- Proper indexes on frequently queried fields
- JSONB for flexible amenities/images storage
- Automatic timestamp updates via triggers
- Query result pagination support