@smicolon/ai-kit 0.3.2 → 0.4.0

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.
Files changed (155) hide show
  1. package/README.md +73 -40
  2. package/dist/index.js +260 -126
  3. package/package.json +5 -5
  4. package/.claude-plugin/marketplace.json +0 -369
  5. package/packs/architect/CHANGELOG.md +0 -17
  6. package/packs/architect/README.md +0 -58
  7. package/packs/architect/agents/system-architect.md +0 -768
  8. package/packs/architect/commands/diagram-create.md +0 -300
  9. package/packs/better-auth/.mcp.json +0 -14
  10. package/packs/better-auth/CHANGELOG.md +0 -26
  11. package/packs/better-auth/README.md +0 -125
  12. package/packs/better-auth/agents/auth-architect.md +0 -278
  13. package/packs/better-auth/commands/auth-provider-add.md +0 -265
  14. package/packs/better-auth/commands/auth-setup.md +0 -298
  15. package/packs/better-auth/skills/auth-security/SKILL.md +0 -425
  16. package/packs/better-auth/skills/better-auth-patterns/SKILL.md +0 -455
  17. package/packs/dev-loop/CHANGELOG.md +0 -69
  18. package/packs/dev-loop/README.md +0 -155
  19. package/packs/dev-loop/commands/cancel-dev.md +0 -21
  20. package/packs/dev-loop/commands/dev-loop.md +0 -72
  21. package/packs/dev-loop/commands/dev-plan.md +0 -351
  22. package/packs/dev-loop/hooks/hooks.json +0 -15
  23. package/packs/dev-loop/hooks/stop-hook.sh +0 -178
  24. package/packs/dev-loop/scripts/setup-dev-loop.sh +0 -194
  25. package/packs/dev-loop/skills/tdd-planner/SKILL.md +0 -249
  26. package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +0 -874
  27. package/packs/dev-loop/skills/tdd-planner/references/good-example.md +0 -260
  28. package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +0 -275
  29. package/packs/django/CHANGELOG.md +0 -39
  30. package/packs/django/README.md +0 -92
  31. package/packs/django/agents/django-architect.md +0 -182
  32. package/packs/django/agents/django-builder.md +0 -250
  33. package/packs/django/agents/django-feature-based.md +0 -420
  34. package/packs/django/agents/django-reviewer.md +0 -253
  35. package/packs/django/agents/django-tester.md +0 -230
  36. package/packs/django/commands/api-endpoint.md +0 -285
  37. package/packs/django/commands/model-create.md +0 -178
  38. package/packs/django/commands/test-generate.md +0 -325
  39. package/packs/django/rules/migrations.md +0 -138
  40. package/packs/django/rules/models.md +0 -167
  41. package/packs/django/rules/serializers.md +0 -126
  42. package/packs/django/rules/services.md +0 -131
  43. package/packs/django/rules/tests.md +0 -140
  44. package/packs/django/rules/views.md +0 -102
  45. package/packs/django/skills/import-convention-enforcer/SKILL.md +0 -226
  46. package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +0 -343
  47. package/packs/django/skills/migration-safety-checker/SKILL.md +0 -375
  48. package/packs/django/skills/model-entity-validator/SKILL.md +0 -298
  49. package/packs/django/skills/performance-optimizer/SKILL.md +0 -447
  50. package/packs/django/skills/red-phase-verifier/SKILL.md +0 -180
  51. package/packs/django/skills/security-first-validator/SKILL.md +0 -435
  52. package/packs/django/skills/test-coverage-advisor/SKILL.md +0 -394
  53. package/packs/django/skills/test-validity-checker/SKILL.md +0 -194
  54. package/packs/failure-log/CHANGELOG.md +0 -20
  55. package/packs/failure-log/README.md +0 -168
  56. package/packs/failure-log/commands/failure-add.md +0 -106
  57. package/packs/failure-log/commands/failure-list.md +0 -89
  58. package/packs/failure-log/hooks/hooks.json +0 -16
  59. package/packs/failure-log/hooks/scripts/inject-failures.sh +0 -64
  60. package/packs/failure-log/skills/failure-log-manager/SKILL.md +0 -164
  61. package/packs/flutter/CHANGELOG.md +0 -19
  62. package/packs/flutter/README.md +0 -170
  63. package/packs/flutter/agents/flutter-architect.md +0 -166
  64. package/packs/flutter/agents/flutter-builder.md +0 -303
  65. package/packs/flutter/agents/release-manager.md +0 -355
  66. package/packs/flutter/commands/fastlane-setup.md +0 -188
  67. package/packs/flutter/commands/flutter-build.md +0 -90
  68. package/packs/flutter/commands/flutter-deploy.md +0 -133
  69. package/packs/flutter/commands/flutter-test.md +0 -117
  70. package/packs/flutter/commands/signing-setup.md +0 -209
  71. package/packs/flutter/hooks/hooks.json +0 -17
  72. package/packs/flutter/skills/fastlane-knowledge/SKILL.md +0 -193
  73. package/packs/flutter/skills/flutter-architecture/SKILL.md +0 -127
  74. package/packs/flutter/skills/store-publishing/SKILL.md +0 -163
  75. package/packs/hono/CHANGELOG.md +0 -19
  76. package/packs/hono/README.md +0 -143
  77. package/packs/hono/agents/hono-architect.md +0 -240
  78. package/packs/hono/agents/hono-builder.md +0 -285
  79. package/packs/hono/agents/hono-reviewer.md +0 -279
  80. package/packs/hono/agents/hono-tester.md +0 -346
  81. package/packs/hono/commands/middleware-create.md +0 -223
  82. package/packs/hono/commands/project-init.md +0 -306
  83. package/packs/hono/commands/route-create.md +0 -153
  84. package/packs/hono/commands/rpc-client.md +0 -263
  85. package/packs/hono/skills/cloudflare-bindings/SKILL.md +0 -408
  86. package/packs/hono/skills/hono-patterns/SKILL.md +0 -309
  87. package/packs/hono/skills/rpc-typesafe/SKILL.md +0 -388
  88. package/packs/hono/skills/zod-validation/SKILL.md +0 -332
  89. package/packs/nestjs/CHANGELOG.md +0 -29
  90. package/packs/nestjs/README.md +0 -75
  91. package/packs/nestjs/agents/nestjs-architect.md +0 -402
  92. package/packs/nestjs/agents/nestjs-builder.md +0 -301
  93. package/packs/nestjs/agents/nestjs-tester.md +0 -437
  94. package/packs/nestjs/commands/module-create.md +0 -369
  95. package/packs/nestjs/rules/controllers.md +0 -92
  96. package/packs/nestjs/rules/dto.md +0 -124
  97. package/packs/nestjs/rules/entities.md +0 -102
  98. package/packs/nestjs/rules/services.md +0 -106
  99. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +0 -389
  100. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +0 -365
  101. package/packs/nextjs/CHANGELOG.md +0 -36
  102. package/packs/nextjs/README.md +0 -76
  103. package/packs/nextjs/agents/frontend-tester.md +0 -680
  104. package/packs/nextjs/agents/frontend-visual.md +0 -820
  105. package/packs/nextjs/agents/nextjs-architect.md +0 -331
  106. package/packs/nextjs/agents/nextjs-modular.md +0 -433
  107. package/packs/nextjs/commands/component-create.md +0 -398
  108. package/packs/nextjs/rules/api-routes.md +0 -129
  109. package/packs/nextjs/rules/components.md +0 -106
  110. package/packs/nextjs/rules/hooks.md +0 -132
  111. package/packs/nextjs/skills/accessibility-validator/SKILL.md +0 -445
  112. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +0 -399
  113. package/packs/nextjs/skills/react-form-validator/SKILL.md +0 -569
  114. package/packs/nuxtjs/CHANGELOG.md +0 -30
  115. package/packs/nuxtjs/README.md +0 -56
  116. package/packs/nuxtjs/agents/frontend-tester.md +0 -680
  117. package/packs/nuxtjs/agents/frontend-visual.md +0 -820
  118. package/packs/nuxtjs/agents/nuxtjs-architect.md +0 -537
  119. package/packs/nuxtjs/commands/component-create.md +0 -223
  120. package/packs/nuxtjs/rules/components.md +0 -101
  121. package/packs/nuxtjs/rules/composables.md +0 -118
  122. package/packs/nuxtjs/rules/server-routes.md +0 -127
  123. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +0 -183
  124. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +0 -196
  125. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +0 -190
  126. package/packs/onboard/CHANGELOG.md +0 -22
  127. package/packs/onboard/README.md +0 -103
  128. package/packs/onboard/agents/onboard-guide.md +0 -118
  129. package/packs/onboard/commands/onboard.md +0 -313
  130. package/packs/onboard/skills/onboard-context-provider/SKILL.md +0 -98
  131. package/packs/tanstack-router/CHANGELOG.md +0 -30
  132. package/packs/tanstack-router/README.md +0 -113
  133. package/packs/tanstack-router/agents/tanstack-architect.md +0 -173
  134. package/packs/tanstack-router/agents/tanstack-builder.md +0 -360
  135. package/packs/tanstack-router/agents/tanstack-tester.md +0 -454
  136. package/packs/tanstack-router/commands/form-create.md +0 -313
  137. package/packs/tanstack-router/commands/query-create.md +0 -263
  138. package/packs/tanstack-router/commands/route-create.md +0 -190
  139. package/packs/tanstack-router/commands/table-create.md +0 -413
  140. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +0 -370
  141. package/packs/tanstack-router/skills/db-patterns/SKILL.md +0 -346
  142. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +0 -415
  143. package/packs/tanstack-router/skills/form-patterns/SKILL.md +0 -425
  144. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +0 -341
  145. package/packs/tanstack-router/skills/query-patterns/SKILL.md +0 -359
  146. package/packs/tanstack-router/skills/router-patterns/SKILL.md +0 -285
  147. package/packs/tanstack-router/skills/store-patterns/SKILL.md +0 -351
  148. package/packs/tanstack-router/skills/table-patterns/SKILL.md +0 -531
  149. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +0 -428
  150. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +0 -490
  151. package/packs/worktree/CHANGELOG.md +0 -45
  152. package/packs/worktree/README.md +0 -219
  153. package/packs/worktree/commands/wt.md +0 -93
  154. package/packs/worktree/scripts/wt.sh +0 -957
  155. package/packs/worktree/skills/worktree-manager/SKILL.md +0 -113
@@ -1,325 +0,0 @@
1
- ---
2
- name: test-generate
3
- description: Generate comprehensive tests for Django code (90%+ coverage target)
4
- ---
5
-
6
- # Django Test Generation
7
-
8
- You are a Django testing specialist. Your task is to generate comprehensive tests that achieve 90%+ code coverage following Smicolon standards.
9
-
10
- ## Core Requirements
11
-
12
- ### Import Pattern (CRITICAL)
13
- ```python
14
- # ✅ CORRECT
15
- import users.models as _users_models
16
- import users.services as _users_services
17
- import users.serializers as _users_serializers
18
- from django.test import TestCase
19
- from rest_framework.test import APITestCase, APIClient
20
- ```
21
-
22
- ### Test Categories
23
-
24
- 1. **Model Tests** - Test model methods, constraints, relationships
25
- 2. **Service Tests** - Test business logic, transactions
26
- 3. **API Tests** - Test endpoints, permissions, validation
27
- 4. **Integration Tests** - Test complete workflows
28
-
29
- ## Test Structure
30
-
31
- ### Model Tests
32
- ```python
33
- # app/tests/test_models.py
34
- import users.models as _users_models
35
- from django.test import TestCase
36
- from django.db import IntegrityError
37
-
38
- class ProductModelTest(TestCase):
39
- def setUp(self):
40
- self.product = _models.Product.objects.create(
41
- name='Test Product',
42
- slug='test-product',
43
- description='Test description',
44
- price=99.99,
45
- stock=10
46
- )
47
-
48
- def test_product_creation(self):
49
- """Test product is created with required fields"""
50
- self.assertIsNotNone(self.product.id)
51
- self.assertIsNotNone(self.product.created_at)
52
- self.assertFalse(self.product.is_deleted)
53
-
54
- def test_product_str(self):
55
- """Test string representation"""
56
- self.assertEqual(str(self.product), 'Test Product')
57
-
58
- def test_slug_unique_constraint(self):
59
- """Test slug must be unique"""
60
- with self.assertRaises(IntegrityError):
61
- _models.Product.objects.create(
62
- name='Another Product',
63
- slug='test-product', # Duplicate slug
64
- price=49.99
65
- )
66
-
67
- def test_price_non_negative(self):
68
- """Test price cannot be negative"""
69
- with self.assertRaises(IntegrityError):
70
- _models.Product.objects.create(
71
- name='Invalid Product',
72
- slug='invalid',
73
- price=-10.00
74
- )
75
-
76
- def test_soft_delete(self):
77
- """Test soft delete functionality"""
78
- product_id = self.product.id
79
- self.product.is_deleted = True
80
- self.product.save()
81
-
82
- # Product still exists in database
83
- product = _models.Product.objects.get(id=product_id)
84
- self.assertTrue(product.is_deleted)
85
- ```
86
-
87
- ### Service Tests
88
- ```python
89
- # app/tests/test_services.py
90
- import users.models as _users_models
91
- import users.services as _users_services
92
- from django.test import TestCase, TransactionTestCase
93
- from django.db import transaction
94
-
95
- class ProductServiceTest(TransactionTestCase):
96
- def setUp(self):
97
- self.user = # Create test user
98
-
99
- def test_create_product(self):
100
- """Test product creation through service"""
101
- data = {
102
- 'name': 'New Product',
103
- 'slug': 'new-product',
104
- 'description': 'New description',
105
- 'price': 149.99,
106
- 'stock': 5
107
- }
108
-
109
- product = _services.ProductService.create_product(data, self.user)
110
-
111
- self.assertIsNotNone(product.id)
112
- self.assertEqual(product.name, 'New Product')
113
- self.assertEqual(product.created_by, self.user)
114
-
115
- def test_update_product(self):
116
- """Test product update through service"""
117
- product = _models.Product.objects.create(
118
- name='Original',
119
- slug='original',
120
- price=100.00
121
- )
122
-
123
- data = {'name': 'Updated'}
124
- updated = _services.ProductService.update_product(str(product.id), data)
125
-
126
- self.assertEqual(updated.name, 'Updated')
127
- self.assertEqual(updated.slug, 'original') # Unchanged
128
-
129
- def test_delete_product(self):
130
- """Test soft delete through service"""
131
- product = _models.Product.objects.create(
132
- name='To Delete',
133
- slug='to-delete',
134
- price=50.00
135
- )
136
-
137
- _services.ProductService.delete_product(str(product.id))
138
-
139
- product.refresh_from_db()
140
- self.assertTrue(product.is_deleted)
141
-
142
- def test_transaction_rollback(self):
143
- """Test transaction rollback on error"""
144
- with self.assertRaises(Exception):
145
- with transaction.atomic():
146
- product = _models.Product.objects.create(
147
- name='Test',
148
- slug='test',
149
- price=100.00
150
- )
151
- raise Exception("Simulated error")
152
-
153
- # Product should not exist due to rollback
154
- self.assertEqual(_models.Product.objects.count(), 0)
155
- ```
156
-
157
- ### API Tests
158
- ```python
159
- # app/tests/test_api.py
160
- import users.models as _users_models
161
- from rest_framework.test import APITestCase
162
- from rest_framework import status
163
-
164
- class ProductAPITest(APITestCase):
165
- def setUp(self):
166
- self.user = # Create test user
167
- self.client.force_authenticate(user=self.user)
168
-
169
- self.product = _models.Product.objects.create(
170
- name='Test Product',
171
- slug='test-product',
172
- price=99.99
173
- )
174
-
175
- def test_list_products(self):
176
- """Test listing products"""
177
- response = self.client.get('/api/products/')
178
-
179
- self.assertEqual(response.status_code, status.HTTP_200_OK)
180
- self.assertEqual(len(response.data), 1)
181
-
182
- def test_create_product(self):
183
- """Test creating product via API"""
184
- data = {
185
- 'name': 'New Product',
186
- 'slug': 'new-product',
187
- 'description': 'Description',
188
- 'price': '149.99',
189
- 'stock': 10
190
- }
191
-
192
- response = self.client.post('/api/products/', data)
193
-
194
- self.assertEqual(response.status_code, status.HTTP_201_CREATED)
195
- self.assertEqual(_models.Product.objects.count(), 2)
196
-
197
- def test_create_product_validation_error(self):
198
- """Test validation errors"""
199
- data = {
200
- 'name': 'Invalid',
201
- 'slug': 'invalid',
202
- 'price': '-10.00' # Negative price
203
- }
204
-
205
- response = self.client.post('/api/products/', data)
206
-
207
- self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
208
- self.assertIn('price', response.data)
209
-
210
- def test_update_product(self):
211
- """Test updating product"""
212
- data = {'name': 'Updated Name'}
213
-
214
- response = self.client.patch(
215
- f'/api/products/{self.product.id}/',
216
- data
217
- )
218
-
219
- self.assertEqual(response.status_code, status.HTTP_200_OK)
220
- self.product.refresh_from_db()
221
- self.assertEqual(self.product.name, 'Updated Name')
222
-
223
- def test_delete_product(self):
224
- """Test deleting product"""
225
- response = self.client.delete(f'/api/products/{self.product.id}/')
226
-
227
- self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
228
- self.product.refresh_from_db()
229
- self.assertTrue(self.product.is_deleted)
230
-
231
- def test_permissions_unauthenticated(self):
232
- """Test unauthenticated access is denied"""
233
- self.client.force_authenticate(user=None)
234
-
235
- response = self.client.get('/api/products/')
236
-
237
- self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
238
-
239
- def test_query_optimization(self):
240
- """Test queryset is optimized"""
241
- with self.assertNumQueries(2): # Should use select_related
242
- response = self.client.get('/api/products/')
243
- list(response.data) # Force evaluation
244
- ```
245
-
246
- ### Integration Tests
247
- ```python
248
- # app/tests/test_integration.py
249
- import users.models as _users_models
250
- from rest_framework.test import APITestCase
251
-
252
- class ProductWorkflowTest(APITestCase):
253
- def test_complete_product_lifecycle(self):
254
- """Test complete product creation to deletion workflow"""
255
- user = # Create test user
256
- self.client.force_authenticate(user=user)
257
-
258
- # 1. Create product
259
- create_data = {
260
- 'name': 'Workflow Product',
261
- 'slug': 'workflow-product',
262
- 'price': '99.99',
263
- 'stock': 10
264
- }
265
- create_response = self.client.post('/api/products/', create_data)
266
- product_id = create_response.data['id']
267
-
268
- # 2. Retrieve product
269
- get_response = self.client.get(f'/api/products/{product_id}/')
270
- self.assertEqual(get_response.data['name'], 'Workflow Product')
271
-
272
- # 3. Update product
273
- update_data = {'stock': 20}
274
- self.client.patch(f'/api/products/{product_id}/', update_data)
275
-
276
- # 4. Custom action
277
- restock_data = {'quantity': 5}
278
- self.client.post(f'/api/products/{product_id}/restock/', restock_data)
279
-
280
- # 5. Verify final state
281
- final_response = self.client.get(f'/api/products/{product_id}/')
282
- self.assertEqual(final_response.data['stock'], 25)
283
-
284
- # 6. Delete product
285
- self.client.delete(f'/api/products/{product_id}/')
286
-
287
- # 7. Verify soft delete
288
- product = _models.Product.objects.get(id=product_id)
289
- self.assertTrue(product.is_deleted)
290
- ```
291
-
292
- ## Running Tests
293
-
294
- ```bash
295
- # Run all tests
296
- python manage.py test
297
-
298
- # Run specific test file
299
- python manage.py test app.tests.test_models
300
-
301
- # Run specific test class
302
- python manage.py test app.tests.test_models.ProductModelTest
303
-
304
- # Run with coverage
305
- coverage run --source='.' manage.py test
306
- coverage report
307
- coverage html
308
- ```
309
-
310
- ## Quality Checklist
311
-
312
- - [ ] Model tests (creation, constraints, methods)
313
- - [ ] Service tests (business logic, transactions)
314
- - [ ] API tests (CRUD operations)
315
- - [ ] Permission tests
316
- - [ ] Validation tests
317
- - [ ] Error handling tests
318
- - [ ] Integration tests
319
- - [ ] Edge cases covered
320
- - [ ] Query optimization tests
321
- - [ ] 90%+ code coverage
322
- - [ ] Absolute imports with aliases
323
- - [ ] Clear test names and docstrings
324
-
325
- Now, ask the user what code they want to test!
@@ -1,138 +0,0 @@
1
- ---
2
- paths:
3
- - "**/migrations/**/*.py"
4
- ---
5
-
6
- # Django Migration Standards
7
-
8
- ## Safety First
9
-
10
- Migrations MUST be:
11
- - Reversible
12
- - Non-destructive
13
- - Tested before deployment
14
-
15
- ## Dangerous Operations
16
-
17
- ### Column Removal (3-step process)
18
-
19
- ```python
20
- # Step 1: Make nullable (Migration 1)
21
- migrations.AlterField(
22
- model_name='user',
23
- name='legacy_field',
24
- field=models.CharField(max_length=100, null=True, blank=True),
25
- )
26
-
27
- # Step 2: Deploy code that stops writing to field
28
- # Step 3: Remove field (Migration 2, separate deploy)
29
- migrations.RemoveField(
30
- model_name='user',
31
- name='legacy_field',
32
- )
33
- ```
34
-
35
- ### Type Changes
36
-
37
- ```python
38
- # WRONG - Data loss risk
39
- migrations.AlterField(
40
- model_name='product',
41
- name='price',
42
- field=models.IntegerField(), # Was DecimalField!
43
- )
44
-
45
- # CORRECT - Add new field, migrate data, remove old
46
- migrations.AddField(
47
- model_name='product',
48
- name='price_cents',
49
- field=models.IntegerField(null=True),
50
- )
51
- migrations.RunPython(migrate_price_to_cents, reverse_migrate),
52
- migrations.RemoveField('product', 'price'),
53
- migrations.RenameField('product', 'price_cents', 'price'),
54
- ```
55
-
56
- ## Requirements
57
-
58
- - Always include `reverse_code` for RunPython
59
- - Test migrations: forward AND backward
60
- - Never use `--fake` in production
61
- - Review auto-generated migrations before committing
62
-
63
- ## RunPython Template
64
-
65
- ```python
66
- def migrate_forward(apps, schema_editor):
67
- """
68
- Migration: Convert price to cents.
69
- """
70
- Product = apps.get_model('products', 'Product')
71
- for product in Product.objects.all():
72
- product.price_cents = int(product.price * 100)
73
- product.save(update_fields=['price_cents'])
74
-
75
-
76
- def migrate_backward(apps, schema_editor):
77
- """
78
- Reverse: Convert cents back to price.
79
- """
80
- Product = apps.get_model('products', 'Product')
81
- for product in Product.objects.all():
82
- product.price = product.price_cents / 100
83
- product.save(update_fields=['price'])
84
-
85
-
86
- class Migration(migrations.Migration):
87
- operations = [
88
- migrations.RunPython(migrate_forward, migrate_backward),
89
- ]
90
- ```
91
-
92
- ## Forbidden Patterns
93
-
94
- - `RunPython(migrate_forward, migrations.RunPython.noop)` - Always provide reverse
95
- - `migrations.DeleteModel` without data backup plan
96
- - Large data migrations without batching
97
- - Migrations that lock tables for long periods
98
-
99
- ## Large Table Migrations
100
-
101
- For tables with >1M rows:
102
-
103
- ```python
104
- def migrate_in_batches(apps, schema_editor):
105
- """Migrate data in batches to avoid lock timeouts."""
106
- Product = apps.get_model('products', 'Product')
107
- batch_size = 1000
108
- total = Product.objects.count()
109
-
110
- for start in range(0, total, batch_size):
111
- batch = Product.objects.all()[start:start + batch_size]
112
- for product in batch:
113
- product.new_field = transform(product.old_field)
114
- Product.objects.bulk_update(batch, ['new_field'])
115
- ```
116
-
117
- ## Migration Naming
118
-
119
- Use descriptive names:
120
-
121
- ```bash
122
- # GOOD
123
- python manage.py makemigrations --name add_email_verified_field
124
- python manage.py makemigrations --name remove_legacy_status_column
125
-
126
- # BAD (auto-generated)
127
- 0023_auto_20241201_1234.py
128
- ```
129
-
130
- ## Pre-Deployment Checklist
131
-
132
- - [ ] Migration is reversible
133
- - [ ] Tested forward migration locally
134
- - [ ] Tested backward migration locally
135
- - [ ] No destructive operations without 3-step process
136
- - [ ] Large tables use batching
137
- - [ ] RunPython has reverse_code
138
- - [ ] Migration name is descriptive
@@ -1,167 +0,0 @@
1
- ---
2
- paths:
3
- - "**/models.py"
4
- - "**/models/*.py"
5
- ---
6
-
7
- # Django Model Standards
8
-
9
- ## BaseModel Pattern (MANDATORY)
10
-
11
- All models MUST inherit from `BaseModel`. Never repeat UUID/timestamp fields.
12
-
13
- ### Step 1: Ensure BaseModel Exists
14
-
15
- Check for BaseModel in your project (usually in `core/models.py` or `shared/models.py`):
16
-
17
- ```python
18
- # core/models.py
19
- import uuid
20
- from django.db import models
21
-
22
- class BaseModel(models.Model):
23
- """
24
- Abstract base model providing:
25
- - UUID primary key
26
- - Automatic timestamps (created_at, updated_at)
27
- - Soft delete support (is_deleted)
28
-
29
- All models MUST inherit from this class.
30
- """
31
-
32
- id = models.UUIDField(
33
- primary_key=True,
34
- default=uuid.uuid4,
35
- editable=False
36
- )
37
- created_at = models.DateTimeField(auto_now_add=True)
38
- updated_at = models.DateTimeField(auto_now=True)
39
- is_deleted = models.BooleanField(default=False)
40
-
41
- class Meta:
42
- abstract = True
43
- ordering = ['-created_at']
44
-
45
- def soft_delete(self) -> None:
46
- """Soft delete the record."""
47
- self.is_deleted = True
48
- self.save(update_fields=['is_deleted', 'updated_at'])
49
-
50
- def restore(self) -> None:
51
- """Restore a soft-deleted record."""
52
- self.is_deleted = False
53
- self.save(update_fields=['is_deleted', 'updated_at'])
54
- ```
55
-
56
- ### Step 2: Inherit from BaseModel
57
-
58
- ```python
59
- # users/models.py
60
- from django.db import models
61
- import core.models as _core_models
62
-
63
- class User(_core_models.BaseModel):
64
- """User model - inherits id, timestamps, soft delete from BaseModel."""
65
-
66
- email = models.EmailField(unique=True, db_index=True)
67
- first_name = models.CharField(max_length=100)
68
- last_name = models.CharField(max_length=100)
69
-
70
- class Meta:
71
- db_table = 'users'
72
- verbose_name = 'User'
73
- verbose_name_plural = 'Users'
74
- ```
75
-
76
- ## Wrong vs Right
77
-
78
- ```python
79
- # ❌ WRONG - Repeating fields that should come from BaseModel
80
- class Product(models.Model):
81
- id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
82
- created_at = models.DateTimeField(auto_now_add=True)
83
- updated_at = models.DateTimeField(auto_now=True)
84
- is_deleted = models.BooleanField(default=False)
85
- name = models.CharField(max_length=255)
86
-
87
- # ✅ CORRECT - Inherit from BaseModel
88
- import core.models as _core_models
89
-
90
- class Product(_core_models.BaseModel):
91
- """Product model."""
92
- name = models.CharField(max_length=255)
93
- price = models.DecimalField(max_digits=10, decimal_places=2)
94
-
95
- class Meta:
96
- db_table = 'products'
97
- ```
98
-
99
- ## Import Pattern
100
-
101
- ```python
102
- # ✅ CORRECT - Absolute import with alias
103
- import core.models as _core_models
104
-
105
- class MyModel(_core_models.BaseModel):
106
- pass
107
-
108
- # ❌ WRONG - Relative import
109
- from .base import BaseModel
110
- ```
111
-
112
- ## Custom Managers
113
-
114
- For soft delete support:
115
-
116
- ```python
117
- class ActiveManager(models.Manager):
118
- def get_queryset(self):
119
- return super().get_queryset().filter(is_deleted=False)
120
-
121
- class Product(_core_models.BaseModel):
122
- name = models.CharField(max_length=255)
123
-
124
- objects = ActiveManager() # Default: excludes deleted
125
- all_objects = models.Manager() # Include deleted
126
- ```
127
-
128
- ## Field Naming Conventions
129
-
130
- - Use snake_case for all field names
131
- - Boolean fields: `is_*` or `has_*` prefix
132
- - DateTime fields: `*_at` suffix
133
- - Foreign keys: descriptive name (not `{model}_id`)
134
-
135
- ```python
136
- # ✅ CORRECT
137
- is_active = models.BooleanField()
138
- published_at = models.DateTimeField()
139
- author = models.ForeignKey(User, on_delete=models.CASCADE)
140
-
141
- # ❌ WRONG
142
- active = models.BooleanField() # No prefix
143
- publishedAt = models.DateTimeField() # camelCase
144
- ```
145
-
146
- ## Meta Options
147
-
148
- Always define:
149
-
150
- ```python
151
- class Meta:
152
- db_table = 'products' # Explicit table name
153
- ordering = ['-created_at'] # Default ordering
154
- verbose_name = 'Product'
155
- verbose_name_plural = 'Products'
156
- indexes = [
157
- models.Index(fields=['name']),
158
- ]
159
- ```
160
-
161
- ## Forbidden Patterns
162
-
163
- - `models.AutoField` - BaseModel uses UUID
164
- - `id = models.UUIDField(...)` in non-base models - Inherit from BaseModel
165
- - `created_at = ...` in non-base models - Inherit from BaseModel
166
- - Hard deletes - Use `soft_delete()` method
167
- - Business logic in models - Use service layer