feat: Memory-Konzept für Agents implementieren (STI-21)
- REST API: 9 Read-Only-Endpunkte unter /api/v1/ für alle Kernmodelle (Destinatäre, Ländereien, Pächter, Förderungen, Konten, Verpachtungen, Verwaltungskosten, Kalender, Transaktionen) - Token-Authentifizierung via DRF TokenAuthentication - Management-Command `create_agent_token` für Agent-Tokens - Wissensbasis: knowledge/ mit Satzung, Richtlinien, Verfahren, Kontakte, Historie - Agent-Instructions: Datenzugriff-Sektion in AGENTS.md dokumentiert Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ INSTALLED_APPS = [
|
||||
"django.contrib.staticfiles",
|
||||
"django.contrib.humanize",
|
||||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
"django_otp",
|
||||
"django_otp.plugins.otp_totp",
|
||||
"django_otp.plugins.otp_static",
|
||||
@@ -99,6 +100,15 @@ STATICFILES_DIRS = [
|
||||
]
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||
"rest_framework.authentication.TokenAuthentication",
|
||||
],
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.IsAuthenticated",
|
||||
],
|
||||
}
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = BASE_DIR / "media"
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from django.urls import include, path
|
||||
from stiftung.views import home
|
||||
|
||||
urlpatterns = [
|
||||
path("api/v1/", include("stiftung.api_urls")),
|
||||
path("", include("stiftung.urls")),
|
||||
path("admin/", admin.site.urls),
|
||||
# Authentication URLs
|
||||
|
||||
88
app/stiftung/api_serializers.py
Normal file
88
app/stiftung/api_serializers.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import (
|
||||
BankTransaction,
|
||||
Destinataer,
|
||||
DestinataerUnterstuetzung,
|
||||
Foerderung,
|
||||
Land,
|
||||
LandVerpachtung,
|
||||
Paechter,
|
||||
StiftungsKalenderEintrag,
|
||||
StiftungsKonto,
|
||||
Verwaltungskosten,
|
||||
)
|
||||
|
||||
|
||||
class DestinataerUnterstuetzungSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = DestinataerUnterstuetzung
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class DestinataerSerializer(serializers.ModelSerializer):
|
||||
unterstuetzungen = DestinataerUnterstuetzungSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Destinataer
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class LandVerpachtungSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = LandVerpachtung
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class LandSerializer(serializers.ModelSerializer):
|
||||
aktive_verpachtungen = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Land
|
||||
fields = "__all__"
|
||||
|
||||
def get_aktive_verpachtungen(self, obj):
|
||||
qs = obj.neue_verpachtungen.filter(status="aktiv")
|
||||
return LandVerpachtungSerializer(qs, many=True).data
|
||||
|
||||
|
||||
class PaechterSerializer(serializers.ModelSerializer):
|
||||
aktive_verpachtungen = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Paechter
|
||||
fields = "__all__"
|
||||
|
||||
def get_aktive_verpachtungen(self, obj):
|
||||
qs = obj.neue_verpachtungen.filter(status="aktiv")
|
||||
return LandVerpachtungSerializer(qs, many=True).data
|
||||
|
||||
|
||||
class FoerderungSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Foerderung
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class StiftungsKontoSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = StiftungsKonto
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class VerwaltungskostenSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Verwaltungskosten
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class StiftungsKalenderEintragSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = StiftungsKalenderEintrag
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class BankTransactionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = BankTransaction
|
||||
fields = "__all__"
|
||||
26
app/stiftung/api_urls.py
Normal file
26
app/stiftung/api_urls.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from .api_views import (
|
||||
BankTransactionViewSet,
|
||||
DestinataerViewSet,
|
||||
FoerderungViewSet,
|
||||
LandVerpachtungViewSet,
|
||||
LandViewSet,
|
||||
PaechterViewSet,
|
||||
StiftungsKalenderEintragViewSet,
|
||||
StiftungsKontoViewSet,
|
||||
VerwaltungskostenViewSet,
|
||||
)
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r"destinataere", DestinataerViewSet)
|
||||
router.register(r"laendereien", LandViewSet)
|
||||
router.register(r"paechter", PaechterViewSet)
|
||||
router.register(r"foerderungen", FoerderungViewSet)
|
||||
router.register(r"konten", StiftungsKontoViewSet)
|
||||
router.register(r"verpachtungen", LandVerpachtungViewSet)
|
||||
router.register(r"verwaltungskosten", VerwaltungskostenViewSet)
|
||||
router.register(r"kalender", StiftungsKalenderEintragViewSet)
|
||||
router.register(r"transaktionen", BankTransactionViewSet)
|
||||
|
||||
urlpatterns = router.urls
|
||||
69
app/stiftung/api_views.py
Normal file
69
app/stiftung/api_views.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
from .api_serializers import (
|
||||
BankTransactionSerializer,
|
||||
DestinataerSerializer,
|
||||
FoerderungSerializer,
|
||||
LandSerializer,
|
||||
LandVerpachtungSerializer,
|
||||
PaechterSerializer,
|
||||
StiftungsKalenderEintragSerializer,
|
||||
StiftungsKontoSerializer,
|
||||
VerwaltungskostenSerializer,
|
||||
)
|
||||
from .models import (
|
||||
BankTransaction,
|
||||
Destinataer,
|
||||
Foerderung,
|
||||
Land,
|
||||
LandVerpachtung,
|
||||
Paechter,
|
||||
StiftungsKalenderEintrag,
|
||||
StiftungsKonto,
|
||||
Verwaltungskosten,
|
||||
)
|
||||
|
||||
|
||||
class DestinataerViewSet(ReadOnlyModelViewSet):
|
||||
queryset = Destinataer.objects.all()
|
||||
serializer_class = DestinataerSerializer
|
||||
|
||||
|
||||
class LandViewSet(ReadOnlyModelViewSet):
|
||||
queryset = Land.objects.all()
|
||||
serializer_class = LandSerializer
|
||||
|
||||
|
||||
class PaechterViewSet(ReadOnlyModelViewSet):
|
||||
queryset = Paechter.objects.all()
|
||||
serializer_class = PaechterSerializer
|
||||
|
||||
|
||||
class FoerderungViewSet(ReadOnlyModelViewSet):
|
||||
queryset = Foerderung.objects.all()
|
||||
serializer_class = FoerderungSerializer
|
||||
|
||||
|
||||
class StiftungsKontoViewSet(ReadOnlyModelViewSet):
|
||||
queryset = StiftungsKonto.objects.all()
|
||||
serializer_class = StiftungsKontoSerializer
|
||||
|
||||
|
||||
class LandVerpachtungViewSet(ReadOnlyModelViewSet):
|
||||
queryset = LandVerpachtung.objects.all()
|
||||
serializer_class = LandVerpachtungSerializer
|
||||
|
||||
|
||||
class VerwaltungskostenViewSet(ReadOnlyModelViewSet):
|
||||
queryset = Verwaltungskosten.objects.all()
|
||||
serializer_class = VerwaltungskostenSerializer
|
||||
|
||||
|
||||
class StiftungsKalenderEintragViewSet(ReadOnlyModelViewSet):
|
||||
queryset = StiftungsKalenderEintrag.objects.all()
|
||||
serializer_class = StiftungsKalenderEintragSerializer
|
||||
|
||||
|
||||
class BankTransactionViewSet(ReadOnlyModelViewSet):
|
||||
queryset = BankTransaction.objects.all()
|
||||
serializer_class = BankTransactionSerializer
|
||||
28
app/stiftung/management/commands/create_agent_token.py
Normal file
28
app/stiftung/management/commands/create_agent_token.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Erstellt oder gibt ein API-Token für einen Django-User aus (für Agent-Zugriff)"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("username", type=str, help="Django-Username")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
User = get_user_model()
|
||||
username = options["username"]
|
||||
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise CommandError(f'User "{username}" nicht gefunden.')
|
||||
|
||||
token, created = Token.objects.get_or_create(user=user)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f"Neues Token erstellt für {username}:"))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f"Bestehendes Token für {username}:"))
|
||||
|
||||
self.stdout.write(token.key)
|
||||
Reference in New Issue
Block a user