@su-record/vibe 2.4.72 → 2.4.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +216 -215
- package/README.md +4 -4
- package/agents/research/best-practices-agent.md +13 -13
- package/agents/research/codebase-patterns-agent.md +33 -33
- package/agents/research/framework-docs-agent.md +23 -23
- package/agents/research/security-advisory-agent.md +29 -29
- package/agents/review/architecture-reviewer.md +31 -31
- package/agents/review/complexity-reviewer.md +21 -21
- package/agents/review/data-integrity-reviewer.md +29 -29
- package/agents/review/git-history-reviewer.md +24 -24
- package/agents/review/performance-reviewer.md +29 -29
- package/agents/review/python-reviewer.md +53 -53
- package/agents/review/rails-reviewer.md +40 -40
- package/agents/review/react-reviewer.md +40 -40
- package/agents/review/security-reviewer.md +29 -29
- package/agents/review/simplicity-reviewer.md +24 -24
- package/agents/review/test-coverage-reviewer.md +31 -31
- package/agents/review/typescript-reviewer.md +41 -41
- package/commands/vibe.analyze.md +103 -7
- package/commands/vibe.reason.md +106 -0
- package/commands/vibe.review.md +123 -38
- package/commands/vibe.run.md +286 -221
- package/commands/vibe.spec.md +290 -175
- package/commands/vibe.utils.md +104 -3
- package/commands/vibe.verify.md +179 -86
- package/dist/cli/detect.js +40 -40
- package/dist/cli/detect.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/llm.js +5 -5
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/setup.js +3 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/lib/ContextCompressor.js +1 -1
- package/dist/lib/ContextCompressor.js.map +1 -1
- package/dist/lib/gemini-api.js +12 -12
- package/dist/lib/gemini-api.js.map +1 -1
- package/dist/lib/gemini-oauth.js +22 -22
- package/dist/lib/gemini-oauth.js.map +1 -1
- package/dist/lib/gemini-storage.js +3 -3
- package/dist/lib/gemini-storage.js.map +1 -1
- package/dist/lib/gpt-api.js +11 -11
- package/dist/lib/gpt-api.js.map +1 -1
- package/dist/lib/gpt-oauth.js +28 -28
- package/dist/lib/gpt-oauth.js.map +1 -1
- package/dist/lib/gpt-storage.js +3 -3
- package/dist/lib/gpt-storage.js.map +1 -1
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +4 -6
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/tools/convention/analyzeComplexity.js +3 -3
- package/dist/tools/convention/analyzeComplexity.js.map +1 -1
- package/dist/tools/convention/applyQualityRules.js +1 -1
- package/dist/tools/convention/applyQualityRules.js.map +1 -1
- package/dist/tools/convention/checkCouplingCohesion.js +2 -2
- package/dist/tools/convention/checkCouplingCohesion.js.map +1 -1
- package/dist/tools/convention/suggestImprovements.js +1 -1
- package/dist/tools/convention/suggestImprovements.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.js +1 -1
- package/dist/tools/convention/validateCodeQuality.js.map +1 -1
- package/dist/tools/memory/autoSaveContext.js +1 -1
- package/dist/tools/memory/autoSaveContext.js.map +1 -1
- package/dist/tools/memory/createMemoryTimeline.js +27 -27
- package/dist/tools/memory/createMemoryTimeline.js.map +1 -1
- package/dist/tools/memory/deleteMemory.js +1 -1
- package/dist/tools/memory/deleteMemory.js.map +1 -1
- package/dist/tools/memory/getMemoryGraph.js +24 -24
- package/dist/tools/memory/getMemoryGraph.js.map +1 -1
- package/dist/tools/memory/getSessionContext.js +36 -36
- package/dist/tools/memory/getSessionContext.js.map +1 -1
- package/dist/tools/memory/linkMemories.js +21 -21
- package/dist/tools/memory/linkMemories.js.map +1 -1
- package/dist/tools/memory/prioritizeMemory.js +1 -1
- package/dist/tools/memory/prioritizeMemory.js.map +1 -1
- package/dist/tools/memory/restoreSessionContext.js +1 -1
- package/dist/tools/memory/restoreSessionContext.js.map +1 -1
- package/dist/tools/memory/searchMemories.js +1 -1
- package/dist/tools/memory/searchMemories.js.map +1 -1
- package/dist/tools/memory/searchMemoriesAdvanced.js +42 -42
- package/dist/tools/memory/searchMemoriesAdvanced.js.map +1 -1
- package/dist/tools/memory/startSession.js +2 -2
- package/dist/tools/memory/startSession.js.map +1 -1
- package/dist/tools/memory/updateMemory.js +1 -1
- package/dist/tools/memory/updateMemory.js.map +1 -1
- package/dist/tools/semantic/analyzeDependencyGraph.js +38 -38
- package/dist/tools/semantic/analyzeDependencyGraph.js.map +1 -1
- package/dist/tools/semantic/findReferences.js +1 -1
- package/dist/tools/semantic/findReferences.js.map +1 -1
- package/dist/tools/semantic/findSymbol.js +1 -1
- package/dist/tools/semantic/findSymbol.js.map +1 -1
- package/dist/tools/time/getCurrentTime.js +1 -1
- package/dist/tools/time/getCurrentTime.js.map +1 -1
- package/dist/tools/ui/previewUiAscii.js +2 -2
- package/dist/tools/ui/previewUiAscii.js.map +1 -1
- package/hooks/hooks.json +11 -2
- package/hooks/scripts/llm-orchestrate.js +1 -1
- package/hooks/scripts/utils.js +31 -6
- package/languages/csharp-unity.md +82 -83
- package/languages/dart-flutter.md +89 -88
- package/languages/go.md +76 -75
- package/languages/java-spring.md +85 -84
- package/languages/kotlin-android.md +64 -63
- package/languages/python-django.md +83 -82
- package/languages/python-fastapi.md +82 -81
- package/languages/rust.md +75 -74
- package/languages/swift-ios.md +73 -72
- package/languages/typescript-electron.md +70 -71
- package/languages/typescript-nextjs.md +93 -92
- package/languages/typescript-node.md +64 -63
- package/languages/typescript-nuxt.md +113 -112
- package/languages/typescript-react-native.md +82 -81
- package/languages/typescript-react.md +76 -75
- package/languages/typescript-tauri.md +74 -75
- package/languages/typescript-vue.md +73 -72
- package/package.json +1 -1
- package/skills/git-worktree.md +25 -25
- package/skills/multi-llm-orchestration.md +4 -6
- package/skills/priority-todos.md +39 -39
- package/skills/vibe-capabilities.md +2 -2
- package/vibe/config.json +2 -2
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Python + Django Quality Rules
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Core Principles (inherited from core)
|
|
4
4
|
|
|
5
5
|
```markdown
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
# Core Principles (inherited from core)
|
|
7
|
+
Single Responsibility (SRP)
|
|
8
|
+
No Duplication (DRY)
|
|
9
|
+
Reusability
|
|
10
|
+
Low Complexity
|
|
11
|
+
Function <= 30 lines
|
|
12
|
+
Nesting <= 3 levels
|
|
13
|
+
Cyclomatic complexity <= 10
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
## Django
|
|
16
|
+
## Django Specific Rules
|
|
16
17
|
|
|
17
|
-
### 1. Model
|
|
18
|
+
### 1. Model Design
|
|
18
19
|
|
|
19
20
|
```python
|
|
20
|
-
#
|
|
21
|
+
# Good: models.py
|
|
21
22
|
from django.db import models
|
|
22
23
|
from django.contrib.auth.models import AbstractUser
|
|
23
24
|
from django.utils import timezone
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class BaseModel(models.Model):
|
|
27
|
-
"""
|
|
28
|
+
"""Abstract model with common fields"""
|
|
28
29
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
29
30
|
updated_at = models.DateTimeField(auto_now=True)
|
|
30
31
|
|
|
@@ -33,7 +34,7 @@ class BaseModel(models.Model):
|
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
class User(AbstractUser):
|
|
36
|
-
"""
|
|
37
|
+
"""Custom user model"""
|
|
37
38
|
email = models.EmailField(unique=True)
|
|
38
39
|
phone = models.CharField(max_length=20, blank=True)
|
|
39
40
|
profile_image = models.ImageField(upload_to='profiles/', blank=True)
|
|
@@ -43,46 +44,46 @@ class User(AbstractUser):
|
|
|
43
44
|
|
|
44
45
|
class Meta:
|
|
45
46
|
db_table = 'users'
|
|
46
|
-
verbose_name = '
|
|
47
|
-
verbose_name_plural = '
|
|
47
|
+
verbose_name = 'User'
|
|
48
|
+
verbose_name_plural = 'Users'
|
|
48
49
|
|
|
49
50
|
def __str__(self):
|
|
50
51
|
return self.email
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class Post(BaseModel):
|
|
54
|
-
"""
|
|
55
|
+
"""Post model"""
|
|
55
56
|
author = models.ForeignKey(
|
|
56
57
|
User,
|
|
57
58
|
on_delete=models.CASCADE,
|
|
58
59
|
related_name='posts',
|
|
59
|
-
verbose_name='
|
|
60
|
+
verbose_name='Author'
|
|
60
61
|
)
|
|
61
|
-
title = models.CharField(max_length=200, verbose_name='
|
|
62
|
-
content = models.TextField(verbose_name='
|
|
63
|
-
is_published = models.BooleanField(default=False, verbose_name='
|
|
62
|
+
title = models.CharField(max_length=200, verbose_name='Title')
|
|
63
|
+
content = models.TextField(verbose_name='Content')
|
|
64
|
+
is_published = models.BooleanField(default=False, verbose_name='Published')
|
|
64
65
|
published_at = models.DateTimeField(null=True, blank=True)
|
|
65
66
|
|
|
66
67
|
class Meta:
|
|
67
68
|
db_table = 'posts'
|
|
68
69
|
ordering = ['-created_at']
|
|
69
|
-
verbose_name = '
|
|
70
|
-
verbose_name_plural = '
|
|
70
|
+
verbose_name = 'Post'
|
|
71
|
+
verbose_name_plural = 'Posts'
|
|
71
72
|
|
|
72
73
|
def __str__(self):
|
|
73
74
|
return self.title
|
|
74
75
|
|
|
75
76
|
def publish(self):
|
|
76
|
-
"""
|
|
77
|
+
"""Publish the post"""
|
|
77
78
|
self.is_published = True
|
|
78
79
|
self.published_at = timezone.now()
|
|
79
80
|
self.save(update_fields=['is_published', 'published_at'])
|
|
80
81
|
```
|
|
81
82
|
|
|
82
|
-
### 2. View (Class-Based Views
|
|
83
|
+
### 2. View (Class-Based Views Recommended)
|
|
83
84
|
|
|
84
85
|
```python
|
|
85
|
-
#
|
|
86
|
+
# Good: views.py
|
|
86
87
|
from django.views.generic import ListView, DetailView, CreateView, UpdateView
|
|
87
88
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
88
89
|
from django.urls import reverse_lazy
|
|
@@ -91,7 +92,7 @@ from .forms import PostForm
|
|
|
91
92
|
|
|
92
93
|
|
|
93
94
|
class PostListView(ListView):
|
|
94
|
-
"""
|
|
95
|
+
"""Post list view"""
|
|
95
96
|
model = Post
|
|
96
97
|
template_name = 'posts/list.html'
|
|
97
98
|
context_object_name = 'posts'
|
|
@@ -103,7 +104,7 @@ class PostListView(ListView):
|
|
|
103
104
|
|
|
104
105
|
|
|
105
106
|
class PostDetailView(DetailView):
|
|
106
|
-
"""
|
|
107
|
+
"""Post detail view"""
|
|
107
108
|
model = Post
|
|
108
109
|
template_name = 'posts/detail.html'
|
|
109
110
|
context_object_name = 'post'
|
|
@@ -113,7 +114,7 @@ class PostDetailView(DetailView):
|
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
class PostCreateView(LoginRequiredMixin, CreateView):
|
|
116
|
-
"""
|
|
117
|
+
"""Post creation view"""
|
|
117
118
|
model = Post
|
|
118
119
|
form_class = PostForm
|
|
119
120
|
template_name = 'posts/form.html'
|
|
@@ -127,13 +128,13 @@ class PostCreateView(LoginRequiredMixin, CreateView):
|
|
|
127
128
|
### 3. Django REST Framework
|
|
128
129
|
|
|
129
130
|
```python
|
|
130
|
-
#
|
|
131
|
+
# Good: serializers.py
|
|
131
132
|
from rest_framework import serializers
|
|
132
133
|
from .models import Post, User
|
|
133
134
|
|
|
134
135
|
|
|
135
136
|
class UserSerializer(serializers.ModelSerializer):
|
|
136
|
-
"""
|
|
137
|
+
"""User serializer"""
|
|
137
138
|
class Meta:
|
|
138
139
|
model = User
|
|
139
140
|
fields = ['id', 'email', 'username', 'profile_image']
|
|
@@ -141,7 +142,7 @@ class UserSerializer(serializers.ModelSerializer):
|
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
class PostSerializer(serializers.ModelSerializer):
|
|
144
|
-
"""
|
|
145
|
+
"""Post serializer"""
|
|
145
146
|
author = UserSerializer(read_only=True)
|
|
146
147
|
author_id = serializers.PrimaryKeyRelatedField(
|
|
147
148
|
queryset=User.objects.all(),
|
|
@@ -159,11 +160,11 @@ class PostSerializer(serializers.ModelSerializer):
|
|
|
159
160
|
|
|
160
161
|
def validate_title(self, value):
|
|
161
162
|
if len(value) < 5:
|
|
162
|
-
raise serializers.ValidationError('
|
|
163
|
+
raise serializers.ValidationError('Title must be at least 5 characters')
|
|
163
164
|
return value
|
|
164
165
|
|
|
165
166
|
|
|
166
|
-
#
|
|
167
|
+
# Good: views.py (DRF)
|
|
167
168
|
from rest_framework import viewsets, permissions, status
|
|
168
169
|
from rest_framework.decorators import action
|
|
169
170
|
from rest_framework.response import Response
|
|
@@ -171,7 +172,7 @@ from django_filters.rest_framework import DjangoFilterBackend
|
|
|
171
172
|
|
|
172
173
|
|
|
173
174
|
class PostViewSet(viewsets.ModelViewSet):
|
|
174
|
-
"""
|
|
175
|
+
"""Post ViewSet"""
|
|
175
176
|
queryset = Post.objects.all()
|
|
176
177
|
serializer_class = PostSerializer
|
|
177
178
|
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
|
@@ -187,34 +188,34 @@ class PostViewSet(viewsets.ModelViewSet):
|
|
|
187
188
|
|
|
188
189
|
@action(detail=True, methods=['post'])
|
|
189
190
|
def publish(self, request, pk=None):
|
|
190
|
-
"""
|
|
191
|
+
"""Publish post action"""
|
|
191
192
|
post = self.get_object()
|
|
192
193
|
|
|
193
194
|
if post.author != request.user:
|
|
194
195
|
return Response(
|
|
195
|
-
{'error': '
|
|
196
|
+
{'error': 'Only the author can publish'},
|
|
196
197
|
status=status.HTTP_403_FORBIDDEN
|
|
197
198
|
)
|
|
198
199
|
|
|
199
200
|
post.publish()
|
|
200
|
-
return Response({'status': '
|
|
201
|
+
return Response({'status': 'Published'})
|
|
201
202
|
```
|
|
202
203
|
|
|
203
|
-
### 4. Service
|
|
204
|
+
### 4. Service Layer (Prevent Fat Model)
|
|
204
205
|
|
|
205
206
|
```python
|
|
206
|
-
#
|
|
207
|
+
# Good: services/post_service.py
|
|
207
208
|
from django.db import transaction
|
|
208
209
|
from django.core.exceptions import PermissionDenied
|
|
209
210
|
from ..models import Post, User
|
|
210
211
|
|
|
211
212
|
|
|
212
213
|
class PostService:
|
|
213
|
-
"""
|
|
214
|
+
"""Post business logic"""
|
|
214
215
|
|
|
215
216
|
@staticmethod
|
|
216
217
|
def create_post(author: User, title: str, content: str) -> Post:
|
|
217
|
-
"""
|
|
218
|
+
"""Create post"""
|
|
218
219
|
post = Post.objects.create(
|
|
219
220
|
author=author,
|
|
220
221
|
title=title,
|
|
@@ -224,9 +225,9 @@ class PostService:
|
|
|
224
225
|
|
|
225
226
|
@staticmethod
|
|
226
227
|
def publish_post(post: Post, user: User) -> Post:
|
|
227
|
-
"""
|
|
228
|
+
"""Publish post"""
|
|
228
229
|
if post.author != user:
|
|
229
|
-
raise PermissionDenied('
|
|
230
|
+
raise PermissionDenied('Only the author can publish')
|
|
230
231
|
|
|
231
232
|
post.publish()
|
|
232
233
|
return post
|
|
@@ -234,7 +235,7 @@ class PostService:
|
|
|
234
235
|
@staticmethod
|
|
235
236
|
@transaction.atomic
|
|
236
237
|
def bulk_publish(post_ids: list[int], user: User) -> int:
|
|
237
|
-
"""
|
|
238
|
+
"""Bulk publish multiple posts"""
|
|
238
239
|
posts = Post.objects.filter(
|
|
239
240
|
id__in=post_ids,
|
|
240
241
|
author=user,
|
|
@@ -248,24 +249,24 @@ class PostService:
|
|
|
248
249
|
return count
|
|
249
250
|
```
|
|
250
251
|
|
|
251
|
-
### 5. Form
|
|
252
|
+
### 5. Form and Validation
|
|
252
253
|
|
|
253
254
|
```python
|
|
254
|
-
#
|
|
255
|
+
# Good: forms.py
|
|
255
256
|
from django import forms
|
|
256
257
|
from django.core.exceptions import ValidationError
|
|
257
258
|
from .models import Post
|
|
258
259
|
|
|
259
260
|
|
|
260
261
|
class PostForm(forms.ModelForm):
|
|
261
|
-
"""
|
|
262
|
+
"""Post form"""
|
|
262
263
|
class Meta:
|
|
263
264
|
model = Post
|
|
264
265
|
fields = ['title', 'content', 'is_published']
|
|
265
266
|
widgets = {
|
|
266
267
|
'title': forms.TextInput(attrs={
|
|
267
268
|
'class': 'form-control',
|
|
268
|
-
'placeholder': '
|
|
269
|
+
'placeholder': 'Enter title'
|
|
269
270
|
}),
|
|
270
271
|
'content': forms.Textarea(attrs={
|
|
271
272
|
'class': 'form-control',
|
|
@@ -276,7 +277,7 @@ class PostForm(forms.ModelForm):
|
|
|
276
277
|
def clean_title(self):
|
|
277
278
|
title = self.cleaned_data.get('title')
|
|
278
279
|
if len(title) < 5:
|
|
279
|
-
raise ValidationError('
|
|
280
|
+
raise ValidationError('Title must be at least 5 characters')
|
|
280
281
|
return title
|
|
281
282
|
|
|
282
283
|
def clean(self):
|
|
@@ -285,20 +286,20 @@ class PostForm(forms.ModelForm):
|
|
|
285
286
|
content = cleaned_data.get('content')
|
|
286
287
|
|
|
287
288
|
if title and content and title in content:
|
|
288
|
-
raise ValidationError('
|
|
289
|
+
raise ValidationError('Content should not contain the title')
|
|
289
290
|
|
|
290
291
|
return cleaned_data
|
|
291
292
|
```
|
|
292
293
|
|
|
293
|
-
### 6. Custom Manager
|
|
294
|
+
### 6. Custom Manager and QuerySet
|
|
294
295
|
|
|
295
296
|
```python
|
|
296
|
-
#
|
|
297
|
+
# Good: managers.py
|
|
297
298
|
from django.db import models
|
|
298
299
|
|
|
299
300
|
|
|
300
301
|
class PostQuerySet(models.QuerySet):
|
|
301
|
-
"""
|
|
302
|
+
"""Post QuerySet"""
|
|
302
303
|
|
|
303
304
|
def published(self):
|
|
304
305
|
return self.filter(is_published=True)
|
|
@@ -314,7 +315,7 @@ class PostQuerySet(models.QuerySet):
|
|
|
314
315
|
|
|
315
316
|
|
|
316
317
|
class PostManager(models.Manager):
|
|
317
|
-
"""
|
|
318
|
+
"""Post Manager"""
|
|
318
319
|
|
|
319
320
|
def get_queryset(self):
|
|
320
321
|
return PostQuerySet(self.model, using=self._db)
|
|
@@ -326,46 +327,46 @@ class PostManager(models.Manager):
|
|
|
326
327
|
return self.get_queryset().by_author(user)
|
|
327
328
|
|
|
328
329
|
|
|
329
|
-
#
|
|
330
|
+
# Use in model
|
|
330
331
|
class Post(BaseModel):
|
|
331
332
|
# ... fields ...
|
|
332
333
|
objects = PostManager()
|
|
333
334
|
```
|
|
334
335
|
|
|
335
|
-
##
|
|
336
|
+
## File Structure
|
|
336
337
|
|
|
337
|
-
```
|
|
338
|
+
```text
|
|
338
339
|
app_name/
|
|
339
|
-
├── migrations/ # DB
|
|
340
|
+
├── migrations/ # DB migrations
|
|
340
341
|
├── management/
|
|
341
|
-
│ └── commands/ #
|
|
342
|
-
├── services/ #
|
|
342
|
+
│ └── commands/ # Custom commands
|
|
343
|
+
├── services/ # Business logic
|
|
343
344
|
├── api/
|
|
344
|
-
│ ├── serializers.py # DRF
|
|
345
|
-
│ ├── views.py # DRF
|
|
346
|
-
│ └── urls.py # API
|
|
347
|
-
├── templates/ # HTML
|
|
348
|
-
├── static/ #
|
|
345
|
+
│ ├── serializers.py # DRF serializers
|
|
346
|
+
│ ├── views.py # DRF views
|
|
347
|
+
│ └── urls.py # API routing
|
|
348
|
+
├── templates/ # HTML templates
|
|
349
|
+
├── static/ # Static files
|
|
349
350
|
├── tests/
|
|
350
351
|
│ ├── test_models.py
|
|
351
352
|
│ ├── test_views.py
|
|
352
353
|
│ └── test_services.py
|
|
353
|
-
├── models.py #
|
|
354
|
-
├── views.py #
|
|
355
|
-
├── forms.py #
|
|
356
|
-
├── managers.py #
|
|
357
|
-
├── admin.py # Admin
|
|
358
|
-
├── urls.py # URL
|
|
359
|
-
└── apps.py #
|
|
354
|
+
├── models.py # Models (or models/ directory)
|
|
355
|
+
├── views.py # Views
|
|
356
|
+
├── forms.py # Forms
|
|
357
|
+
├── managers.py # Custom managers
|
|
358
|
+
├── admin.py # Admin configuration
|
|
359
|
+
├── urls.py # URL routing
|
|
360
|
+
└── apps.py # App configuration
|
|
360
361
|
```
|
|
361
362
|
|
|
362
|
-
##
|
|
363
|
+
## Checklist
|
|
363
364
|
|
|
364
|
-
- [ ]
|
|
365
|
-
- [ ] CBV
|
|
366
|
-
- [ ]
|
|
367
|
-
- [ ]
|
|
368
|
-
- [ ] DRF Serializer
|
|
369
|
-
- [ ] Custom Manager/QuerySet
|
|
370
|
-
- [ ] Type hints
|
|
371
|
-
- [ ]
|
|
365
|
+
- [ ] Define `__str__`, `Meta` in Model
|
|
366
|
+
- [ ] Use CBV (recommended)
|
|
367
|
+
- [ ] Separate business logic with Service layer
|
|
368
|
+
- [ ] Prevent N+1 with select_related/prefetch_related
|
|
369
|
+
- [ ] Validate input/output with DRF Serializer
|
|
370
|
+
- [ ] Use Custom Manager/QuerySet
|
|
371
|
+
- [ ] Use Type hints (Python 3.10+)
|
|
372
|
+
- [ ] Set verbose_name for fields
|