@smicolon/ai-kit 0.3.1 → 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 (156) 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 -373
  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/hooks/hooks.json +0 -4
  86. package/packs/hono/skills/cloudflare-bindings/SKILL.md +0 -408
  87. package/packs/hono/skills/hono-patterns/SKILL.md +0 -309
  88. package/packs/hono/skills/rpc-typesafe/SKILL.md +0 -388
  89. package/packs/hono/skills/zod-validation/SKILL.md +0 -332
  90. package/packs/nestjs/CHANGELOG.md +0 -29
  91. package/packs/nestjs/README.md +0 -75
  92. package/packs/nestjs/agents/nestjs-architect.md +0 -402
  93. package/packs/nestjs/agents/nestjs-builder.md +0 -301
  94. package/packs/nestjs/agents/nestjs-tester.md +0 -437
  95. package/packs/nestjs/commands/module-create.md +0 -369
  96. package/packs/nestjs/rules/controllers.md +0 -92
  97. package/packs/nestjs/rules/dto.md +0 -124
  98. package/packs/nestjs/rules/entities.md +0 -102
  99. package/packs/nestjs/rules/services.md +0 -106
  100. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +0 -389
  101. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +0 -365
  102. package/packs/nextjs/CHANGELOG.md +0 -36
  103. package/packs/nextjs/README.md +0 -76
  104. package/packs/nextjs/agents/frontend-tester.md +0 -680
  105. package/packs/nextjs/agents/frontend-visual.md +0 -820
  106. package/packs/nextjs/agents/nextjs-architect.md +0 -331
  107. package/packs/nextjs/agents/nextjs-modular.md +0 -433
  108. package/packs/nextjs/commands/component-create.md +0 -398
  109. package/packs/nextjs/rules/api-routes.md +0 -129
  110. package/packs/nextjs/rules/components.md +0 -106
  111. package/packs/nextjs/rules/hooks.md +0 -132
  112. package/packs/nextjs/skills/accessibility-validator/SKILL.md +0 -445
  113. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +0 -399
  114. package/packs/nextjs/skills/react-form-validator/SKILL.md +0 -569
  115. package/packs/nuxtjs/CHANGELOG.md +0 -30
  116. package/packs/nuxtjs/README.md +0 -56
  117. package/packs/nuxtjs/agents/frontend-tester.md +0 -680
  118. package/packs/nuxtjs/agents/frontend-visual.md +0 -820
  119. package/packs/nuxtjs/agents/nuxtjs-architect.md +0 -537
  120. package/packs/nuxtjs/commands/component-create.md +0 -223
  121. package/packs/nuxtjs/rules/components.md +0 -101
  122. package/packs/nuxtjs/rules/composables.md +0 -118
  123. package/packs/nuxtjs/rules/server-routes.md +0 -127
  124. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +0 -183
  125. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +0 -196
  126. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +0 -190
  127. package/packs/onboard/CHANGELOG.md +0 -22
  128. package/packs/onboard/README.md +0 -103
  129. package/packs/onboard/agents/onboard-guide.md +0 -118
  130. package/packs/onboard/commands/onboard.md +0 -313
  131. package/packs/onboard/skills/onboard-context-provider/SKILL.md +0 -98
  132. package/packs/tanstack-router/CHANGELOG.md +0 -30
  133. package/packs/tanstack-router/README.md +0 -113
  134. package/packs/tanstack-router/agents/tanstack-architect.md +0 -173
  135. package/packs/tanstack-router/agents/tanstack-builder.md +0 -360
  136. package/packs/tanstack-router/agents/tanstack-tester.md +0 -454
  137. package/packs/tanstack-router/commands/form-create.md +0 -313
  138. package/packs/tanstack-router/commands/query-create.md +0 -263
  139. package/packs/tanstack-router/commands/route-create.md +0 -190
  140. package/packs/tanstack-router/commands/table-create.md +0 -413
  141. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +0 -370
  142. package/packs/tanstack-router/skills/db-patterns/SKILL.md +0 -346
  143. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +0 -415
  144. package/packs/tanstack-router/skills/form-patterns/SKILL.md +0 -425
  145. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +0 -341
  146. package/packs/tanstack-router/skills/query-patterns/SKILL.md +0 -359
  147. package/packs/tanstack-router/skills/router-patterns/SKILL.md +0 -285
  148. package/packs/tanstack-router/skills/store-patterns/SKILL.md +0 -351
  149. package/packs/tanstack-router/skills/table-patterns/SKILL.md +0 -531
  150. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +0 -428
  151. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +0 -490
  152. package/packs/worktree/CHANGELOG.md +0 -45
  153. package/packs/worktree/README.md +0 -219
  154. package/packs/worktree/commands/wt.md +0 -93
  155. package/packs/worktree/scripts/wt.sh +0 -957
  156. package/packs/worktree/skills/worktree-manager/SKILL.md +0 -113
@@ -1,375 +0,0 @@
1
- ---
2
- name: migration-safety-checker
3
- description: This skill should be used when the user asks to "create a migration", "run makemigrations", "modify a model field", "rename a column", or mentions "schema change", "alter table", "database migration". Validates migrations are production-safe.
4
- ---
5
-
6
- # Migration Safety Checker
7
-
8
- Validates Django migrations are production-safe before they cause data loss.
9
-
10
- ## Activation Triggers
11
-
12
- This skill activates when:
13
- - Running `makemigrations`
14
- - Modifying model fields
15
- - Mentioning "migration", "schema", "alter table"
16
- - Adding/removing/renaming fields
17
- - Changing field types
18
- - Creating or modifying migration files
19
-
20
- ## Safety Requirements
21
-
22
- All migrations MUST be:
23
- - ✅ **Reversible** - Can roll back safely
24
- - ✅ **No data loss** - Preserve existing data
25
- - ✅ **Tested** - Run on staging first
26
- - ✅ **Safe for production** - No downtime operations
27
- - ✅ **Documented** - Explain what changes and why
28
-
29
- ## High-Risk Operations
30
-
31
- These operations require special attention:
32
-
33
- ### 🔴 CRITICAL RISK - Data Loss Possible
34
-
35
- 1. **Dropping columns** without data migration
36
- 2. **Renaming fields** without data migration
37
- 3. **Changing field types** (data conversion issues)
38
- 4. **Adding non-nullable fields** without default
39
- 5. **Removing tables** with data
40
-
41
- ### 🟡 MEDIUM RISK - Requires Careful Planning
42
-
43
- 1. **Adding indexes** on large tables (use `CONCURRENTLY`)
44
- 2. **Adding unique constraints** (check for duplicates first)
45
- 3. **Changing `max_length`** (data truncation risk)
46
-
47
- ### 🟢 LOW RISK - Generally Safe
48
-
49
- 1. **Adding nullable fields**
50
- 2. **Adding fields with defaults**
51
- 3. **Creating new tables**
52
- 4. **Adding non-unique indexes**
53
-
54
- ## Validation Process
55
-
56
- ### Step 1: Analyze Migration File
57
-
58
- When migration is created:
59
-
60
- ```python
61
- # Generated migration
62
- class Migration(migrations.Migration):
63
- operations = [
64
- migrations.RemoveField(
65
- model_name='user',
66
- name='old_email', # 🔴 DATA LOSS RISK!
67
- ),
68
- ]
69
- ```
70
-
71
- ### Step 2: Identify Risks
72
-
73
- Detect:
74
- - Operation type: `RemoveField`
75
- - Field: `old_email`
76
- - **Risk:** 🔴 CRITICAL - Dropping column loses data!
77
-
78
- ### Step 3: Block Unsafe Migration
79
-
80
- > **⛔ UNSAFE MIGRATION DETECTED**
81
- >
82
- > **Operation:** `RemoveField(model_name='user', name='old_email')`
83
- >
84
- > **Risk:** 🔴 CRITICAL - Data loss!
85
- >
86
- > **Problem:**
87
- > - Drops `old_email` column immediately
88
- > - All existing email data will be PERMANENTLY LOST
89
- > - Cannot be rolled back after data is gone
90
- >
91
- > **Safe Approach:**
92
- > Use 3-step migration pattern:
93
- > 1. Data migration: Archive `old_email` data
94
- > 2. Wait for deployment
95
- > 3. Drop column in separate migration
96
- >
97
- > Should I generate the safe migration sequence?
98
-
99
- ### Step 4: Generate Safe Migration
100
-
101
- If user approves, create:
102
-
103
- ```python
104
- # Migration 1: Archive data
105
- class Migration(migrations.Migration):
106
- dependencies = [('users', '0001_initial')]
107
-
108
- operations = [
109
- migrations.RunPython(archive_old_emails, reverse_code=restore_old_emails),
110
- ]
111
-
112
- def archive_old_emails(apps, schema_editor):
113
- """Archive old_email data before dropping."""
114
- User = apps.get_model('users', 'User')
115
- EmailArchive = apps.get_model('users', 'EmailArchive')
116
-
117
- for user in User.objects.all():
118
- if user.old_email:
119
- EmailArchive.objects.create(
120
- user_id=user.id,
121
- email=user.old_email
122
- )
123
-
124
- def restore_old_emails(apps, schema_editor):
125
- """Restore old_email data on rollback."""
126
- User = apps.get_model('users', 'User')
127
- EmailArchive = apps.get_model('users', 'EmailArchive')
128
-
129
- for archive in EmailArchive.objects.all():
130
- User.objects.filter(id=archive.user_id).update(
131
- old_email=archive.email
132
- )
133
-
134
- # Migration 2: Drop column (run after deployment)
135
- class Migration(migrations.Migration):
136
- dependencies = [('users', '0002_archive_emails')]
137
-
138
- operations = [
139
- migrations.RemoveField(
140
- model_name='user',
141
- name='old_email',
142
- ),
143
- ]
144
- ```
145
-
146
- ## Safe Migration Patterns
147
-
148
- ### Pattern 1: Renaming Field (3 Steps)
149
-
150
- **❌ UNSAFE:**
151
- ```python
152
- operations = [
153
- migrations.RenameField('user', 'email', 'email_address'), # ❌ Risky!
154
- ]
155
- ```
156
-
157
- **✅ SAFE (3-Step):**
158
- ```python
159
- # Step 1: Add new field
160
- operations = [
161
- migrations.AddField('user', 'email_address',
162
- models.EmailField(null=True))
163
- ]
164
-
165
- # Step 2: Data migration (copy old → new)
166
- operations = [
167
- migrations.RunPython(copy_email_to_email_address)
168
- ]
169
-
170
- # Step 3: Drop old field (separate deployment)
171
- operations = [
172
- migrations.RemoveField('user', 'email')
173
- ]
174
- ```
175
-
176
- ### Pattern 2: Changing Field Type (3 Steps)
177
-
178
- **❌ UNSAFE:**
179
- ```python
180
- operations = [
181
- migrations.AlterField('product', 'price',
182
- models.DecimalField(max_digits=10, decimal_places=2))
183
- ]
184
- ```
185
-
186
- **✅ SAFE:**
187
- ```python
188
- # Step 1: Add new field with new type
189
- operations = [
190
- migrations.AddField('product', 'price_decimal',
191
- models.DecimalField(max_digits=10, decimal_places=2, null=True))
192
- ]
193
-
194
- # Step 2: Data migration (convert & copy)
195
- operations = [
196
- migrations.RunPython(convert_price_to_decimal)
197
- ]
198
-
199
- # Step 3: Drop old field, rename new field
200
- operations = [
201
- migrations.RemoveField('product', 'price'),
202
- migrations.RenameField('product', 'price_decimal', 'price')
203
- ]
204
- ```
205
-
206
- ### Pattern 3: Adding Non-Nullable Field (2 Steps)
207
-
208
- **❌ UNSAFE:**
209
- ```python
210
- operations = [
211
- migrations.AddField('user', 'organization',
212
- models.ForeignKey('Organization')) # ❌ No default!
213
- ]
214
- ```
215
-
216
- **✅ SAFE:**
217
- ```python
218
- # Step 1: Add as nullable
219
- operations = [
220
- migrations.AddField('user', 'organization',
221
- models.ForeignKey('Organization', null=True))
222
- ]
223
-
224
- # Step 2: Populate + make non-nullable
225
- operations = [
226
- migrations.RunPython(assign_default_organizations),
227
- migrations.AlterField('user', 'organization',
228
- models.ForeignKey('Organization', null=False))
229
- ]
230
- ```
231
-
232
- ### Pattern 4: Adding Unique Constraint (Check First)
233
-
234
- **❌ UNSAFE:**
235
- ```python
236
- operations = [
237
- migrations.AlterField('user', 'email',
238
- models.EmailField(unique=True)) # ❌ Fails if duplicates!
239
- ]
240
- ```
241
-
242
- **✅ SAFE:**
243
- ```python
244
- # Step 1: Check for duplicates
245
- operations = [
246
- migrations.RunPython(check_and_fix_duplicate_emails)
247
- ]
248
-
249
- # Step 2: Add unique constraint
250
- operations = [
251
- migrations.AlterField('user', 'email',
252
- models.EmailField(unique=True))
253
- ]
254
- ```
255
-
256
- ## Production-Safe Practices
257
-
258
- ### Use CONCURRENT Index Creation
259
-
260
- ```python
261
- from django.db import migrations
262
- from django.contrib.postgres.operations import AddIndexConcurrently
263
-
264
- class Migration(migrations.Migration):
265
- atomic = False # Required for CONCURRENT operations
266
-
267
- operations = [
268
- AddIndexConcurrently(
269
- model_name='user',
270
- index=models.Index(fields=['email'], name='user_email_idx')
271
- )
272
- ]
273
- ```
274
-
275
- ### Data Migration Template
276
-
277
- ```python
278
- def forward_migration(apps, schema_editor):
279
- """
280
- Safe data migration with batching.
281
- """
282
- Model = apps.get_model('app', 'Model')
283
- batch_size = 1000
284
-
285
- total = Model.objects.count()
286
- for offset in range(0, total, batch_size):
287
- batch = Model.objects.all()[offset:offset + batch_size]
288
- for obj in batch:
289
- # Transform data
290
- obj.new_field = transform(obj.old_field)
291
- obj.save(update_fields=['new_field'])
292
-
293
- def reverse_migration(apps, schema_editor):
294
- """
295
- Reverse the migration.
296
- """
297
- Model = apps.get_model('app', 'Model')
298
- Model.objects.all().update(new_field=None)
299
-
300
- class Migration(migrations.Migration):
301
- operations = [
302
- migrations.RunPython(forward_migration, reverse_migration)
303
- ]
304
- ```
305
-
306
- ## Migration Testing Checklist
307
-
308
- Before applying migration:
309
-
310
- - ✅ Run on copy of production database
311
- - ✅ Verify data integrity after migration
312
- - ✅ Test rollback works
313
- - ✅ Check migration duration (< 5 minutes ideal)
314
- - ✅ Review SQL with `sqlmigrate`
315
- - ✅ Confirm no downtime required
316
- - ✅ Have rollback plan ready
317
-
318
- ## Validation Commands
319
-
320
- Suggest running:
321
-
322
- ```bash
323
- # Review SQL before applying
324
- python manage.py sqlmigrate users 0002
325
-
326
- # Check for issues
327
- python manage.py makemigrations --check
328
-
329
- # Dry run
330
- python manage.py migrate --plan
331
-
332
- # Apply to staging first
333
- python manage.py migrate --database=staging
334
- ```
335
-
336
- ## Integration with CI/CD
337
-
338
- ```yaml
339
- # .github/workflows/migrations.yml
340
- - name: Check migrations safety
341
- run: |
342
- python manage.py makemigrations --check --dry-run --no-input
343
- python manage.py migrate --plan
344
- ```
345
-
346
- ## Success Criteria
347
-
348
- ✅ No data loss migrations
349
- ✅ All migrations tested on staging
350
- ✅ Rollback plan exists
351
- ✅ Large table migrations use CONCURRENT
352
- ✅ Data migrations properly batched
353
- ✅ Reversible migrations
354
-
355
- ## Behavior
356
-
357
- **Proactive enforcement:**
358
- - Analyze migrations without being asked
359
- - Block unsafe migrations immediately
360
- - Suggest safe 3-step patterns
361
- - Generate data migration code
362
- - Explain WHY the migration is risky
363
-
364
- **Never:**
365
- - Allow data loss migrations
366
- - Let users skip safety checks
367
- - Apply migrations without review
368
- - Just warn without blocking unsafe operations
369
-
370
- **When migration is unsafe:**
371
- - Stop the process
372
- - Explain the risk
373
- - Provide safe alternative
374
- - Generate corrected migration code
375
- - User must acknowledge before proceeding
@@ -1,298 +0,0 @@
1
- ---
2
- name: model-entity-validator
3
- description: This skill should be used when the user asks to "create a model", "add a Django model", "create database table", "add entity", "define schema", or when writing class definitions inheriting from models.Model. Validates BaseModel inheritance pattern.
4
- ---
5
-
6
- # Model/Entity Validator
7
-
8
- Enforces Smicolon's BaseModel inheritance pattern for all Django models.
9
-
10
- ## Activation Triggers
11
-
12
- This skill activates when:
13
- - Creating new model files
14
- - Modifying existing models
15
- - Mentioning "model", "database", "schema", "table"
16
- - Writing class inheriting from `models.Model`
17
- - Running migrations
18
- - Discussing data structure
19
-
20
- ## Core Principle: BaseModel Inheritance
21
-
22
- **NEVER repeat UUID/timestamp fields.** All models inherit from BaseModel.
23
-
24
- ```python
25
- # ❌ WRONG - Repeating fields
26
- class User(models.Model):
27
- id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
28
- created_at = models.DateTimeField(auto_now_add=True)
29
- updated_at = models.DateTimeField(auto_now=True)
30
- is_deleted = models.BooleanField(default=False)
31
- email = models.EmailField()
32
-
33
- # ✅ CORRECT - Inherit from BaseModel
34
- import core.models as _core_models
35
-
36
- class User(_core_models.BaseModel):
37
- email = models.EmailField(unique=True)
38
- ```
39
-
40
- ## Validation Process
41
-
42
- ### Step 1: Check if BaseModel Exists
43
-
44
- Before any action, check if the project has a BaseModel:
45
-
46
- ```python
47
- # Search for BaseModel in (in order):
48
- # 1. core/models.py
49
- # 2. shared/models.py
50
- # 3. common/models.py
51
- # 4. {app}/base.py
52
- ```
53
-
54
- **If BaseModel found:** Suggest inheritance (Step 2a)
55
- **If BaseModel NOT found:** Create BaseModel first (Step 2b)
56
-
57
- ### Step 2a: BaseModel Exists - Suggest Inheritance
58
-
59
- When seeing:
60
- ```python
61
- class Product(models.Model):
62
- name = models.CharField(max_length=255)
63
- ```
64
-
65
- Fix to:
66
- ```python
67
- import core.models as _core_models
68
-
69
- class Product(_core_models.BaseModel):
70
- """Product model - inherits id, timestamps, soft delete from BaseModel."""
71
-
72
- name = models.CharField(max_length=255)
73
- price = models.DecimalField(max_digits=10, decimal_places=2)
74
-
75
- class Meta:
76
- db_table = 'products'
77
- ```
78
-
79
- ### Step 2b: BaseModel NOT Found - Create It First
80
-
81
- If no BaseModel exists, create it:
82
-
83
- ```python
84
- # core/models.py
85
- import uuid
86
- from django.db import models
87
-
88
- class BaseModel(models.Model):
89
- """
90
- Abstract base model providing:
91
- - UUID primary key
92
- - Automatic timestamps (created_at, updated_at)
93
- - Soft delete support (is_deleted)
94
-
95
- All models MUST inherit from this class.
96
- """
97
-
98
- id = models.UUIDField(
99
- primary_key=True,
100
- default=uuid.uuid4,
101
- editable=False
102
- )
103
- created_at = models.DateTimeField(auto_now_add=True)
104
- updated_at = models.DateTimeField(auto_now=True)
105
- is_deleted = models.BooleanField(default=False)
106
-
107
- class Meta:
108
- abstract = True
109
- ordering = ['-created_at']
110
-
111
- def soft_delete(self) -> None:
112
- """Soft delete the record."""
113
- self.is_deleted = True
114
- self.save(update_fields=['is_deleted', 'updated_at'])
115
-
116
- def restore(self) -> None:
117
- """Restore a soft-deleted record."""
118
- self.is_deleted = False
119
- self.save(update_fields=['is_deleted', 'updated_at'])
120
-
121
-
122
- class ActiveManager(models.Manager):
123
- """Manager that excludes soft-deleted records."""
124
-
125
- def get_queryset(self):
126
- return super().get_queryset().filter(is_deleted=False)
127
- ```
128
-
129
- Report to developer:
130
- > **BaseModel Created**
131
- >
132
- > Created `core/models.py` with BaseModel. All models should now inherit from it:
133
- > ```python
134
- > import core.models as _core_models
135
- >
136
- > class YourModel(_core_models.BaseModel):
137
- > # Your fields here - DO NOT add id, created_at, updated_at, is_deleted
138
- > ```
139
-
140
- ### Step 3: Detect Duplicate Fields
141
-
142
- If seeing a model with explicit id/timestamp fields that inherits from BaseModel:
143
-
144
- ```python
145
- # ❌ WRONG - Duplicate fields
146
- class User(_core_models.BaseModel):
147
- id = models.UUIDField(...) # Already in BaseModel!
148
- created_at = models.DateTimeField(...) # Already in BaseModel!
149
- email = models.EmailField()
150
- ```
151
-
152
- Remove them:
153
- ```python
154
- # ✅ CORRECT - Only custom fields
155
- class User(_core_models.BaseModel):
156
- email = models.EmailField(unique=True)
157
- ```
158
-
159
- ### Step 4: Validate Indexes
160
-
161
- Check if appropriate indexes exist:
162
-
163
- ```python
164
- class Product(_core_models.BaseModel):
165
- name = models.CharField(max_length=255)
166
- sku = models.CharField(max_length=100, unique=True)
167
-
168
- class Meta:
169
- db_table = 'products'
170
- indexes = [
171
- models.Index(fields=['sku']), # Suggest for unique lookups
172
- models.Index(fields=['name']), # Suggest for search
173
- ]
174
- ```
175
-
176
- ## Complete Model Examples
177
-
178
- ### Standard Model
179
-
180
- ```python
181
- # products/models.py
182
- from django.db import models
183
- import core.models as _core_models
184
-
185
- class Product(_core_models.BaseModel):
186
- """Product model."""
187
-
188
- name = models.CharField(max_length=255)
189
- description = models.TextField(blank=True)
190
- price = models.DecimalField(max_digits=10, decimal_places=2)
191
- sku = models.CharField(max_length=100, unique=True, db_index=True)
192
- is_active = models.BooleanField(default=True)
193
-
194
- class Meta:
195
- db_table = 'products'
196
- verbose_name = 'Product'
197
- verbose_name_plural = 'Products'
198
- indexes = [
199
- models.Index(fields=['name']),
200
- models.Index(fields=['is_active', 'is_deleted']),
201
- ]
202
-
203
- def __str__(self):
204
- return self.name
205
- ```
206
-
207
- ### User Model (with AbstractUser)
208
-
209
- ```python
210
- # users/models.py
211
- import uuid
212
- from django.db import models
213
- from django.contrib.auth.models import AbstractUser
214
-
215
- class User(AbstractUser):
216
- """
217
- Custom User model with UUID and timestamps.
218
-
219
- Note: For User, override AbstractUser directly since it has its own
220
- ID handling. Add the standard fields manually.
221
- """
222
-
223
- id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
224
- created_at = models.DateTimeField(auto_now_add=True)
225
- updated_at = models.DateTimeField(auto_now=True)
226
- is_deleted = models.BooleanField(default=False)
227
-
228
- email = models.EmailField(unique=True)
229
-
230
- USERNAME_FIELD = 'email'
231
- REQUIRED_FIELDS = []
232
-
233
- class Meta:
234
- db_table = 'users'
235
- ```
236
-
237
- ### Through Model (Many-to-Many)
238
-
239
- ```python
240
- # users/models.py
241
- import core.models as _core_models
242
-
243
- class UserOrganization(_core_models.BaseModel):
244
- """Through model for user-organization relationship."""
245
-
246
- user = models.ForeignKey('User', on_delete=models.CASCADE)
247
- organization = models.ForeignKey('Organization', on_delete=models.CASCADE)
248
- role = models.CharField(max_length=50)
249
-
250
- class Meta:
251
- db_table = 'user_organizations'
252
- unique_together = [['user', 'organization']]
253
- ```
254
-
255
- ## Custom Managers
256
-
257
- BaseModel provides soft delete. Add a custom manager for convenience:
258
-
259
- ```python
260
- import core.models as _core_models
261
-
262
- class Product(_core_models.BaseModel):
263
- name = models.CharField(max_length=255)
264
-
265
- objects = models.Manager() # All records
266
- active = _core_models.ActiveManager() # Excludes soft-deleted
267
-
268
- # Usage
269
- Product.active.all() # Only non-deleted
270
- Product.objects.all() # All including deleted
271
- ```
272
-
273
- ## Validation Checklist
274
-
275
- When reviewing a model, check:
276
-
277
- 1. ✅ Inherits from `BaseModel` (or has explicit required fields for special cases)
278
- 2. ✅ Does NOT duplicate fields from BaseModel
279
- 3. ✅ Uses absolute import: `import core.models as _core_models`
280
- 4. ✅ Has appropriate `db_table` name (singular or plural, snake_case)
281
- 5. ✅ Has indexes on frequently queried fields
282
- 6. ✅ Foreign keys have `on_delete` specified
283
- 7. ✅ Has docstring explaining the model
284
- 8. ✅ Has `__str__` method for admin display
285
-
286
- ## Behavior
287
-
288
- **Proactive enforcement:**
289
- - Check if BaseModel exists FIRST
290
- - Suggest inheritance instead of field duplication
291
- - Remove duplicate fields automatically
292
- - Create BaseModel if missing
293
- - Explain WHY inheritance is better
294
-
295
- **Never:**
296
- - Add duplicate id/timestamp fields to models
297
- - Let developers repeat base fields
298
- - Ignore existing BaseModel in the project