mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 15:55:19 -05:00
312 lines
7.4 KiB
Markdown
312 lines
7.4 KiB
Markdown
---
|
|
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]
|
|
```
|