---
description: Implement a full-stack feature across Django backend and Nuxt frontend
---

# New Feature Workflow

Implement a complete feature spanning the Django backend and Nuxt frontend.

## Planning Phase

Before writing any code, create an implementation plan:

### 1. Feature Definition
- **Goal**: What problem does this feature solve?
- **User Stories**: Who uses it and how?
- **Acceptance Criteria**: How do we know it's done?

### 2. Technical Scope
- **Backend Changes**: Models, APIs, permissions
- **Frontend Changes**: Pages, components, state
- **Data Flow**: How data moves between layers

### 3. Implementation Order

Always implement in this order:
1. **Database/Models** - Foundation first
2. **API Endpoints** - Backend logic
3. **Frontend Components** - UI building blocks
4. **Frontend Pages** - Assembled views
5. **Integration** - Wire it all together
6. **Tests** - Verify everything works

## Implementation Steps

### Step 1: Backend - Models

```python
# Create or modify models
# Remember: Inherit from BaseModel, add proper indexes

class NewFeature(BaseModel):
    # Fields
    name = models.CharField(max_length=255)
    # ... other fields
    
    class Meta:
        ordering = ['-created_at']
```

Run migrations:
```bash
python manage.py makemigrations
python manage.py migrate
```

### Step 2: Backend - Serializers

```python
# backend/apps/[app]/serializers.py

class NewFeatureSerializer(serializers.ModelSerializer):
    class Meta:
        model = NewFeature
        fields = ['id', 'name', 'created_at', 'updated_at']
        read_only_fields = ['id', 'created_at', 'updated_at']

class NewFeatureDetailSerializer(NewFeatureSerializer):
    # Extended fields for detail view
    related_data = RelatedSerializer(many=True, read_only=True)
    
    class Meta(NewFeatureSerializer.Meta):
        fields = NewFeatureSerializer.Meta.fields + ['related_data']
```

### Step 3: Backend - API Views

```python
# backend/apps/[app]/views.py

class NewFeatureViewSet(viewsets.ModelViewSet):
    queryset = NewFeature.objects.all()
    serializer_class = NewFeatureSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    
    def get_queryset(self):
        return NewFeature.objects.select_related(
            # Add related models
        ).prefetch_related(
            # Add many-to-many or reverse relations
        )
    
    def get_serializer_class(self):
        if self.action == 'retrieve':
            return NewFeatureDetailSerializer
        return NewFeatureSerializer
```

### Step 4: Backend - URLs

```python
# backend/apps/[app]/urls.py
router.register('new-features', NewFeatureViewSet, basename='new-feature')
```

### Step 5: Backend - Tests

```python
# backend/apps/[app]/tests/test_new_feature.py

class TestNewFeatureAPI(APITestCase):
    def test_list_features(self):
        response = self.client.get('/api/v1/new-features/')
        self.assertEqual(response.status_code, 200)
    
    def test_create_feature_authenticated(self):
        self.client.force_authenticate(user=self.user)
        response = self.client.post('/api/v1/new-features/', {'name': 'Test'})
        self.assertEqual(response.status_code, 201)
```

### Step 6: Frontend - Types

```typescript
// frontend/types/newFeature.ts

export interface NewFeature {
  id: string
  name: string
  createdAt: string
  updatedAt: string
}

export interface NewFeatureDetail extends NewFeature {
  relatedData: RelatedItem[]
}
```

### Step 7: Frontend - Composables

```typescript
// frontend/composables/useNewFeatures.ts

export function useNewFeatures() {
  const api = useApi()
  
  async function getFeatures(params?: Record<string, any>) {
    return api<PaginatedResponse<NewFeature>>('/new-features/', { params })
  }
  
  async function getFeature(id: string) {
    return api<NewFeatureDetail>(`/new-features/${id}/`)
  }
  
  async function createFeature(data: Partial<NewFeature>) {
    return api<NewFeature>('/new-features/', {
      method: 'POST',
      body: data
    })
  }
  
  return { getFeatures, getFeature, createFeature }
}
```

### Step 8: Frontend - Components

Create necessary components following component patterns:

```vue
<!-- frontend/components/entity/NewFeatureCard.vue -->
<script setup lang="ts">
import type { NewFeature } from '~/types'

defineProps<{
  feature: NewFeature
}>()
</script>

<template>
  <Card interactive>
    <div class="p-4">
      <h3 class="font-semibold">{{ feature.name }}</h3>
      <!-- Additional content -->
    </div>
  </Card>
</template>
```

### Step 9: Frontend - Pages

```vue
<!-- frontend/pages/new-features/index.vue -->
<script setup lang="ts">
definePageMeta({
  // middleware: ['auth'], // if needed
})

useSeoMeta({
  title: 'New Features | ThrillWiki',
})

const { data, pending, error } = await useAsyncData('new-features', () =>
  useNewFeatures().getFeatures()
)
</script>

<template>
  <PageContainer>
    <h1 class="text-3xl font-bold mb-8">New Features</h1>
    
    <div v-if="pending" class="grid grid-cols-1 md:grid-cols-3 gap-6">
      <Skeleton v-for="i in 6" :key="i" class="h-48" />
    </div>
    
    <div v-else-if="data?.results" class="grid grid-cols-1 md:grid-cols-3 gap-6">
      <NewFeatureCard 
        v-for="feature in data.results" 
        :key="feature.id" 
        :feature="feature" 
      />
    </div>
    
    <EmptyState v-else title="No features found" />
  </PageContainer>
</template>
```

### Step 10: Integration Testing

Test the full flow:

1. **API Test**: Verify endpoints with curl or API client
2. **Component Test**: Test components in isolation
3. **E2E Test**: Test complete user journey

```typescript
// frontend/tests/e2e/newFeature.spec.ts
import { test, expect } from '@playwright/test'

test('user can view new features', async ({ page }) => {
  await page.goto('/new-features')
  await expect(page.locator('h1')).toContainText('New Features')
})

test('authenticated user can create feature', async ({ page }) => {
  // Login first
  await page.goto('/auth/login')
  // ... login steps
  
  await page.goto('/new-features/create')
  await page.fill('input[name="name"]', 'Test Feature')
  await page.click('button[type="submit"]')
  
  await expect(page).toHaveURL(/\/new-features\//)
})
```

## Feature Checklist

### Backend
- [ ] Models created with proper fields and indexes
- [ ] Migrations created and applied
- [ ] Serializers handle validation
- [ ] ViewSet has proper permissions
- [ ] Queries are optimized
- [ ] URLs registered
- [ ] Unit tests pass

### Frontend
- [ ] Types defined
- [ ] Composables created for API calls
- [ ] Components follow design system
- [ ] Pages have proper SEO meta
- [ ] Loading states implemented
- [ ] Error states handled
- [ ] Responsive design verified
- [ ] Keyboard accessible

### Integration
- [ ] Data flows correctly between backend and frontend
- [ ] Authentication/authorization works
- [ ] Error handling covers edge cases
- [ ] Performance is acceptable

## Output Summary

After completing the feature:

```markdown
## Feature: [Feature Name]

### Backend
- Model: `apps/[app]/models.py` - NewFeature
- API: `/api/v1/new-features/`
- Permissions: [describe]

### Frontend  
- Page: `/new-features` (list), `/new-features/[id]` (detail)
- Components: NewFeatureCard, NewFeatureForm
- Composable: useNewFeatures

### Tests
- Backend: X tests passing
- Frontend: X tests passing
- E2E: X tests passing

### Notes
- [Any important implementation notes]
- [Known limitations]
- [Future improvements]
```
