# Data Documentation

## Database Schema

### Core Models

#### Parks
```sql
CREATE TABLE parks_park (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    slug VARCHAR(255) UNIQUE NOT NULL,
    description TEXT,
    status VARCHAR(20) DEFAULT 'OPERATING',
    opening_date DATE,
    closing_date DATE,
    operating_season VARCHAR(255),
    size_acres DECIMAL(10,2),
    website VARCHAR(200),
    average_rating DECIMAL(3,2),
    ride_count INTEGER,
    coaster_count INTEGER,
    owner_id INTEGER REFERENCES companies_company(id),
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);
```

#### Rides
```sql
CREATE TABLE rides_ride (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    slug VARCHAR(255) NOT NULL,
    description TEXT,
    status VARCHAR(20),
    park_id INTEGER REFERENCES parks_park(id),
    area_id INTEGER REFERENCES parks_parkarea(id),
    manufacturer_id INTEGER REFERENCES companies_company(id),
    designer_id INTEGER REFERENCES designers_designer(id),
    opening_date DATE,
    closing_date DATE,
    height_requirement INTEGER,
    ride_type VARCHAR(50),
    thrill_rating INTEGER,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    UNIQUE(park_id, slug)
);
```

#### Reviews
```sql
CREATE TABLE reviews_review (
    id SERIAL PRIMARY KEY,
    content TEXT NOT NULL,
    rating DECIMAL(3,2),
    status VARCHAR(20),
    author_id INTEGER REFERENCES auth_user(id),
    content_type_id INTEGER REFERENCES django_content_type(id),
    object_id INTEGER,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);
```

### Entity Relationships

```mermaid
erDiagram
    Park ||--o{ ParkArea : "contains"
    Park ||--o{ Ride : "has"
    Park ||--o{ Photo : "has"
    Park ||--o{ Review : "receives"
    ParkArea ||--o{ Ride : "contains"
    Ride ||--o{ Photo : "has"
    Ride ||--o{ Review : "receives"
    Company ||--o{ Park : "owns"
    Company ||--o{ Ride : "manufactures"
    Designer ||--o{ Ride : "designs"
    User ||--o{ Review : "writes"
```

## Data Models

### Content Models

#### Park Model
- Core information about theme parks
- Location data through GenericRelation
- Media attachments
- Historical tracking
- Owner relationship

#### Ride Model
- Technical specifications
- Park and area relationships
- Manufacturer and designer links
- Operation status tracking
- Safety requirements

#### Review Model
- Generic foreign key for flexibility
- Rating system
- Media attachments
- Moderation status
- Author tracking

### Supporting Models

#### Location Model
```python
class Location(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()
    
    address = models.CharField(max_length=255)
    city = models.CharField(max_length=100)
    state = models.CharField(max_length=100)
    country = models.CharField(max_length=100)
    postal_code = models.CharField(max_length=20)
    latitude = models.DecimalField(max_digits=9, decimal_places=6)
    longitude = models.DecimalField(max_digits=9, decimal_places=6)
```

#### Media Model
```python
class Photo(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()
    
    file = models.ImageField(upload_to='photos/')
    caption = models.CharField(max_length=255)
    taken_at = models.DateTimeField(null=True)
    uploaded_at = models.DateTimeField(auto_now_add=True)
```

## Storage Strategies

### Database Storage

#### PostgreSQL Configuration
```python
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'thrillwiki',
        'CONN_MAX_AGE': 60,
        'OPTIONS': {
            'client_encoding': 'UTF8',
        },
    }
}
```

#### Indexing Strategy
```sql
-- Performance indexes
CREATE INDEX idx_park_slug ON parks_park(slug);
CREATE INDEX idx_ride_slug ON rides_ride(slug);
CREATE INDEX idx_review_content_type ON reviews_review(content_type_id, object_id);
```

### File Storage

#### Media Storage
```python
# Media storage configuration
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

# File upload handlers
FILE_UPLOAD_HANDLERS = [
    'django.core.files.uploadhandler.MemoryFileUploadHandler',
    'django.core.files.uploadhandler.TemporaryFileUploadHandler',
]
```

#### Directory Structure
```
media/
├── photos/
│   ├── parks/
│   ├── rides/
│   └── reviews/
├── avatars/
└── documents/
```

### Caching Strategy

#### Cache Configuration
```python
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}
```

#### Cache Keys
```python
# Cache key patterns
CACHE_KEYS = {
    'park_detail': 'park:{slug}',
    'ride_list': 'park:{park_slug}:rides',
    'review_count': 'content:{type}:{id}:reviews',
}
```

## Data Migration

### Migration Strategy
1. Schema migrations via Django
2. Data migrations for model changes
3. Content migrations for large updates

### Example Migration
```python
# migrations/0002_add_park_status.py
from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [
        ('parks', '0001_initial'),
    ]
    
    operations = [
        migrations.AddField(
            model_name='park',
            name='status',
            field=models.CharField(
                max_length=20,
                choices=[
                    ('OPERATING', 'Operating'),
                    ('CLOSED', 'Closed'),
                ],
                default='OPERATING'
            ),
        ),
    ]
```

## Data Protection

### Backup Strategy
1. Daily database backups
2. Media files backup
3. Retention policy management

### Backup Configuration
```python
# backup settings
BACKUP_ROOT = os.path.join(BASE_DIR, 'backups')
BACKUP_RETENTION_DAYS = 30
BACKUP_COMPRESSION = True
```

## Data Validation

### Model Validation
```python
class Park(models.Model):
    def clean(self):
        if self.closing_date and self.opening_date:
            if self.closing_date < self.opening_date:
                raise ValidationError({
                    'closing_date': 'Closing date cannot be before opening date'
                })
```

### Form Validation
```python
class RideForm(forms.ModelForm):
    def clean_height_requirement(self):
        height = self.cleaned_data['height_requirement']
        if height and height < 0:
            raise forms.ValidationError('Height requirement cannot be negative')
        return height
```

## Data Access Patterns

### QuerySet Optimization
```python
# Optimized query pattern
Park.objects.select_related('owner')\
    .prefetch_related('rides', 'areas')\
    .filter(status='OPERATING')
```

### Caching Pattern
```python
def get_park_detail(slug):
    cache_key = f'park:{slug}'
    park = cache.get(cache_key)
    if not park:
        park = Park.objects.get(slug=slug)
        cache.set(cache_key, park, timeout=3600)
    return park
```

## Monitoring and Metrics

### Database Metrics
- Query performance
- Cache hit rates
- Storage usage
- Connection pool status

### Collection Configuration
```python
LOGGING = {
    'handlers': {
        'db_log': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'logs/db.log',
        },
    },
}