mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 09:45:17 -05:00
lol
This commit is contained in:
311
.agent/workflows/new-feature.md
Normal file
311
.agent/workflows/new-feature.md
Normal file
@@ -0,0 +1,311 @@
|
||||
---
|
||||
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]
|
||||
```
|
||||
Reference in New Issue
Block a user