@smicolon/ai-kit 0.1.0 → 0.2.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 (164) hide show
  1. package/.claude-plugin/CLAUDE.md +7 -0
  2. package/.claude-plugin/marketplace.json +373 -0
  3. package/README.md +26 -16
  4. package/dist/index.js +146 -38
  5. package/package.json +4 -3
  6. package/packs/architect/CHANGELOG.md +17 -0
  7. package/packs/architect/README.md +58 -0
  8. package/packs/architect/agents/system-architect.md +768 -0
  9. package/packs/architect/commands/diagram-create.md +300 -0
  10. package/packs/better-auth/.claude-plugin/plugin.json +14 -0
  11. package/packs/better-auth/.mcp.json +14 -0
  12. package/packs/better-auth/CHANGELOG.md +26 -0
  13. package/packs/better-auth/README.md +125 -0
  14. package/packs/better-auth/agents/auth-architect.md +278 -0
  15. package/packs/better-auth/commands/auth-provider-add.md +265 -0
  16. package/packs/better-auth/commands/auth-setup.md +298 -0
  17. package/packs/better-auth/skills/auth-security/SKILL.md +425 -0
  18. package/packs/better-auth/skills/better-auth-patterns/SKILL.md +455 -0
  19. package/packs/dev-loop/.claude-plugin/plugin.json +10 -0
  20. package/packs/dev-loop/CHANGELOG.md +69 -0
  21. package/packs/dev-loop/README.md +155 -0
  22. package/packs/dev-loop/commands/cancel-dev.md +21 -0
  23. package/packs/dev-loop/commands/dev-loop.md +72 -0
  24. package/packs/dev-loop/commands/dev-plan.md +351 -0
  25. package/packs/dev-loop/hooks/hooks.json +15 -0
  26. package/packs/dev-loop/hooks/stop-hook.sh +178 -0
  27. package/packs/dev-loop/scripts/setup-dev-loop.sh +194 -0
  28. package/packs/dev-loop/skills/tdd-planner/SKILL.md +249 -0
  29. package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +874 -0
  30. package/packs/dev-loop/skills/tdd-planner/references/good-example.md +260 -0
  31. package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +275 -0
  32. package/packs/django/CHANGELOG.md +39 -0
  33. package/packs/django/README.md +92 -0
  34. package/packs/django/agents/django-architect.md +182 -0
  35. package/packs/django/agents/django-builder.md +250 -0
  36. package/packs/django/agents/django-feature-based.md +420 -0
  37. package/packs/django/agents/django-reviewer.md +253 -0
  38. package/packs/django/agents/django-tester.md +230 -0
  39. package/packs/django/commands/api-endpoint.md +285 -0
  40. package/packs/django/commands/model-create.md +178 -0
  41. package/packs/django/commands/test-generate.md +325 -0
  42. package/packs/django/rules/migrations.md +138 -0
  43. package/packs/django/rules/models.md +167 -0
  44. package/packs/django/rules/serializers.md +126 -0
  45. package/packs/django/rules/services.md +131 -0
  46. package/packs/django/rules/tests.md +140 -0
  47. package/packs/django/rules/views.md +102 -0
  48. package/packs/django/skills/import-convention-enforcer/SKILL.md +226 -0
  49. package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +343 -0
  50. package/packs/django/skills/migration-safety-checker/SKILL.md +375 -0
  51. package/packs/django/skills/model-entity-validator/SKILL.md +298 -0
  52. package/packs/django/skills/performance-optimizer/SKILL.md +447 -0
  53. package/packs/django/skills/red-phase-verifier/SKILL.md +180 -0
  54. package/packs/django/skills/security-first-validator/SKILL.md +435 -0
  55. package/packs/django/skills/test-coverage-advisor/SKILL.md +394 -0
  56. package/packs/django/skills/test-validity-checker/SKILL.md +194 -0
  57. package/packs/failure-log/.claude-plugin/plugin.json +14 -0
  58. package/packs/failure-log/CHANGELOG.md +20 -0
  59. package/packs/failure-log/README.md +168 -0
  60. package/packs/failure-log/commands/failure-add.md +106 -0
  61. package/packs/failure-log/commands/failure-list.md +89 -0
  62. package/packs/failure-log/hooks/hooks.json +16 -0
  63. package/packs/failure-log/hooks/scripts/inject-failures.sh +64 -0
  64. package/packs/failure-log/skills/failure-log-manager/SKILL.md +164 -0
  65. package/packs/flutter/.claude-plugin/plugin.json +10 -0
  66. package/packs/flutter/CHANGELOG.md +19 -0
  67. package/packs/flutter/README.md +170 -0
  68. package/packs/flutter/agents/flutter-architect.md +166 -0
  69. package/packs/flutter/agents/flutter-builder.md +303 -0
  70. package/packs/flutter/agents/release-manager.md +355 -0
  71. package/packs/flutter/commands/fastlane-setup.md +188 -0
  72. package/packs/flutter/commands/flutter-build.md +90 -0
  73. package/packs/flutter/commands/flutter-deploy.md +133 -0
  74. package/packs/flutter/commands/flutter-test.md +117 -0
  75. package/packs/flutter/commands/signing-setup.md +209 -0
  76. package/packs/flutter/hooks/hooks.json +17 -0
  77. package/packs/flutter/skills/fastlane-knowledge/SKILL.md +193 -0
  78. package/packs/flutter/skills/flutter-architecture/SKILL.md +127 -0
  79. package/packs/flutter/skills/store-publishing/SKILL.md +163 -0
  80. package/packs/hono/.claude-plugin/plugin.json +19 -0
  81. package/packs/hono/CHANGELOG.md +19 -0
  82. package/packs/hono/README.md +143 -0
  83. package/packs/hono/agents/hono-architect.md +240 -0
  84. package/packs/hono/agents/hono-builder.md +285 -0
  85. package/packs/hono/agents/hono-reviewer.md +279 -0
  86. package/packs/hono/agents/hono-tester.md +346 -0
  87. package/packs/hono/commands/middleware-create.md +223 -0
  88. package/packs/hono/commands/project-init.md +306 -0
  89. package/packs/hono/commands/route-create.md +153 -0
  90. package/packs/hono/commands/rpc-client.md +263 -0
  91. package/packs/hono/hooks/hooks.json +4 -0
  92. package/packs/hono/skills/cloudflare-bindings/SKILL.md +408 -0
  93. package/packs/hono/skills/hono-patterns/SKILL.md +309 -0
  94. package/packs/hono/skills/rpc-typesafe/SKILL.md +388 -0
  95. package/packs/hono/skills/zod-validation/SKILL.md +332 -0
  96. package/packs/nestjs/CHANGELOG.md +29 -0
  97. package/packs/nestjs/README.md +75 -0
  98. package/packs/nestjs/agents/nestjs-architect.md +402 -0
  99. package/packs/nestjs/agents/nestjs-builder.md +301 -0
  100. package/packs/nestjs/agents/nestjs-tester.md +437 -0
  101. package/packs/nestjs/commands/module-create.md +369 -0
  102. package/packs/nestjs/rules/controllers.md +92 -0
  103. package/packs/nestjs/rules/dto.md +124 -0
  104. package/packs/nestjs/rules/entities.md +102 -0
  105. package/packs/nestjs/rules/services.md +106 -0
  106. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +389 -0
  107. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +365 -0
  108. package/packs/nextjs/CHANGELOG.md +36 -0
  109. package/packs/nextjs/README.md +76 -0
  110. package/packs/nextjs/agents/frontend-tester.md +680 -0
  111. package/packs/nextjs/agents/frontend-visual.md +820 -0
  112. package/packs/nextjs/agents/nextjs-architect.md +331 -0
  113. package/packs/nextjs/agents/nextjs-modular.md +433 -0
  114. package/packs/nextjs/commands/component-create.md +398 -0
  115. package/packs/nextjs/rules/api-routes.md +129 -0
  116. package/packs/nextjs/rules/components.md +106 -0
  117. package/packs/nextjs/rules/hooks.md +132 -0
  118. package/packs/nextjs/skills/accessibility-validator/SKILL.md +445 -0
  119. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +399 -0
  120. package/packs/nextjs/skills/react-form-validator/SKILL.md +569 -0
  121. package/packs/nuxtjs/CHANGELOG.md +30 -0
  122. package/packs/nuxtjs/README.md +56 -0
  123. package/packs/nuxtjs/agents/frontend-tester.md +680 -0
  124. package/packs/nuxtjs/agents/frontend-visual.md +820 -0
  125. package/packs/nuxtjs/agents/nuxtjs-architect.md +537 -0
  126. package/packs/nuxtjs/commands/component-create.md +223 -0
  127. package/packs/nuxtjs/rules/components.md +101 -0
  128. package/packs/nuxtjs/rules/composables.md +118 -0
  129. package/packs/nuxtjs/rules/server-routes.md +127 -0
  130. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +183 -0
  131. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +196 -0
  132. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +190 -0
  133. package/packs/onboard/CHANGELOG.md +22 -0
  134. package/packs/onboard/README.md +103 -0
  135. package/packs/onboard/agents/onboard-guide.md +118 -0
  136. package/packs/onboard/commands/onboard.md +313 -0
  137. package/packs/onboard/skills/onboard-context-provider/SKILL.md +98 -0
  138. package/packs/tanstack-router/.claude-plugin/plugin.json +14 -0
  139. package/packs/tanstack-router/CHANGELOG.md +30 -0
  140. package/packs/tanstack-router/README.md +113 -0
  141. package/packs/tanstack-router/agents/tanstack-architect.md +173 -0
  142. package/packs/tanstack-router/agents/tanstack-builder.md +360 -0
  143. package/packs/tanstack-router/agents/tanstack-tester.md +454 -0
  144. package/packs/tanstack-router/commands/form-create.md +313 -0
  145. package/packs/tanstack-router/commands/query-create.md +263 -0
  146. package/packs/tanstack-router/commands/route-create.md +190 -0
  147. package/packs/tanstack-router/commands/table-create.md +413 -0
  148. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +370 -0
  149. package/packs/tanstack-router/skills/db-patterns/SKILL.md +346 -0
  150. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +415 -0
  151. package/packs/tanstack-router/skills/form-patterns/SKILL.md +425 -0
  152. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +341 -0
  153. package/packs/tanstack-router/skills/query-patterns/SKILL.md +359 -0
  154. package/packs/tanstack-router/skills/router-patterns/SKILL.md +285 -0
  155. package/packs/tanstack-router/skills/store-patterns/SKILL.md +351 -0
  156. package/packs/tanstack-router/skills/table-patterns/SKILL.md +531 -0
  157. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +428 -0
  158. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +490 -0
  159. package/packs/worktree/.claude-plugin/plugin.json +19 -0
  160. package/packs/worktree/CHANGELOG.md +24 -0
  161. package/packs/worktree/README.md +110 -0
  162. package/packs/worktree/commands/wt.md +73 -0
  163. package/packs/worktree/scripts/wt.sh +396 -0
  164. package/packs/worktree/skills/worktree-manager/SKILL.md +68 -0
@@ -0,0 +1,375 @@
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
@@ -0,0 +1,298 @@
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