agent

backend

**Identity**: You are an expert Django 5 / Python 3.13 developer working on a multi-tenant SaaS for e-commerce returns management. **Objective**: Maintain high code quality, follow strict architectura

$ curl -fsSL https://skills.reveni.dev/install.sh | bash

AI Agent Instructions - Reveni Backend

Identity: You are an expert Django 5 / Python 3.13 developer working on a multi-tenant SaaS for e-commerce returns management. Objective: Maintain high code quality, follow strict architectural patterns, and leverage existing tooling.


1. Tech Stack & Structure

Tech Stack

Layer Technology
Language Python 3.13
Framework Django 5.x, Django REST Framework
Async Celery (Workers & Beat), Redis/Valkey
Database PostgreSQL 17, django-safedelete, cacheops
Deployment Docker/Docker Compose, Digital Ocean App Platform
Tooling Poetry, uv, ruff, pre-commit, pytest, mypy

Directory Structure

apps/
├── accounts/          # Merchants, Stores, Customers
├── orders/            # Orders, Returns, Line Items
├── deliveries/        # Shipping, Carriers, Labels
├── payments/          # Payment gateways (polymorphic)
├── integrations/      # E-commerce connectors (Shopify, Magento...)
├── billing/           # Fees, Invoicing
├── notifications/     # Email, SMS, Webhooks
├── events/            # Event tracking
├── metrics/           # Analytics
├── underwriting/      # Risk assessment
├── core/              # Shared utilities, base models
├── users/             # User roles, permissions
└── api/               # REST API (host-segregated)
    ├── merchants/     # Dashboard API
    ├── returns/       # Public Returns Portal
    ├── customers/     # Customer Dashboard
    ├── platforms/     # Webhook ingestion
    ├── public/        # Public API (docs: reveni.readme.io)
    └── common/        # Shared mixins, generics

App File Patterns

File Purpose
models.py Rich Models with Mixins. Core business logic lives here.
managers.py Query logic, custom QuerySets. NO selectors.py.
services.py Process orchestration (reports, complex workflows).
connectors.py External API integrations. Inherit AbstractConnector.
helpers.py Platform-specific logic (e.g., ReturnsHelper).
choices.py Enums for model fields. Critical for migrations.
tasks.py or tasks/ Celery async jobs.
signals/ Django signals. Receivers in signals.py.
tests/factories.py Factory Boy factories for tests.

Nested Modules Pattern

Complex apps use modules/ subdirectories:

apps/orders/modules/
├── discounts/      # Discount logic
├── eligibility/    # Eligibility rules
├── inventory/      # Stock management
└── recoveries/     # Recovery workflows

Each module has its own models.py, managers.py, services.py, tests/.


2. Command Center (Makefile)

ALWAYS use these commands. Never run python manage.py directly on host.

Goal Command Notes
Start Dev make up Starts all services in background
Bash Shell make shell Bash inside Django container
Django Shell make sh shell_plus with models pre-loaded
Run Tests make test ARGS="path" pytest with --reuse-db
Lint/Check make pre-commit ruff, mypy. Run before review.
Migrations make migrations Creates migrations inside docker

3. Architectural Patterns

A. Rich Models & Mixins

Models contain business logic, split into mixins for manageability:

class Order(RejectionRulesMixin, WithUnderWritingEngine, AbstractTimeStampedUUID):
    # Core fields + business methods

B. Integration Layer (apps/integrations/)

C. Payment Layer (apps/payments/)

D. Delivery Layer (apps/deliveries/)

E. API Layer (Host-Segregated)

APIs are organized by consumer, not resource:

Directory Host Consumer
api/merchants/ merchants-api Merchant Dashboard
api/returns/ returns-api End-customer Portal
api/customers/ customers-api Customer Dashboard
api/platforms/ platforms-api Webhook ingestion
api/public/ api Third-party integrations

Key Patterns:

F. Services Layer

Reserved for process orchestration, not CRUD:

@dataclass
class ProcessReturnRequest:
    order_id: str
    items: list[ReturnableLineItem]
    reason: str

G. Signals & Events


4. Rules of Engagement (CRITICAL)

A. Migrations & Choices

ALWAYS import choices from choices.py. NEVER inline in migrations.

# CORRECT
from apps.accounts import choices

class Migration(migrations.Migration):
    operations = [
        migrations.AddField(
            model_name="store",
            name="status",
            field=models.CharField(choices=choices.Merchant.Status.choices, max_length=50),
        ),
    ]

# WRONG - causes new migrations on every choice change
field=models.CharField(choices=[("active", "Active"), ("inactive", "Inactive")])

B. Testing Standards

Rule Details
Engine pytest + pytest-xdist (parallel)
Factories Use factory_boy in tests/factories.py. NO Model.objects.create()
Assertions Use bare assert x == y. NO self.assertEqual()
Naming Test classes use suffix: OrderTest, ReturnTest. NEVER TestOrder, TestReturn
Coverage Strict 97.5% threshold. Do not break.
Signals Muted by default. Use @pytest.mark.enable_signals when needed
Full Suite Don't run unless told to (tests are slow)
# Factory example
class StoreFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Store
    merchant = factory.SubFactory(MerchantFactory)
    preferences__with_all_allowed_orders = True

C. Form Tests vs View Tests (API Layer)

Test validation logic in form tests, NOT view tests. Forms are DRF serializers that validate input and return typed objects (dataclasses).

Test Type Location What to Test
Form tests api/*/forms/tests/ Field validation, business rules, error messages, validated_data output
View tests api/*/tests/ HTTP status codes, auth, response serialization, side effects
# CORRECT - Form test (fast, isolated)
# apps/api/merchants/forms/tests/test_orders.py
def test_reject_without_reason(self):
    form = self.form(self.ret, {"status": Status.REJECTED}, context=self.context)
    assert not form.is_valid()
    assert "reject_reason is required" in form.errors["non_field_errors"]

# CORRECT - View test (integration)
# apps/api/customers/tests/test_api.py
def test_ok(self):
    response = self.client.post(self.url, data={"tracking_number": "test"})
    assert response.status_code == status.HTTP_204_NO_CONTENT

# WRONG - Testing form validation in view test
def test_required_fields(self):  # ← Should be in form test!
    response = self.client.post(self.url, {})
    assert response.json() == {"order_number": ["This field is required."]}

D. Type Safety

E. Code Style


5. Anti-Patterns (DO NOT)

Pattern Why Not Instead
selectors.py Not our pattern Use Manager methods
use_cases/ No clean architecture Use services.py
Cross-host imports Violates host segregation Import from api/common/ only
Generic views for complex logic Hard to maintain Use APIView + Serializer
Hardcoded choices in migrations Causes migration churn Import from choices.py
self.assertEqual() Not pytest style Use bare assert
TestXXX naming Wrong convention Use XXXTest suffix
Excessive comments Makes code noisy Comment only when necessary
Running full test suite Very slow Run specific tests
Co-Authored-By in commits Not wanted Omit entirely
Form validation in view tests Slow, duplicates coverage Test in forms/tests/

6. Developer Cheatsheet

If you want to... Look in...
Add a field to Order apps/orders/models.py (maybe a Mixin)
Add Store configuration apps/accounts/models.py (Merchant & Store)
Integrate new e-commerce apps/integrations/[name]/, implement AbstractConnector
Integrate new carrier apps/deliveries/providers/[name]/
Add API endpoint apps/api/[host]/views.py AND forms/[name].py
Fix complex query managers.py of relevant model
Debug payment error apps/payments/gateways/[provider]/models.py
Add async task apps/[app]/tasks.py, use @shared_task
Add custom signal apps/[app]/signals/signals.py

7. Environment & Setup

Required Files

.envs/.local/.django      # Local Django env
.envs/.local/.postgres    # Local Postgres env
.envs/.tests/.django      # CI test env

Hosts File (/etc/hosts)

127.0.0.1 reveni.local api.reveni.local admin.reveni.local platforms.reveni.local customers-api.reveni.local returns-api.reveni.local merchants-api.reveni.local

Celery Notes


8. Workflow: New Feature

  1. Plan: Identify which apps/ are involved
  2. Model: Define data in models.py (use Mixins if complex)
  3. Migration: make migrations - CHECK for hardcoded choices
  4. Manager: Add query methods to managers.py if needed
  5. Service: Complex logic in services.py (use @dataclass for params)
  6. API: Expose via api/[host]/views.py + forms/[name].py
  7. Test: Write tests with factories, mirroring service logic
  8. Lint: make pre-commit before requesting review

9. Key Configuration Files

File Purpose
pyproject.toml Tool config (pytest, mypy, ruff, coverage)
.pre-commit-config.yaml Pre-commit hooks
Makefile Command interface
docker/local.yml Docker Compose services
config/celery_scheduler.py Celery Beat schedule
config/hosts.py Django-hosts configuration
conftest.py Pytest fixtures, signal muting