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,492 @@
1
+ ---
2
+ id: python-django-stack
3
+ version: 1.0.0
4
+ name: Python Django Stack
5
+ description: >
6
+ Python and Django conventions for multi-tenant SaaS POS projects:
7
+ views, services, naming, JSON APIs, PDFs, and cart patterns.
8
+ Trigger: When writing any view, service, API endpoint, or model code in apps/.
9
+
10
+ compatibility:
11
+ tools: [claude, codex, opencode]
12
+ stacks:
13
+ languages: [python]
14
+ frameworks: [django, django-tenants, django-rest-framework, reportlab]
15
+
16
+ risk:
17
+ level: medium
18
+ can_execute_shell: true
19
+ can_modify_files: true
20
+ requires_network: false
21
+
22
+ inputs:
23
+ - view files (views.py)
24
+ - service files (services.py)
25
+ - model files (models.py)
26
+ - URL configuration files (urls.py)
27
+ - existing app structure under apps/
28
+
29
+ outputs:
30
+ - FBV and CBV view implementations
31
+ - service layer classes with static methods
32
+ - JSON API responses with correct status codes
33
+ - pagination with offset/limit pattern
34
+ - PDF generation functions (reportlab)
35
+ - cart session implementations
36
+ - URL configurations with namespaces
37
+ - model definitions with indexes and choices
38
+
39
+ quality:
40
+ reviewed_by: codeconductor-core
41
+ version: 0.1.0
42
+ ---
43
+
44
+ ## When to Use
45
+
46
+ - Writing any new view, service method, or API endpoint
47
+ - Designing a new feature and deciding where logic lives
48
+ - Adding a JSON API response
49
+ - Implementing a PDF report or cart operation
50
+ - Structuring the architecture of a new app
51
+
52
+ ## Django Project Structure
53
+
54
+ ### Recommended Apps
55
+
56
+ A well-structured Django project follows modular app patterns:
57
+
58
+ ```
59
+ apps/
60
+ ├── core/ # Configuration, shared models (Store)
61
+ ├── users/ # User model, authentication
62
+ ├── employees/ # Employees (tenant)
63
+ ├── catalog/ # Products, categories (tenant)
64
+ ├── cart/ # Storefront cart (tenant)
65
+ ├── orders/ # Orders (tenant)
66
+ ├── pos/ # Point of Sale (tenant)
67
+ ├── storefront/ # Public store (tenant)
68
+ └── analytics/ # Reports and metrics (tenant)
69
+ ```
70
+
71
+ ### Per-App File Structure
72
+
73
+ ```
74
+ apps/catalog/
75
+ ├── __init__.py
76
+ ├── models.py # Models (Product, Category, ProductImage)
77
+ ├── views.py # Views
78
+ ├── urls.py # Routes
79
+ ├── services.py # Business logic
80
+ ├── serializers.py # Serialization (if using DRF)
81
+ ├── reports.py # PDF reports
82
+ ├── signals.py # Signals
83
+ ├── admin.py # Admin config
84
+ ├── tests/
85
+ │ ├── __init__.py
86
+ │ └── test_{feature}.py
87
+ └── migrations/
88
+ ```
89
+
90
+ ## View Patterns
91
+
92
+ ### FBV vs CBV
93
+
94
+ | Type | When to Use | Examples |
95
+ | ------------------------ | ---------------------------------------------------------------------- | ----------------------------------------------------- |
96
+ | **FBV** (Function-Based) | All API endpoints, all POS/manager views, any view with business logic | `api_cart_add`, `api_search_products`, `pos_checkout` |
97
+ | **CBV** (Class-Based) | Only basic storefront list/detail | `HomeView`, `CategoryListView`, `ProductDetailView` |
98
+
99
+ **Rule**: CBV for generic read-only views with simple templates. FBV for
100
+ everything else (APIs, complex logic, POS).
101
+
102
+ ```python
103
+ # FBV — always for APIs
104
+ @require_pos_access
105
+ @require_POST
106
+ def api_cart_add(request):
107
+ cart = POSCart(request)
108
+ data = json.loads(request.body)
109
+ cart.add(data["product_id"], data["quantity"])
110
+ return JsonResponse({"success": True, "cart_count": cart.count()})
111
+
112
+ # CBV — only for basic storefront
113
+ class ProductDetailView(TemplateView):
114
+ template_name = "storefront/product.html"
115
+
116
+ def get_context_data(self, **kwargs):
117
+ ctx = super().get_context_data(**kwargs)
118
+ ctx["product"] = get_object_or_404(Product, slug=self.kwargs["slug"])
119
+ return ctx
120
+ ```
121
+
122
+ ### Decorator Order
123
+
124
+ Custom access decorator outermost, HTTP method decorator innermost:
125
+
126
+ ```python
127
+ @require_pos_access # outermost — runs first, guards access
128
+ @require_POST # innermost — closest to the function
129
+ def api_cart_add(request):
130
+ ...
131
+ ```
132
+
133
+ **Always use** `@require_POST` / `@require_GET` explicitly. Never
134
+ `if request.method == "POST"` inside an API view.
135
+
136
+ ## Service Layer
137
+
138
+ Business logic lives in `services.py` modules. Services are classes with
139
+ `@staticmethod` only — no instance state, no `__init__`:
140
+
141
+ ```python
142
+ class OrderService:
143
+ @staticmethod
144
+ def create_order(order: Order, cart: Cart) -> Order:
145
+ with transaction.atomic():
146
+ order.save()
147
+ OrderItem.objects.bulk_create(items)
148
+ Product.objects.bulk_update(products, ["stock"])
149
+ cart.clear()
150
+ return order
151
+
152
+ @staticmethod
153
+ def cancel_order(order_id: int, reason: str) -> Order:
154
+ ...
155
+ ```
156
+
157
+ Views call `OrderService.create_order(...)`. **No business logic in views.**
158
+
159
+ ### When to Create a Service
160
+
161
+ - Complex business logic involving multiple models
162
+ - Transactions spanning multiple DB operations
163
+ - Logic reusable across multiple views
164
+ - Anything that isn't "delegate to another component"
165
+
166
+ ## Naming Conventions
167
+
168
+ | Pattern | Convention | Examples |
169
+ | ---------------------- | -------------------------------------------- | --------------------------------------------------------------- |
170
+ | AJAX API views | `api_{resource}_{action}` | `api_cart_add`, `api_search_products`, `api_temporal_cart_save` |
171
+ | Module-private helpers | leading `_` | `_build_pos_order`, `_sort_by_category` |
172
+ | Module constants | `UPPER_SNAKE_CASE` | `VALID_PAYMENT_METHODS = {"cash", "transfer", "card"}` |
173
+ | URL names | `{scope}_{resource}_{action}` | `api_catalog_products`, `pos_checkout` |
174
+ | Service methods | `camelCase` (PEP8 inconsistent but accepted) | `createOrder`, `calculateTotal` |
175
+ | Model methods | `snake_case` | `get_display_price()`, `is_available()` |
176
+
177
+ ## JSON API Response Shapes
178
+
179
+ ### List Endpoint with Pagination
180
+
181
+ ```python
182
+ return JsonResponse({
183
+ "results": [...],
184
+ "total": N,
185
+ "has_more": bool,
186
+ })
187
+ ```
188
+
189
+ ### Successful Mutation
190
+
191
+ ```python
192
+ return JsonResponse({"success": True, "cart_count": N})
193
+ ```
194
+
195
+ ### Error Response
196
+
197
+ ```python
198
+ return JsonResponse({"success": False, "error": "error message"}, status=400)
199
+ ```
200
+
201
+ ### HTTP Status Codes
202
+
203
+ - `200` — OK, success
204
+ - `201` — Created
205
+ - `400` — Client error (invalid data, missing fields)
206
+ - `404` — Not found
207
+ - `500` — Server error
208
+
209
+ **Never return** `200` with `"success": false`. Use the correct status code.
210
+
211
+ ## Pagination
212
+
213
+ ### Offset/Limit — No Page Numbers
214
+
215
+ Always offset + limit, never page numbers. Default 20 items, max 100:
216
+
217
+ ```python
218
+ offset = int(request.GET.get("offset", 0))
219
+ limit = min(int(request.GET.get("limit", 20)), 100)
220
+
221
+ total = qs.count()
222
+ page = qs[offset:offset + limit]
223
+
224
+ return JsonResponse({
225
+ "results": list(page.values("id", "name", "price")),
226
+ "total": total,
227
+ "has_more": (offset + limit) < total,
228
+ })
229
+ ```
230
+
231
+ ## PDF Patterns
232
+
233
+ Pure functions, no classes. Take primitive data, return `bytes`. Internal
234
+ helpers prefixed with `_`:
235
+
236
+ ```python
237
+ import io
238
+ from reportlab.lib.pagesizes import A4
239
+ from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
240
+
241
+ def generate_restock_pdf(store_name: str, products_raw: list) -> bytes:
242
+ buffer = io.BytesIO()
243
+ doc = _make_doc(buffer)
244
+ story = _build_story(store_name, products_raw)
245
+ doc.build(story)
246
+ buffer.seek(0)
247
+ return buffer.read()
248
+
249
+ def _make_doc(buffer: io.BytesIO) -> SimpleDocTemplate:
250
+ return SimpleDocTemplate(
251
+ buffer,
252
+ pagesize=A4,
253
+ rightMargin=30,
254
+ leftMargin=30,
255
+ topMargin=30,
256
+ bottomMargin=30,
257
+ )
258
+
259
+ def _build_story(store_name: str, products_raw: list) -> list:
260
+ data = [["SKU", "Product", "Stock", "Min"]]
261
+ for p in products_raw:
262
+ data.append([p["sku"], p["name"], p["stock"], p["min_stock"]])
263
+ table = Table(data, colWidths=[60, 200, 50, 50])
264
+ table.setStyle(TableStyle([...]))
265
+ return [table]
266
+ ```
267
+
268
+ The view wraps the result in `HttpResponse`:
269
+
270
+ ```python
271
+ def api_restock_pdf(request):
272
+ products = Product.objects.filter(stock__lte=F("min_stock"))
273
+ pdf_bytes = generate_restock_pdf(request.store.name, list(products.values()))
274
+ response = HttpResponse(pdf_bytes, content_type="application/pdf")
275
+ response["Content-Disposition"] = 'inline; filename="restock.pdf"'
276
+ return response
277
+ ```
278
+
279
+ ## Cart Patterns
280
+
281
+ Two independent carts coexist per request. Session key is the only separator:
282
+
283
+ | Cart | Session Key | Module |
284
+ | ---------- | ----------- | ---------------------- |
285
+ | Storefront | `cart` | `apps/cart/cart.py` |
286
+ | POS | `pos_cart` | `apps/pos/pos_cart.py` |
287
+
288
+ Both follow the same contract:
289
+
290
+ - Initialize with `request`
291
+ - Store as `{str(product_id): {"quantity": int, "price": str}}`
292
+ - Price stored as `str` (Decimal is not JSON-serializable)
293
+ - Always call `self.session.modified = True` in `save()`
294
+
295
+ ```python
296
+ class POSCart:
297
+ def __init__(self, request):
298
+ self.session = request.session.get("pos_cart", {})
299
+
300
+ def add(self, product_id, quantity):
301
+ key = str(product_id)
302
+ if key in self.session:
303
+ self.session[key]["quantity"] += quantity
304
+ else:
305
+ self.session[key] = {"quantity": quantity, "price": "0.00"}
306
+ self.save()
307
+
308
+ def save(self):
309
+ self.session["pos_cart"] = self.session
310
+ self.session.modified = True
311
+ ```
312
+
313
+ ## Type Hints
314
+
315
+ **Minimal**: Only on public service/utility function signatures, not on views or
316
+ helpers:
317
+
318
+ ```python
319
+ # Service — annotate
320
+ def generate_restock_pdf(store_name: str, products_raw: list) -> bytes:
321
+ ...
322
+
323
+ # View — no annotations
324
+ def api_cart_add(request):
325
+ ...
326
+
327
+ # Private helpers — no annotations
328
+ def _build_cart_item(product, quantity):
329
+ ...
330
+ ```
331
+
332
+ ## Access Decorators
333
+
334
+ ### require_pos_access
335
+
336
+ Verifies the employee has POS access:
337
+
338
+ ```python
339
+ def require_pos_access(view):
340
+ def wrapper(request, *args, **kwargs):
341
+ if not request.user.is_authenticated:
342
+ return JsonResponse({"error": "Auth required"}, status=401)
343
+ if not request.user.is_superuser:
344
+ emp = EmployeeProfile.objects.get(user=request.user)
345
+ if not emp.has_pos_access:
346
+ return JsonResponse({"error": "No POS access"}, status=403)
347
+ return view(request, *args, **kwargs)
348
+ return wrapper
349
+ ```
350
+
351
+ ### require_manager_access
352
+
353
+ Verifies the employee is a manager:
354
+
355
+ ```python
356
+ def require_manager_access(view):
357
+ def wrapper(request, *args, **kwargs):
358
+ if not request.user.is_authenticated:
359
+ return JsonResponse({"error": "Auth required"}, status=401)
360
+ if not request.user.is_superuser:
361
+ emp = EmployeeProfile.objects.get(user=request.user)
362
+ if not emp.is_manager:
363
+ return JsonResponse({"error": "Manager required"}, status=403)
364
+ return view(request, *args, **kwargs)
365
+ return wrapper
366
+ ```
367
+
368
+ ## URLs and Routing
369
+
370
+ ### URL Structure
371
+
372
+ ```python
373
+ # apps/catalog/urls.py
374
+ from django.urls import path
375
+
376
+ urlpatterns = [
377
+ # API
378
+ path("api/products/", api_catalog_products, name="api_catalog_products"),
379
+ path("api/products/<int:pk>/", api_product_detail, name="api_product_detail"),
380
+ # Web
381
+ path("", product_list, name="catalog_product_list"),
382
+ path("<slug:slug>/", product_detail, name="catalog_product_detail"),
383
+ ]
384
+ ```
385
+
386
+ ### Namespaces
387
+
388
+ ```python
389
+ # config/urls.py
390
+ urlpatterns = [
391
+ path("catalog/", include("apps.catalog.urls", namespace="catalog")),
392
+ path("pos/", include("apps.pos.urls", namespace="pos")),
393
+ ]
394
+ ```
395
+
396
+ ## Models — Best Practices
397
+
398
+ ### Model Fields
399
+
400
+ ```python
401
+ class Product(models.Model):
402
+ name = models.CharField(max_length=255)
403
+ slug = models.SlugField(max_length=255, unique=True)
404
+ description = models.TextField(blank=True)
405
+ price = models.DecimalField(max_digits=10, decimal_places=2)
406
+ stock = models.PositiveIntegerField(default=0)
407
+ is_active = models.BooleanField(default=True)
408
+ created_at = models.DateTimeField(auto_now_add=True)
409
+ updated_at = models.DateTimeField(auto_now=True)
410
+
411
+ class Meta:
412
+ ordering = ["name"]
413
+ indexes = [
414
+ models.Index(fields=["is_active", "stock"]),
415
+ models.Index(fields=["slug"]),
416
+ ]
417
+
418
+ def __str__(self):
419
+ return self.name
420
+
421
+ @property
422
+ def is_available(self):
423
+ return self.is_active and (self.is_service or self.stock > 0)
424
+ ```
425
+
426
+ ### Choices
427
+
428
+ ```python
429
+ class Order(models.Model):
430
+ class Status(models.TextChoices):
431
+ PENDING = "pending", "Pending"
432
+ PAID = "paid", "Paid"
433
+ SHIPPED = "shipped", "Shipped"
434
+ CANCELLED = "cancelled", "Cancelled"
435
+
436
+ status = models.CharField(
437
+ max_length=20,
438
+ choices=Status.choices,
439
+ default=Status.PENDING,
440
+ )
441
+ ```
442
+
443
+ ## Code Quality
444
+
445
+ ### Line Length
446
+
447
+ 88 characters (Black + Ruff). Run before every commit:
448
+
449
+ ```bash
450
+ make format # black + ruff --fix
451
+ make lint # ruff check
452
+ uv run djlint . --reformat # templates
453
+ ```
454
+
455
+ Pre-commit hooks enforce Black and Ruff automatically.
456
+
457
+ ### Imports
458
+
459
+ ```python
460
+ # Standard library
461
+ import os
462
+ import json
463
+ from datetime import datetime
464
+
465
+ # Third party
466
+ from django.db import models
467
+ from django.http import JsonResponse
468
+ from django.views.decorators.http import require_POST
469
+
470
+ # Local
471
+ from apps.catalog.models import Product
472
+ from apps.pos.services import CartService
473
+ ```
474
+
475
+ ## Commands
476
+
477
+ ```bash
478
+ make run # dev server on 0.0.0.0:8000
479
+ make lint # ruff check
480
+ make format # black + ruff fix
481
+ make tests # pytest (--reuse-db --nomigrations by default)
482
+ make migrate # migrate_schemas --shared + --tenant
483
+ ```
484
+
485
+ ## Resources
486
+
487
+ - **FBV API examples**: `apps/pos/views.py`
488
+ - **Service layer**: `apps/orders/services.py`
489
+ - **PDF pattern**: `apps/catalog/reports.py`
490
+ - **Cart pattern**: `apps/pos/pos_cart.py`, `apps/cart/cart.py`
491
+ - **Pagination**: `apps/catalog/views.py` (api_catalog_products)
492
+ - **Django docs**: https://docs.djangoproject.com/en/5.2/