cc-codeconductor 0.2.1

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 (93) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +319 -0
  3. package/dist/index.js +12741 -0
  4. package/package.json +51 -0
  5. package/policy.yml +124 -0
  6. package/presets/claude/CLAUDE.md +598 -0
  7. package/presets/claude/commands/cc/feature.md +115 -0
  8. package/presets/claude/commands/cc/fix.md +121 -0
  9. package/presets/claude/commands/cc/refactor.md +148 -0
  10. package/presets/claude/commands/cc/review.md +126 -0
  11. package/presets/claude/commands/cc/tdd-cycle.md +226 -0
  12. package/presets/claude/commands/cc/test-plan.md +138 -0
  13. package/presets/claude/settings.json +37 -0
  14. package/presets/claude/skills/api-versioning/SKILL.md +389 -0
  15. package/presets/claude/skills/django-orm/SKILL.md +455 -0
  16. package/presets/claude/skills/django-testing/SKILL.md +409 -0
  17. package/presets/claude/skills/jpa-postgres/SKILL.md +618 -0
  18. package/presets/claude/skills/python/SKILL.md +606 -0
  19. package/presets/claude/skills/python-django-stack/SKILL.md +492 -0
  20. package/presets/claude/skills/python-fastapi-stack/SKILL.md +457 -0
  21. package/presets/claude/skills/spring-boot-feature/SKILL.md +558 -0
  22. package/presets/claude/skills/spring-boot-kotlin/SKILL.md +400 -0
  23. package/presets/claude/skills/sqlalchemy/SKILL.md +466 -0
  24. package/presets/claude/skills/testing-strategy/SKILL.md +479 -0
  25. package/presets/codex/AGENTS.md +883 -0
  26. package/presets/codex/README.md +102 -0
  27. package/presets/codex/skills/api-versioning/SKILL.md +389 -0
  28. package/presets/codex/skills/django-orm/SKILL.md +455 -0
  29. package/presets/codex/skills/django-testing/SKILL.md +409 -0
  30. package/presets/codex/skills/jpa-postgres/SKILL.md +618 -0
  31. package/presets/codex/skills/python/SKILL.md +606 -0
  32. package/presets/codex/skills/python-django-stack/SKILL.md +492 -0
  33. package/presets/codex/skills/python-fastapi-stack/SKILL.md +457 -0
  34. package/presets/codex/skills/spring-boot-feature/SKILL.md +558 -0
  35. package/presets/codex/skills/spring-boot-kotlin/SKILL.md +400 -0
  36. package/presets/codex/skills/sqlalchemy/SKILL.md +466 -0
  37. package/presets/codex/skills/testing-strategy/SKILL.md +479 -0
  38. package/presets/opencode/README.md +191 -0
  39. package/presets/opencode/agents/architect.md +133 -0
  40. package/presets/opencode/agents/docs.md +113 -0
  41. package/presets/opencode/agents/implementer.md +116 -0
  42. package/presets/opencode/agents/orchestrator.md +248 -0
  43. package/presets/opencode/agents/repo-explorer.md +119 -0
  44. package/presets/opencode/agents/reviewer.md +130 -0
  45. package/presets/opencode/agents/task-coach.md +103 -0
  46. package/presets/opencode/agents/tester.md +269 -0
  47. package/presets/opencode/commands/cc-feature.md +114 -0
  48. package/presets/opencode/commands/cc-fix.md +123 -0
  49. package/presets/opencode/commands/cc-refactor.md +148 -0
  50. package/presets/opencode/commands/cc-review.md +141 -0
  51. package/presets/opencode/commands/cc-tdd-cycle.md +225 -0
  52. package/presets/opencode/commands/cc-test-plan.md +144 -0
  53. package/presets/opencode/opencode.jsonc +89 -0
  54. package/presets/opencode/prompts/v0.1.0/architect.md +213 -0
  55. package/presets/opencode/prompts/v0.1.0/docs.md +181 -0
  56. package/presets/opencode/prompts/v0.1.0/implementer.md +154 -0
  57. package/presets/opencode/prompts/v0.1.0/orchestrator.md +169 -0
  58. package/presets/opencode/prompts/v0.1.0/repo-explorer.md +102 -0
  59. package/presets/opencode/prompts/v0.1.0/reviewer.md +183 -0
  60. package/presets/opencode/prompts/v0.1.0/task-coach.md +142 -0
  61. package/presets/opencode/prompts/v0.1.0/tester.md +160 -0
  62. package/presets/opencode/prompts/v0.2.0/architect.md +219 -0
  63. package/presets/opencode/prompts/v0.2.0/docs.md +187 -0
  64. package/presets/opencode/prompts/v0.2.0/implementer.md +160 -0
  65. package/presets/opencode/prompts/v0.2.0/orchestrator.md +238 -0
  66. package/presets/opencode/prompts/v0.2.0/repo-explorer.md +108 -0
  67. package/presets/opencode/prompts/v0.2.0/reviewer.md +190 -0
  68. package/presets/opencode/prompts/v0.2.0/task-coach.md +153 -0
  69. package/presets/opencode/prompts/v0.2.0/tester.md +249 -0
  70. package/presets/opencode/skills/api-versioning/SKILL.md +388 -0
  71. package/presets/opencode/skills/astro/SKILL.md +313 -0
  72. package/presets/opencode/skills/code-review/SKILL.md +202 -0
  73. package/presets/opencode/skills/django-orm/SKILL.md +455 -0
  74. package/presets/opencode/skills/django-testing/SKILL.md +408 -0
  75. package/presets/opencode/skills/django-uv/SKILL.md +400 -0
  76. package/presets/opencode/skills/jpa-postgres/SKILL.md +617 -0
  77. package/presets/opencode/skills/nextjs-typescript/SKILL.md +385 -0
  78. package/presets/opencode/skills/python/SKILL.md +605 -0
  79. package/presets/opencode/skills/python-django-stack/SKILL.md +491 -0
  80. package/presets/opencode/skills/python-fastapi-stack/SKILL.md +456 -0
  81. package/presets/opencode/skills/security/SKILL.md +376 -0
  82. package/presets/opencode/skills/spring-boot-feature/SKILL.md +557 -0
  83. package/presets/opencode/skills/spring-boot-kotlin/SKILL.md +399 -0
  84. package/presets/opencode/skills/spring-boot-testing-strategy/SKILL.md +470 -0
  85. package/presets/opencode/skills/sqlalchemy/SKILL.md +465 -0
  86. package/presets/opencode/skills/testing-tdd/SKILL.md +586 -0
  87. package/src/presets/council/council.yml +59 -0
  88. package/src/presets/manifests/claude.yml +23 -0
  89. package/src/presets/manifests/codex.yml +12 -0
  90. package/src/presets/manifests/opencode.yml +18 -0
  91. package/src/presets/models/claude.yml +37 -0
  92. package/src/presets/models/codex.yml +38 -0
  93. package/src/presets/models/opencode.yml +37 -0
@@ -0,0 +1,455 @@
1
+ ---
2
+ id: django-orm
3
+ version: 1.0.0
4
+ name: Django ORM
5
+ description: >
6
+ Django ORM patterns for multi-tenant POS projects: efficient queries,
7
+ bulk operations, transactions, and multi-schema upload paths.
8
+ Trigger: When writing queryset logic, model saves, or DB-touching service code.
9
+
10
+ compatibility:
11
+ tools: [claude, codex, opencode]
12
+ stacks:
13
+ languages: [python]
14
+ frameworks: [django, django-tenants]
15
+
16
+ risk:
17
+ level: medium
18
+ can_execute_shell: true
19
+ can_modify_files: true
20
+ requires_network: false
21
+
22
+ inputs:
23
+ - model files (models.py)
24
+ - service files (services.py)
25
+ - view files with queryset logic
26
+ - existing queryset or bulk-operation code
27
+
28
+ outputs:
29
+ - optimized queryset patterns with select_related / prefetch_related
30
+ - bulk_create and bulk_update implementations
31
+ - transaction-safe service methods
32
+ - annotated and aggregated querysets
33
+ - migration commands for multi-schema projects
34
+
35
+ quality:
36
+ reviewed_by: codeconductor-core
37
+ version: 0.1.0
38
+ ---
39
+
40
+ ## When to Use
41
+
42
+ - Writing or reviewing queryset code in any `apps/*/`
43
+ - Adding aggregations, filters, or annotations to a queryset
44
+ - Writing model `save()` overrides or signals
45
+ - Implementing service-layer DB operations
46
+ - Optimizing queries that traverse FK relationships
47
+
48
+ ## Performance Fundamentals
49
+
50
+ ### The N+1 Problem
51
+
52
+ The most common Django mistake: iterating over a queryset and accessing FK
53
+ fields without `select_related`. Each access generates a separate DB query.
54
+
55
+ ```
56
+ # Initial query: 1 query
57
+ products = Product.objects.all()
58
+
59
+ # In the loop: N additional queries (one per product)
60
+ for p in products:
61
+ print(p.category.name) # category_id → SELECT * FROM category WHERE id = ?
62
+
63
+ # Total: 1 + N queries
64
+ ```
65
+
66
+ ### Solution: select_related and prefetch_related
67
+
68
+ | Method | Use | SQL Query |
69
+ | ---------------------------------- | -------------------------- | ------------------------ |
70
+ | `select_related` | FK one-to-one or ManyToOne | Automatic JOIN |
71
+ | `prefetch_related` | Reverse FK or ManyToMany | 2 separate queries |
72
+ | `prefetch_related` with `Prefetch` | Custom queryset | Filtered in nested query |
73
+
74
+ ```python
75
+ # FK traversal — use select_related
76
+ products = Product.objects.select_related("category", "tax")
77
+
78
+ # Multiple FK
79
+ products = Product.objects.select_related("category", "tax", "supplier")
80
+
81
+ # Reverse FK (one-to-many) — use prefetch_related
82
+ categories = Category.objects.prefetch_related("products")
83
+
84
+ # ManyToMany — prefetch_related
85
+ product = Product.objects.prefetch_related("tags").first()
86
+
87
+ # Custom prefetch with filter
88
+ from django.db.models import Prefetch
89
+
90
+ products = Product.objects.prefetch_related(
91
+ Prefetch(
92
+ "order_items",
93
+ queryset=OrderItem.objects.filter(order__status="paid")
94
+ )
95
+ )
96
+ ```
97
+
98
+ ## Query Patterns
99
+
100
+ ### 1. Efficient Filtering
101
+
102
+ ```python
103
+ # Basic filtering
104
+ Product.objects.filter(is_active=True, stock__gt=0)
105
+
106
+ # Filtering with Q objects — OR and negations
107
+ from django.db.models import Q
108
+
109
+ Product.objects.filter(
110
+ Q(is_active=True) & (Q(stock__gt=0) | Q(is_service=True))
111
+ )
112
+
113
+ # Exclusion
114
+ Product.objects.exclude(status="draft")
115
+
116
+ # Filter by nested FK
117
+ Order.objects.filter(employee__store=store)
118
+ ```
119
+
120
+ ### 2. Annotations and Aggregations
121
+
122
+ ```python
123
+ from django.db.models import Count, Sum, Avg, Max, Min, F, Q, Case, When, Value, CharField
124
+ from django.db.models.functions import Coalesce, Concat
125
+
126
+ # Conditional sum with Coalesce (avoids None)
127
+ Product.objects.annotate(
128
+ total_sold=Coalesce(
129
+ Sum(
130
+ "order_items__quantity",
131
+ filter=Q(
132
+ order_items__order__status__in=["paid", "shipped"],
133
+ order_items__order__created_at__gte=cutoff,
134
+ ),
135
+ ),
136
+ 0,
137
+ ),
138
+ )
139
+
140
+ # Use F for arithmetic operations
141
+ Product.objects.update(stock=F("stock") - 1)
142
+
143
+ # Annotation with Case/When for conditional logic
144
+ Product.objects.annotate(
145
+ status_flag=Case(
146
+ When(stock__lte=0, then=Value("out_of_stock")),
147
+ When(stock__lte=10, then=Value("low_stock")),
148
+ default=Value("available"),
149
+ output_field=CharField(),
150
+ ),
151
+ )
152
+
153
+ # Aggregation with filter
154
+ Store.objects.annotate(
155
+ paid_orders=Count("orders", filter=Q(orders__status="paid")),
156
+ )
157
+ ```
158
+
159
+ ### 3. Exists vs Count
160
+
161
+ **Golden rule**: For existence checks, use `Exists`, never `Count`.
162
+
163
+ ```python
164
+ from django.db.models import Exists, OuterRef, Count
165
+
166
+ # WRONG — loads full count
167
+ products = Product.objects.annotate(
168
+ order_count=Count("order_items")
169
+ ).filter(order_count__gt=0)
170
+
171
+ # CORRECT — short-circuits at first match
172
+ products = Product.objects.annotate(
173
+ has_orders=Exists(OrderItem.objects.filter(product=OuterRef("pk")))
174
+ ).filter(has_orders=True)
175
+
176
+ # With more complex subquery
177
+ from django.db.models import Subquery
178
+
179
+ latest_order = Order.objects.filter(
180
+ customer=OuterRef("customer_id")
181
+ ).order_by("-created_at")
182
+
183
+ Customer.objects.annotate(
184
+ last_order_date=Subquery(
185
+ latest_order.values("created_at")[:1]
186
+ )
187
+ )
188
+ ```
189
+
190
+ ### 4. Ordering
191
+
192
+ ```python
193
+ # Basic ordering
194
+ Product.objects.order_by("name")
195
+
196
+ # Ordering with NullsFirst/NullsLast
197
+ Product.objects.order_by(F("price").nulls_last())
198
+
199
+ # Ordering by annotation
200
+ Store.objects.annotate(
201
+ order_count=Count("orders")
202
+ ).order_by("-order_count")
203
+ ```
204
+
205
+ ## Write Operations
206
+
207
+ ### 5. Bulk Operations — Anti-N+1
208
+
209
+ **Never do `save()` inside a loop.** Build lists and use bulk operations:
210
+
211
+ ```python
212
+ # Get with lock once
213
+ products = {p.id: p for p in Product.objects.select_for_update().filter(id__in=ids)}
214
+
215
+ order_items_to_create = []
216
+ products_to_update = []
217
+
218
+ for item in cart:
219
+ product = products[item["id"]]
220
+ product.stock -= item["quantity"]
221
+ order_items_to_create.append(
222
+ OrderItem(order=order, product=product, quantity=item["quantity"], ...)
223
+ )
224
+ products_to_update.append(product)
225
+
226
+ # Bulk create and update
227
+ OrderItem.objects.bulk_create(order_items_to_create)
228
+ Product.objects.bulk_update(products_to_update, ["stock", "updated_at"])
229
+ ```
230
+
231
+ **Bulk operation table:**
232
+
233
+ | Method | Use case | Returns |
234
+ | ------------------------------------------- | -------------------------- | ----------------- |
235
+ | `bulk_create(items)` | Create multiple records | List of objects |
236
+ | `bulk_update(items, fields)` | Update multiple records | None (in-place) |
237
+ | `bulk_create(items, ignore_conflicts=True)` | Ignore duplicates | List (IDs only) |
238
+ | `update()` | Mass update without return | Count of affected |
239
+
240
+ ```python
241
+ # bulk_create with ignore_conflicts
242
+ Product.objects.bulk_create(new_products, ignore_conflicts=True)
243
+
244
+ # bulk update
245
+ Product.objects.filter(category=cat).update(is_active=False)
246
+
247
+ # update with F expressions
248
+ Product.objects.update(stock=F("stock") - 1)
249
+ ```
250
+
251
+ ### 6. Surgical Saves — update_fields
252
+
253
+ **Always pass `update_fields`** when saving a subset of fields:
254
+
255
+ ```python
256
+ # Update single field
257
+ product.stock -= 1
258
+ product.save(update_fields=["stock"])
259
+
260
+ # Update multiple fields
261
+ order.status = "paid"
262
+ order.paid_at = timezone.now()
263
+ order.save(update_fields=["status", "paid_at", "updated_at"])
264
+
265
+ # Don't use in migrations — that uses reconstructor
266
+ # DO use in application code
267
+ ```
268
+
269
+ **Why?** Prevents:
270
+
271
+ - Accidental image reprocessing
272
+ - Unnecessary signals
273
+ - Race conditions on unrelated fields
274
+
275
+ ### 7. Transactions
276
+
277
+ Use `transaction.atomic()` as a context manager, never as a decorator:
278
+
279
+ ```python
280
+ from django.db import transaction
281
+
282
+ # CORRECT — clear context, automatic error handling
283
+ with transaction.atomic():
284
+ order.save()
285
+ OrderItem.objects.bulk_create(items)
286
+ Product.objects.bulk_update(products, ["stock"])
287
+ cart.clear()
288
+
289
+ # With select_for_update inside the transaction
290
+ with transaction.atomic():
291
+ product = Product.objects.select_for_update().get(pk=product_id)
292
+ product.stock -= quantity
293
+ product.save(update_fields=["stock", "updated_at"])
294
+
295
+ # WRONG — decorator hides intent
296
+ @transaction.atomic
297
+ def create_order(...):
298
+ ...
299
+ ```
300
+
301
+ **Isolation levels:**
302
+
303
+ ```python
304
+ from django.db import transaction
305
+
306
+ # Serializable — maximum isolation
307
+ with transaction.atomic():
308
+ ...
309
+
310
+ # Read committed (default) — may cause dirty reads on Edge
311
+ ```
312
+
313
+ ## Multi-Tenant and Upload Paths
314
+
315
+ ### 8. Upload Paths with Schema
316
+
317
+ Every `FileField`/`ImageField` must include `connection.schema_name` to isolate
318
+ files per tenant:
319
+
320
+ ```python
321
+ import os
322
+ from django.db import connection
323
+
324
+ def get_upload_path(instance, filename):
325
+ schema = connection.schema_name
326
+ ext = filename.split(".")[-1].lower()
327
+ safe_name = f"{uuid4().hex}.{ext}"
328
+ return os.path.join(schema, "products", safe_name)
329
+
330
+ def get_thumb_path(instance, filename):
331
+ schema = connection.schema_name
332
+ return os.path.join(schema, "products", "thumbs", filename)
333
+
334
+ class Product(models.Model):
335
+ image = models.ImageField(upload_to=get_upload_path, storage=S3Storage())
336
+ thumbnail = models.ImageField(upload_to=get_thumb_path, blank=True)
337
+ ```
338
+
339
+ ## Advanced Queries
340
+
341
+ ### 9. Subqueries
342
+
343
+ ```python
344
+ from django.db.models import Subquery, OuterRef
345
+
346
+ # Subquery to get last value
347
+ latest_price = ProductPrice.objects.filter(
348
+ product=OuterRef("pk")
349
+ ).order_by("-valid_from").values("price")[:1]
350
+
351
+ Product.objects.annotate(current_price=Subquery(latest_price))
352
+
353
+ # Subquery with aggregate
354
+ order_total = OrderItem.objects.filter(
355
+ order=OuterRef("pk")
356
+ ).values("order").annotate(total=Sum("subtotal")).values("total")
357
+
358
+ Order.objects.annotate(order_total=Subquery(order_total))
359
+ ```
360
+
361
+ ### 10. Raw Queries — WHEN TO USE
362
+
363
+ Avoid raw queries unless necessary. Use when:
364
+
365
+ - Complex aggregation functions not supported by ORM
366
+ - Queries with multiple JOINs manually optimized
367
+ - Very complex queries where ORM generates inefficient SQL
368
+
369
+ ```python
370
+ # With safe parameters (never string interpolation!)
371
+ Product.objects.raw(
372
+ "SELECT * FROM catalog_product WHERE tsvector @@ plainto_tsquery(%s)",
373
+ [search_term]
374
+ )
375
+
376
+ # With cursor for complex cases
377
+ from django.db import connection
378
+
379
+ with connection.cursor() as cursor:
380
+ cursor.execute("SELECT ...", [params])
381
+ results = cursor.fetchall()
382
+ ```
383
+
384
+ ## Migration Commands
385
+
386
+ ```bash
387
+ # Always migrate both schemas
388
+ uv run python manage.py migrate_schemas --shared
389
+ uv run python manage.py migrate_schemas --tenant
390
+
391
+ # Check for pending migrations
392
+ make verifymigrations
393
+
394
+ # Create specific migration
395
+ uv run python manage.py makemigrations catalog --name add_thumbnail
396
+
397
+ # Shows SQL without running
398
+ uv run python manage.py migrate --fake catalog 0003
399
+ ```
400
+
401
+ ## Common Mistakes and How to Avoid Them
402
+
403
+ ### N+1 in templates
404
+
405
+ ```python
406
+ # WRONG — N queries
407
+ {% for product in products %}
408
+ {{ product.category.name }}
409
+ {% endfor %}
410
+
411
+ # CORRECT — 1 query with select_related
412
+ products = Product.objects.select_related("category")
413
+ ```
414
+
415
+ ### ForeignKey without related_name
416
+
417
+ ```python
418
+ # WRONG
419
+ class Order(models.Model):
420
+ customer = models.ForeignKey("users.User", on_delete=...)
421
+
422
+ # CORRECT — always add related_name
423
+ class Order(models.Model):
424
+ customer = models.ForeignKey(
425
+ "users.User",
426
+ on_delete=models.CASCADE,
427
+ related_name="orders",
428
+ )
429
+ ```
430
+
431
+ ### Queries in signals
432
+
433
+ ```python
434
+ # WRONG — signal makes additional query
435
+ @receiver(post_save, sender=Order)
436
+ def on_order_save(sender, instance, **kwargs):
437
+ customer = instance.customer # Additional query!
438
+ send_email(customer.email, ...)
439
+
440
+ # CORRECT — pass the object, not the ID
441
+ @receiver(post_save, sender=Order)
442
+ def on_order_save(sender, instance, created, **kwargs):
443
+ if created:
444
+ customer = instance.customer
445
+ send_email(customer.email, ...)
446
+ ```
447
+
448
+ ## Resources
449
+
450
+ - **Bulk write pattern**: `apps/orders/services.py`, `apps/pos/views.py` lines
451
+ 216-246
452
+ - **Annotation examples**: `apps/pos/views.py` lines 59-75
453
+ - **Exists usage**: `apps/catalog/views.py` line 112
454
+ - **Upload paths**: `apps/catalog/models.py`
455
+ - **Django ORM docs**: https://docs.djangoproject.com/en/5.2/topics/db/queries/