Communitygithub.com

django-security

Best Practices für Django-Sicherheit: Authentifizierung, Autorisierung, CSRF-Schutz, SQL-Injection-Prävention, XSS-Prävention und sichere Deployment-Konfigurationen. Verwenden Sie dies bei der Überprüfung von Django-Authentifizierung, Autorisierung, Eingabebehandlung oder Deployment-Einstellungen.

Was ist django-security?

Diese Skill-Richtlinie bietet umfassende Sicherheitsrichtlinien für Django-Anwendungen, die vor häufigen Schwachstellen wie CSRF, XSS, SQL-Injection und unsicheren Deployment-Konfigurationen schützen. Sie konzentriert sich auf die Implementierung bewährter Sicherheitspraktiken, einschließlich sicherer Produktionseinstellungen, Passwort-Hashing mit Argon2, Sitzungsverwaltung und der Erstellung benutzerdefinierter Benutzermodelle mit E-Mail als Benutzername. Entwickler können Codebeispiele für rollenbasierte Zugriffskontrolle (RBAC), benutzerdefinierte Berechtigungen für Django REST Framework und Middleware für Sicherheitsheader nutzen. Die Richtlinie behandelt auch Datei-Upload-Validierung mit Magic-Bytes, API-Ratenbegrenzung und JWT-Authentifizierung für REST-Endpunkte. Sie ist für die Verwendung mit Tools wie Claude Code, Cursor und Codex optimiert, die SKILL.md-Dokumentation interpretieren, um kontextbezogene Sicherheitsempfehlungen während der Django-Entwicklung zu geben.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/django-security

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Best Practices für Django-Sicherheit

Umfassende Sicherheitsrichtlinien für Django-Anwendungen zum Schutz vor häufigen Schwachstellen.

Wann zu aktivieren

  • Einrichten der Django-Authentifizierung und -Autorisierung
  • Implementieren von Benutzerberechtigungen und -rollen
  • Konfigurieren von Produktionssicherheitseinstellungen
  • Überprüfen einer Django-Anwendung auf Sicherheitsprobleme
  • Bereitstellen von Django-Anwendungen in der Produktion

Kern-Sicherheitseinstellungen

Produktionseinstellungen konfigurieren

# settings/production.py
import os

DEBUG = False  # KRITISCH: Niemals True in der Produktion verwenden

ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

# Sicherheitsheader
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000  # 1 Jahr
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'

# HTTPS und Cookies
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SAMESITE = 'Lax'

# Geheimer Schlüssel (muss über Umgebungsvariable gesetzt werden)
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
if not SECRET_KEY:
    raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')

# Passwortvalidierung
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 12,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

Authentifizierung

Benutzerdefiniertes Benutzermodell

# apps/users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """Benutzerdefiniertes Benutzermodell für bessere Sicherheit."""

    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=20, blank=True)

    USERNAME_FIELD = 'email'  # E-Mail als Benutzername verwenden
    REQUIRED_FIELDS = ['username']

    class Meta:
        db_table = 'users'
        verbose_name = 'Benutzer'
        verbose_name_plural = 'Benutzer'

    def __str__(self):
        return self.email

# settings/base.py
AUTH_USER_MODEL = 'users.User'

Passwort-Hashing

# Django verwendet standardmäßig PBKDF2. Für stärkere Sicherheit:
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

Sitzungsverwaltung

# Sitzungskonfiguration
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Oder 'db'
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 Woche
SESSION_SAVE_EVERY_REQUEST = False
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Bessere UX, aber weniger sicher

Autorisierung

Berechtigungen

# models.py
from django.db import models
from django.contrib.auth.models import Permission

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        permissions = [
            ('can_publish', 'Kann Beiträge veröffentlichen'),
            ('can_edit_others', 'Kann Beiträge anderer bearbeiten'),
        ]

    def user_can_edit(self, user):
        """Überprüfen, ob ein Benutzer diesen Beitrag bearbeiten kann."""
        return self.author == user or user.has_perm('app.can_edit_others')

# views.py
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import UpdateView

class PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
    model = Post
    permission_required = 'app.can_edit_others'
    raise_exception = True  # 403 anstelle einer Weiterleitung zurückgeben

    def get_queryset(self):
        """Nur Benutzern erlauben, ihre eigenen Beiträge zu bearbeiten."""
        return Post.objects.filter(author=self.request.user)

Benutzerdefinierte Berechtigungen

# permissions.py
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """Nur Eigentümern erlauben, Objekte zu bearbeiten."""

    def has_object_permission(self, request, view, obj):
        # Leseberechtigungen sind für jede Anfrage erlaubt
        if request.method in permissions.SAFE_METHODS:
            return True

        # Schreibberechtigungen nur für den Eigentümer
        return obj.author == request.user

class IsAdminOrReadOnly(permissions.BasePermission):
    """Administratoren dürfen alles, andere haben Nur-Lese-Zugriff."""

    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return True
        return request.user and request.user.is_staff

class IsVerifiedUser(permissions.BasePermission):
    """Nur verifizierten Benutzern Zugriff gewähren."""

    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated and request.user.is_verified

Rollenbasierte Zugriffskontrolle (RBAC)

# models.py
from django.contrib.auth.models import AbstractUser, Group

class User(AbstractUser):
    ROLE_CHOICES = [
        ('admin', 'Administrator'),
        ('moderator', 'Moderator'),
        ('user', 'Regulärer Benutzer'),
    ]
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')

    def is_admin(self):
        return self.role == 'admin' or self.is_superuser

    def is_moderator(self):
        return self.role in ['admin', 'moderator']

# Mixins
class AdminRequiredMixin:
    """Mixin, um die Admin-Rolle zu erzwingen."""

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated or not request.user.is_admin():
            from django.core.exceptions import PermissionDenied
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

SQL-Injection-Prävention

Django ORM-Schutz

# GUT: Das Django ORM maskiert Parameter automatisch
def get_user(username):
    return User.objects.get(username=username)  # Sicher

# GUT: Verwendung von Parametern mit raw()
def search_users(query):
    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])

# SCHLECHT: Niemals Benutzereingaben direkt interpolieren
def get_user_bad(username):
    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # ANGREIFBAR!

# GUT: Verwendung von filter mit ordnungsgemäßer Maskierung
def get_users_by_email(email):
    return User.objects.filter(email__iexact=email)  # Sicher

# GUT: Verwendung von Q-Objekten für komplexe Abfragen
from django.db.models import Q
def search_users_complex(query):
    return User.objects.filter(
        Q(username__icontains=query) |
        Q(email__icontains=query)
    )  # Sicher

Zusätzliche Sicherheit mit raw()

# Wenn Sie raw SQL verwenden müssen, verwenden Sie immer Parameter
User.objects.raw(
    'SELECT * FROM users WHERE email = %s AND status = %s',
    [user_input_email, status]
)

XSS-Prävention

Template-Escaping

{# Django maskiert Variablen standardmäßig automatisch - SICHER #}
{{ user_input }}  {# Maskiertes HTML #}

{# Explizit als sicher markieren nur für vertrauenswürdige Inhalte #}
{{ trusted_html|safe }}  {# Nicht maskiert #}

{# Template-Filter für sicheres HTML verwenden #}
{{ user_input|escape }}  {# Gleiches Verhalten wie Standard #}
{{ user_input|striptags }}  {# Alle HTML-Tags entfernen #}

{# JavaScript-Escaping #}
<script>
    var username = {{ username|escapejs }};
</script>

Sichere String-Behandlung

from django.utils.safestring import mark_safe
from django.utils.html import escape

# SCHLECHT: Niemals Benutzereingaben ohne Escaping als sicher markieren
def render_bad(user_input):
    return mark_safe(user_input)  # ANGREIFBAR!

# GUT: Zuerst maskieren, dann als sicher markieren
def render_good(user_input):
    return mark_safe(escape(user_input))

# GUT: format_html für HTML mit Variablen verwenden
from django.utils.html import format_html

def greet_user(username):
    return format_html('<span class="user">{}</span>', escape(username))

HTTP-Header

# settings.py
SECURE_CONTENT_TYPE_NOSNIFF = True  # MIME-Sniffing verhindern
SECURE_BROWSER_XSS_FILTER = True  # XSS-Filter aktivieren
X_FRAME_OPTIONS = 'DENY'  # Clickjacking verhindern

# Benutzerdefinierte Middleware
from django.conf import settings

class SecurityHeaderMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response['X-Content-Type-Options'] = 'nosniff'
        response['X-Frame-Options'] = 'DENY'
        response['X-XSS-Protection'] = '1; mode=block'
        response['Content-Security-Policy'] = "default-src 'self'"
        return response

CSRF-Schutz

Standard-CSRF-Schutz

# settings.py - CSRF ist standardmäßig aktiviert
CSRF_COOKIE_SECURE = True  # Nur über HTTPS senden
CSRF_COOKIE_HTTPONLY = True  # JavaScript-Zugriff verhindern
CSRF_COOKIE_SAMESITE = 'Lax'  # CSRF in bestimmten Fällen verhindern
CSRF_TRUSTED_ORIGINS = ['https://example.com']  # Vertrauenswürdige Domains

# Template-Verwendung
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Absenden</button>
</form>

# AJAX-Anfragen
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

fetch('/api/endpoint/', {
    method: 'POST',
    headers: {
        'X-CSRFToken': getCookie('csrftoken'),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(data)
});

Ansichten ausnehmen (Vorsicht walten lassen)

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt  # Nur verwenden, wenn unbedingt nötig!
def webhook_view(request):
    # Webhook von einem externen Dienst
    pass

Datei-Upload-Sicherheit

Datei-Validierung

import os
import magic  # pip install python-magic
from django.core.exceptions import ValidationError

ALLOWED_MIMES = {
    'image/jpeg', 'image/png', 'image/gif', 'application/pdf',
}

MIME_TO_EXTENSIONS = {
    'image/jpeg': {'.jpg', '.jpeg'},
    'image/png': {'.png'},
    'image/gif': {'.gif'},
    'application/pdf': {'.pdf'},
}

def validate_file_type(value):
    """Dateityp mit Magic-Bytes validieren und Erweiterung gegenprüfen."""
    mime = magic.from_buffer(value.read(2048), mime=True)
    value.seek(0)

    if mime not in ALLOWED_MIMES:
        raise ValidationError('Nicht unterstützter Dateityp.')

    ext = os.path.splitext(value.name)[1].lower()
    if ext not in MIME_TO_EXTENSIONS.get(mime, set()):
        raise ValidationError('Dateierweiterung stimmt nicht mit dem Dateiinhalt überein.')

def validate_file_size(value):
    """Dateigröße validieren (max. 5 MB)."""
    if value.size > 5 * 1024 * 1024:
        raise ValidationError('Datei zu groß. Maximale Größe beträgt 5 MB.')

# models.py
class Document(models.Model):
    file = models.FileField(
        upload_to='documents/',
        validators=[validate_file_type, validate_file_size]
    )

Für Umgebungen, in denen die Installation von libmagic schwierig ist (z. B. minimale Container), verwenden Sie das reine Python-Paket filetype als Alternative:

import os
from django.core.exceptions import ValidationError

import filetype  # pip install filetype

ALLOWED_MIMES = {
    'image/jpeg', 'image/png', 'image/gif', 'application/pdf',
}

MIME_TO_EXTENSIONS = {
    'image/jpeg': {'.jpg', '.jpeg'},
    'image/png': {'.png'},
    'image/gif': {'.gif'},
    'application/pdf': {'.pdf'},
}

def validate_file_type(value):
    """Dateityp mit Magic-Bytes validieren."""
    kind = filetype.guess(value.read(2048))
    value.seek(0)

    if kind is None or kind.mime not in ALLOWED_MIMES:
        raise ValidationError('Nicht unterstützter Dateityp.')

    ext = os.path.splitext(value.name)[1].lower()
    if ext not in MIME_TO_EXTENSIONS.get(kind.mime, set()):
        raise ValidationError('Dateierweiterung stimmt nicht mit dem Dateiinhalt überein.')

Sicherer Dateispeicher

# settings.py
MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = '/media/'

# In der Produktion eine separate Domain für Medien verwenden
MEDIA_DOMAIN = 'https://media.example.com'

# Benutzer-Uploads nicht direkt bereitstellen
# whitenoise oder ein CDN für statische Dateien verwenden
# Einen separaten Server oder S3 für Mediendateien verwenden

API-Sicherheit

Ratenbegrenzung

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day',
        'upload': '10/hour',
    }
}

# Benutzerdefinierte Ratenbegrenzung
from rest_framework.throttling import UserRateThrottle

class BurstRateThrottle(UserRateThrottle):
    scope = 'burst'
    rate = '60/min'

class SustainedRateThrottle(UserRateThrottle):
    scope = 'sustained'
    rate = '1000/day'

Authentifizierung für APIs

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

# views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def user_profile(request):
    pass

Sichere Deployment-Konfiguration

Umgebungsvariablen

# settings.py
import os
from dotenv import load_dotenv

load_dotenv()

SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
DATABASE_URL = os.environ.get('DATABASE_URL')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

HTTPS-Konfiguration

# settings/production.py
MIDDLEWARE = [
    # Sicherheits-Middleware sollte zuerst kommen
    'django.middleware.security.SecurityMiddleware',
    # ... andere Middleware
]

# HTTPS-Weiterleitung
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Sicherheits-Checks

# deployment_check.py
from django.conf import settings
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Überprüft die Sicherheitseinstellungen'

    def handle(self, *args, **options):
        checks = [
            ('DEBUG ist False', not settings.DEBUG),
            ('SECRET_KEY ist gesetzt', bool(settings.SECRET_KEY)),
            ('ALLOWED_HOSTS sind konfiguriert', bool(settings.ALLOWED_HOSTS)),
            ('SESSION_COOKIE_SECURE ist True', settings.SESSION_COOKIE_SECURE),
            ('CSRF_COOKIE_SECURE ist True', settings.CSRF_COOKIE_SECURE),
            ('SECURE_SSL_REDIRECT ist True', settings.SECURE_SSL_REDIRECT),
            ('SECURE_HSTS_SECONDS ist gesetzt', settings.SECURE_HSTS_SECONDS > 0),
        ]

        for check_name, result in checks:
            status = '✓' if result else '✗'
            self.stdout.write(f'{status} {check_name}')

        self.stdout.write(self.style.SUCCESS('Sicherheitscheck abgeschlossen'))

Weitere Sicherheitsüberlegungen

  • Content Security Policy (CSP) implementieren
  • Subresource Integrity (SRI) für externe Skripte verwenden
  • Übermäßige Datenweitergabe in API-Antworten vermeiden
  • Alles protokollieren, was sicherheitsrelevant ist
  • Regelmäßig python manage.py check --deploy ausführen
  • Abhängigkeiten aktuell halten: pip audit verwenden
  • django-csp in Betracht ziehen
  • Zwei-Faktor-Authentifizierung mit django-otp implementieren

Nützliche Tools

  • bandit – Sicherheitslücken-Scanner für Python
  • safety – Bekannte Schwachstellen in Abhängigkeiten prüfen
  • pip audit – Python-Pakete auf Sicherheitslücken prüfen
  • django-csp – Content Security Policy für Django
  • django-axes – Brute-Force-Angriffe erkennen und blockieren
  • django-otp – Zwei-Faktor-Authentifizierung
  • django-ratelimit – Ratenbegrenzung für Ansichten

Referenzen

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Verwandte Skills