Taskflow backend

Backend Orchestrator Skill

install
source · Clone the upstream repo
git clone https://github.com/Brownbull/taskflow
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Brownbull/taskflow "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/orchestrators/backend" ~/.claude/skills/brownbull-taskflow-backend && rm -rf "$T"
manifest: .claude/skills/orchestrators/backend/skill.md
source content

Backend Orchestrator Skill

Purpose

Manages all backend development tasks including API design, service implementation, database operations, business logic, and backend testing using Django/Python by default.

Tier

Tier 0-2 - Pre-Launch to Growth

When to Use

  • Building REST APIs
  • Implementing business logic
  • Database design and operations
  • Service integrations
  • Authentication/authorization
  • Background job processing

Technology Stack

Default Stack

framework: "Django 4.2+"
language: "Python 3.11+"
database: "PostgreSQL"
cache: "Redis"
task_queue: "Celery"
api_framework: "Django REST Framework"
testing: "pytest + factory_boy"
authentication: "Django Auth + JWT"

Alternative Options

  • FastAPI for microservices
  • Flask for lightweight APIs
  • Node.js/Express for JavaScript teams
  • MySQL for different DB needs

API Architecture

RESTful Design

# apps/payments/views.py
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response

class PaymentViewSet(viewsets.ModelViewSet):
    """
    API endpoint for payment operations
    """
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer
    permission_classes = [IsAuthenticated]

    def create(self, request):
        """POST /api/payments/"""
        # 1. Validate input
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 2. Business logic
        payment = self.perform_payment(serializer.validated_data)

        # 3. Response
        return Response(
            PaymentSerializer(payment).data,
            status=status.HTTP_201_CREATED
        )

    @action(detail=True, methods=['post'])
    def refund(self, request, pk=None):
        """POST /api/payments/{id}/refund/"""
        payment = self.get_object()
        refund = payment.process_refund(request.data.get('amount'))
        return Response(RefundSerializer(refund).data)

API Versioning

# urls.py
urlpatterns = [
    path('api/v1/', include('apps.v1.urls')),
    path('api/v2/', include('apps.v2.urls')),
]

Database Design

Model Structure

# apps/payments/models.py
from django.db import models
from django.contrib.auth import get_user_model

class Payment(models.Model):
    """Payment transaction model"""

    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('processing', 'Processing'),
        ('completed', 'Completed'),
        ('failed', 'Failed'),
        ('refunded', 'Refunded'),
    ]

    # Relations
    user = models.ForeignKey(
        get_user_model(),
        on_delete=models.PROTECT,
        related_name='payments'
    )

    # Fields
    amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0.01)]
    )
    currency = models.CharField(max_length=3, default='USD')
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )

    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'payments'
        indexes = [
            models.Index(fields=['user', 'status']),
            models.Index(fields=['created_at']),
        ]

    def process(self):
        """Process the payment"""
        # Business logic here
        pass

Migration Strategy

# apps/payments/migrations/0001_initial.py
class Migration(migrations.Migration):
    dependencies = []

    operations = [
        migrations.CreateModel(
            name='Payment',
            fields=[
                # Field definitions
            ],
        ),
        migrations.RunSQL(
            "CREATE INDEX idx_payment_status ON payments(status);",
            reverse_sql="DROP INDEX idx_payment_status;"
        ),
    ]

Service Layer

Business Logic

# apps/payments/services.py
from typing import Optional
from decimal import Decimal

class PaymentService:
    """Encapsulates payment business logic"""

    def create_payment(
        self,
        user: User,
        amount: Decimal,
        payment_method: str
    ) -> Payment:
        """
        Create and process a payment
        """
        # 1. Validate
        self._validate_payment_method(payment_method)
        self._check_user_limits(user, amount)

        # 2. Create payment
        payment = Payment.objects.create(
            user=user,
            amount=amount,
            status='pending'
        )

        # 3. Process asynchronously
        process_payment_task.delay(payment.id)

        return payment

    def _validate_payment_method(self, method: str) -> None:
        """Validate payment method"""
        if method not in ALLOWED_METHODS:
            raise ValidationError(f"Invalid payment method: {method}")

    def _check_user_limits(self, user: User, amount: Decimal) -> None:
        """Check user transaction limits"""
        daily_total = self._get_daily_total(user)
        if daily_total + amount > user.daily_limit:
            raise ValidationError("Daily limit exceeded")

Authentication & Authorization

JWT Authentication

# apps/authentication/views.py
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class CustomTokenSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        token['role'] = user.role
        return token

class LoginView(TokenObtainPairView):
    serializer_class = CustomTokenSerializer

Permission Classes

# apps/core/permissions.py
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """
    def has_object_permission(self, request, view, obj):
        # Read permissions for any request
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions only for owner
        return obj.user == request.user

Testing Strategy

All 8 Test Types

# tests/test_payment_api.py
import pytest
from rest_framework.test import APIClient

class TestPaymentAPI:
    """Payment API test suite"""

    # 1. Valid: Happy path
    def test_create_payment_success(self, api_client, user):
        response = api_client.post('/api/payments/', {
            'amount': 100.00,
            'method': 'credit_card'
        })
        assert response.status_code == 201

    # 2. Error: Handle failures
    def test_payment_gateway_error(self, api_client, mock_gateway_error):
        response = api_client.post('/api/payments/', {...})
        assert response.status_code == 502

    # 3. Invalid: Input validation
    def test_negative_amount_rejected(self, api_client):
        response = api_client.post('/api/payments/', {
            'amount': -10.00
        })
        assert response.status_code == 400

    # 4. Edge: Boundary conditions
    def test_minimum_payment_amount(self, api_client):
        response = api_client.post('/api/payments/', {
            'amount': 0.01
        })
        assert response.status_code == 201

    # 5. Functional: Business logic
    def test_daily_limit_enforcement(self, api_client, user_at_limit):
        response = api_client.post('/api/payments/', {...})
        assert response.status_code == 400

    # 6. Visual: API response format
    def test_response_structure(self, api_client):
        response = api_client.get('/api/payments/')
        assert 'results' in response.data
        assert 'count' in response.data

    # 7. Performance: Response time
    def test_api_response_time(self, api_client, django_benchmark):
        with django_benchmark:
            response = api_client.get('/api/payments/')
        assert django_benchmark.elapsed < 0.2

    # 8. Security: Authorization
    def test_unauthorized_access_denied(self, api_client):
        api_client.logout()
        response = api_client.get('/api/payments/')
        assert response.status_code == 401

Background Tasks

Celery Tasks

# apps/payments/tasks.py
from celery import shared_task
from django.core.mail import send_mail

@shared_task(bind=True, max_retries=3)
def process_payment_task(self, payment_id):
    """Process payment asynchronously"""
    try:
        payment = Payment.objects.get(id=payment_id)
        payment.process()
        send_payment_confirmation.delay(payment_id)
    except Payment.DoesNotExist:
        raise
    except Exception as exc:
        # Retry with exponential backoff
        raise self.retry(exc=exc, countdown=2 ** self.request.retries)

@shared_task
def send_payment_confirmation(payment_id):
    """Send confirmation email"""
    payment = Payment.objects.get(id=payment_id)
    send_mail(
        'Payment Confirmation',
        f'Your payment of {payment.amount} has been processed.',
        'noreply@example.com',
        [payment.user.email],
    )

Error Handling

Global Exception Handler

# apps/core/exceptions.py
from rest_framework.views import exception_handler
from rest_framework.response import Response

def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if response is not None:
        custom_response_data = {
            'error': {
                'status': response.status_code,
                'message': response.data.get('detail', str(exc)),
                'timestamp': datetime.now().isoformat(),
                'path': context['request'].path
            }
        }
        response.data = custom_response_data

    return response

Performance Optimization

Database Optimization

# Query optimization
payments = Payment.objects.select_related('user') \
                         .prefetch_related('items') \
                         .filter(status='completed') \
                         .only('id', 'amount', 'created_at')

# Database indexing
class Meta:
    indexes = [
        models.Index(fields=['user', 'status']),
        models.Index(fields=['created_at']),
    ]

Caching Strategy

from django.core.cache import cache

def get_user_payment_summary(user_id):
    cache_key = f'payment_summary_{user_id}'
    summary = cache.get(cache_key)

    if summary is None:
        summary = calculate_payment_summary(user_id)
        cache.set(cache_key, summary, timeout=3600)

    return summary

Quality Standards

  • API response time: < 200ms (p95)
  • Test coverage: > 80%
  • Code complexity: < 10 (McCabe)
  • Database queries: < 10 per request
  • Error rate: < 0.1%
  • Security: OWASP Top 10 compliance

File Structure

apps/
├── authentication/
├── payments/
│   ├── __init__.py
│   ├── models.py
│   ├── views.py
│   ├── serializers.py
│   ├── services.py
│   ├── tasks.py
│   ├── urls.py
│   └── tests/
├── core/
│   ├── permissions.py
│   ├── exceptions.py
│   └── middleware.py
└── tests/

Integration Points

  • Receives from: main-orchestrator
  • Provides APIs to: frontend-orchestrator
  • Communicates with: Database, Redis, External APIs
  • Outputs to: test-orchestrator

Common Patterns

  • Repository Pattern: Data access abstraction
  • Service Layer: Business logic encapsulation
  • Factory Pattern: Object creation
  • Strategy Pattern: Payment processors
  • Observer Pattern: Event handling

Anti-Patterns to Avoid

  • Fat models (> 200 lines)
  • Business logic in views
  • Synchronous heavy operations
  • N+1 queries
  • Missing input validation
  • Hardcoded secrets
  • Poor error messages