# Developer Guidelines

Best practices for UX development in ThrillWiki.

## General Principles

### 1. Progressive Enhancement

All features should work without JavaScript, with HTMX and Alpine.js enhancing the experience:

```html
<!-- Form works with or without JS -->
<form method="post" action="/parks/create/"
      hx-post="/parks/create/"
      hx-target="#form-container">
    {% csrf_token %}
    <!-- Form fields -->
    <button type="submit">Save</button>
</form>
```

### 2. Consistent Feedback

Every user action should provide immediate feedback:

- **Loading states**: Show progress during requests
- **Success messages**: Confirm completed actions
- **Error messages**: Explain what went wrong
- **Validation**: Inline feedback on form fields

### 3. Accessibility First

All components must be accessible:

- Proper ARIA attributes
- Keyboard navigation
- Screen reader support
- Focus management
- Sufficient color contrast

### 4. Mobile-First Design

Design for mobile first, then enhance for larger screens:

```html
<!-- Mobile: stacked, Desktop: side-by-side -->
<div class="flex flex-col md:flex-row gap-4">
    <div class="w-full md:w-1/2">Left</div>
    <div class="w-full md:w-1/2">Right</div>
</div>
```

## File Organization

### Template Structure

```
templates/
├── base/
│   └── base.html           # Base template
├── components/
│   ├── layout/             # Layout components
│   ├── modals/             # Modal components
│   ├── navigation/         # Navigation components
│   ├── skeletons/          # Skeleton screens
│   └── ui/                 # UI primitives
├── forms/
│   ├── layouts/            # Form layouts
│   └── partials/           # Form field components
├── htmx/
│   └── components/         # HTMX-specific components
└── [app_name]/
    ├── list.html           # Full page templates
    ├── list_partial.html   # HTMX partials
    └── _card.html          # Reusable fragments
```

### Naming Conventions

| Type | Convention | Example |
|------|------------|---------|
| Full page | `name.html` | `list.html` |
| HTMX partial | `name_partial.html` | `list_partial.html` |
| Fragment | `_name.html` | `_card.html` |
| Component | `name.html` in components/ | `button.html` |

## Django Integration

### Context Processors

Use context processors for global data:

```python
# apps/core/context_processors.py
def breadcrumbs(request):
    return {'breadcrumbs': getattr(request, 'breadcrumbs', [])}

def page_meta(request):
    return {'page_meta': getattr(request, 'page_meta', {})}
```

### View Patterns

#### Standard View

```python
def park_list(request):
    parks = Park.objects.all()
    return render(request, 'parks/list.html', {'parks': parks})
```

#### HTMX-Aware View

```python
from apps.core.htmx_utils import is_htmx_request

def park_list(request):
    parks = Park.objects.all()
    template = 'parks/list_partial.html' if is_htmx_request(request) else 'parks/list.html'
    return render(request, template, {'parks': parks})
```

#### Using Decorator

```python
from apps.core.htmx_utils import htmx_partial

@htmx_partial('parks/list.html')
def park_list(request):
    parks = Park.objects.all()
    return ({'parks': parks},)
```

### Breadcrumbs

Set breadcrumbs in views:

```python
from apps.core.utils import BreadcrumbBuilder

def park_detail(request, slug):
    park = get_object_or_404(Park, slug=slug)

    request.breadcrumbs = (
        BreadcrumbBuilder()
        .add_home()
        .add('Parks', reverse('parks:list'))
        .add_current(park.name)
        .build()
    )

    return render(request, 'parks/detail.html', {'park': park})
```

### Page Meta

Set meta information in views:

```python
from apps.core.utils import build_meta_context

def park_detail(request, slug):
    park = get_object_or_404(Park, slug=slug)

    request.page_meta = build_meta_context(
        title=park.name,
        description=park.description,
        instance=park,
        request=request,
    )

    return render(request, 'parks/detail.html', {'park': park})
```

## HTMX Best Practices

### 1. Use Appropriate HTTP Methods

```html
<!-- GET for read operations -->
<button hx-get="/parks/">Load Parks</button>

<!-- POST for create -->
<form hx-post="/parks/create/">...</form>

<!-- PUT/PATCH for update -->
<form hx-put="/parks/123/edit/">...</form>

<!-- DELETE for remove -->
<button hx-delete="/parks/123/">Delete</button>
```

### 2. Target Specific Elements

```html
<!-- Good: Specific target -->
<button hx-get="/parks/" hx-target="#parks-list">Load</button>

<!-- Avoid: Replacing large sections unnecessarily -->
<button hx-get="/parks/" hx-target="#main-content">Load</button>
```

### 3. Use Loading Indicators

```html
<button hx-get="/parks/"
        hx-target="#parks-list"
        hx-indicator="#loading">
    Load Parks
</button>

<div id="loading" class="htmx-indicator">
    {% include 'htmx/components/loading_indicator.html' %}
</div>
```

### 4. Handle Errors Gracefully

```python
def create_park(request):
    form = ParkForm(request.POST)

    if not form.is_valid():
        # Return form with errors, status 422
        return render(
            request,
            'parks/_form.html',
            {'form': form},
            status=422
        )

    park = form.save()
    return htmx_success(f'{park.name} created!')
```

### 5. Use Response Headers

```python
from apps.core.htmx_utils import (
    htmx_success,
    htmx_error,
    htmx_redirect,
    htmx_modal_close,
)

# Success with toast
return htmx_success('Park saved!')

# Error with toast
return htmx_error('Validation failed', status=422)

# Redirect
return htmx_redirect('/parks/')

# Close modal and refresh
return htmx_modal_close(
    message='Saved!',
    refresh_target='#parks-list'
)
```

## Alpine.js Best Practices

### 1. Keep Components Small

```html
<!-- Good: Focused component -->
<div x-data="{ open: false }">
    <button @click="open = !open">Toggle</button>
    <div x-show="open">Content</div>
</div>

<!-- Avoid: Large monolithic components -->
<div x-data="{
    open: false,
    items: [],
    selectedItem: null,
    loading: false,
    // ... many more properties
}">
```

### 2. Use Stores for Global State

```javascript
// stores/index.js
Alpine.store('toast', {
    messages: [],
    success(message, duration = 5000) { /* ... */ },
    error(message, duration = 0) { /* ... */ },
});

// Usage anywhere
Alpine.store('toast').success('Saved!');
```

### 3. Initialize from Server Data

```html
<div x-data="{ items: {{ items_json|safe }} }">
    <template x-for="item in items">
        <div x-text="item.name"></div>
    </template>
</div>
```

### 4. Use Magic Properties

```html
<div x-data="{ message: '' }">
    <!-- $refs for DOM access -->
    <input x-ref="input" x-model="message">
    <button @click="$refs.input.focus()">Focus</button>

    <!-- $watch for reactive updates -->
    <div x-init="$watch('message', value => console.log(value))">

    <!-- $nextTick for DOM updates -->
    <button @click="items.push('new'); $nextTick(() => scrollToBottom())">
        Add
    </button>
</div>
```

## CSS/Tailwind Best Practices

### 1. Use Design Tokens

```css
/* Use CSS variables */
.custom-element {
    color: hsl(var(--foreground));
    background: hsl(var(--background));
    border-color: hsl(var(--border));
}
```

### 2. Use Component Classes

```html
<!-- Good: Semantic classes -->
<button class="btn btn-primary btn-lg">Save</button>

<!-- Avoid: Long utility chains for common patterns -->
<button class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium">
    Save
</button>
```

### 3. Responsive Design

```html
<!-- Mobile-first -->
<div class="p-4 md:p-6 lg:p-8">
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        <!-- Items -->
    </div>
</div>
```

### 4. Dark Mode Support

```html
<!-- Automatic dark mode via CSS variables -->
<div class="bg-background text-foreground">
    Content adapts to theme
</div>

<!-- Explicit dark mode variants -->
<div class="bg-white dark:bg-gray-800">
    Explicit dark override
</div>
```

## Testing Guidelines

### 1. Test User Flows

```python
def test_create_park_flow(self):
    # Navigate to create page
    response = self.client.get('/parks/create/')
    self.assertEqual(response.status_code, 200)

    # Submit form
    response = self.client.post('/parks/create/', {
        'name': 'Test Park',
        'location': 'Test Location',
    })

    # Verify redirect or success
    self.assertEqual(response.status_code, 302)
    self.assertTrue(Park.objects.filter(name='Test Park').exists())
```

### 2. Test HTMX Responses

```python
def test_htmx_park_list(self):
    response = self.client.get('/parks/', HTTP_HX_REQUEST='true')

    # Should return partial template
    self.assertTemplateUsed(response, 'parks/list_partial.html')

    # Should not include base template chrome
    self.assertNotContains(response, '<html')
```

### 3. Test Error States

```python
def test_form_validation_errors(self):
    response = self.client.post('/parks/create/', {
        'name': '',  # Required field
    })

    self.assertEqual(response.status_code, 422)
    self.assertContains(response, 'This field is required')
```

## Performance Guidelines

### 1. Minimize DOM Updates

```html
<!-- Good: Update specific element -->
<button hx-get="/count/" hx-target="#count-badge">Refresh</button>

<!-- Avoid: Replacing entire page section -->
<button hx-get="/dashboard/" hx-target="#main">Refresh</button>
```

### 2. Use Skeleton Screens

```html
<div id="content"
     hx-get="/parks/"
     hx-trigger="load"
     hx-swap="innerHTML">
    {% include 'components/skeletons/card_grid_skeleton.html' %}
</div>
```

### 3. Lazy Load Content

```html
<!-- Load when visible -->
<div hx-get="/stats/"
     hx-trigger="revealed"
     hx-swap="innerHTML">
    <div class="skeleton h-20"></div>
</div>
```

### 4. Debounce Input

```html
<!-- Debounce search input -->
<input hx-get="/search/"
       hx-trigger="keyup changed delay:300ms"
       hx-target="#results">
```

## Security Guidelines

### 1. CSRF Protection

```html
<!-- Include token in body -->
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>

<!-- Or in forms -->
<form hx-post="/create/">
    {% csrf_token %}
</form>
```

### 2. Validate on Server

Always validate data server-side, even with client-side validation:

```python
def create_park(request):
    form = ParkForm(request.POST)
    if not form.is_valid():
        return htmx_error('Invalid data', status=422)
    # Process valid data
```

### 3. Escape User Content

```django
<!-- Auto-escaped by Django -->
{{ user_input }}

<!-- Explicitly mark as safe only for trusted content -->
{{ trusted_html|safe }}
```

### 4. Use Appropriate Permissions

```python
from django.contrib.auth.decorators import login_required, permission_required

@login_required
@permission_required('parks.add_park')
def create_park(request):
    # Only authenticated users with permission
    pass
```
