Files
timemaster/backend/app/schemas/reseller.py
T
patrickandClaude Opus 4.8 898a81f499
Security Audit / Python Dependency Audit (push) Has been cancelled
Security Audit / Node.js Dependency Audit (push) Has been cancelled
feat: Reseller-Rolle + SUPER_ADMIN-Mandantenübersicht
Mandantenfähigkeit ausgebaut:
- Neue Rolle RESELLER (company_id NULL); companies.reseller_id + is_active
- RLS-Erweiterung (Migration 0034): companies/users zusätzlich auf app.reseller_id
  gefenced → Reseller sieht/verwaltet DB-seitig nur eigene Firmen, keine
  personenbezogenen Zeit-/Abwesenheitsdaten (DSGVO: nur Verwaltung)
- get_current_user setzt app.reseller_id + Bypass aus für RESELLER
- tenant_service: Firma + Erst-Admin (Einladung), Übersicht mit Kennzahlen
- Router /reseller/* (Self-Service) und /admin/* (SUPER_ADMIN: Mandanten + Reseller)
- Login-Sperre bei deaktiviertem Mandanten
- Frontend: TenantsPage (/admin/tenants), eigene ResellerCompaniesPage (/reseller),
  rollenbasierte Login-Weiterleitung, Nav "Mandanten" für SUPER_ADMIN
- 4 neue Tests inkl. Cross-Reseller-RLS-Isolation; 172/172 grün

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:15:51 +02:00

70 lines
2.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Schemas für Reseller-Selbstverwaltung und SUPER_ADMIN-Mandantenübersicht.
Wichtig (DSGVO): Reseller sehen ausschließlich Firmen-Stammdaten und Kennzahlen
(z.B. Nutzeranzahl) KEINE personenbezogenen Zeit-/Abwesenheitsdaten.
"""
import uuid
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field
class TenantOut(BaseModel):
"""Eine Firma als Mandant für Reseller- und SUPER_ADMIN-Übersicht."""
model_config = {"from_attributes": True}
id: uuid.UUID
name: str
slug: str
plan: str
is_active: bool
country: str
reseller_id: uuid.UUID | None = None
reseller_name: str | None = None
user_count: int = 0
active_user_count: int = 0
admin_email: str | None = None
created_at: datetime | None = None
class TenantCreate(BaseModel):
"""Neue Firma anlegen (durch Reseller oder SUPER_ADMIN).
Es wird automatisch ein erster COMPANY_ADMIN per Einladung angelegt.
"""
name: str = Field(min_length=2, max_length=255)
country: str = Field(default="DE", max_length=10)
plan: str = Field(default="trial", max_length=50)
admin_email: EmailStr
admin_first_name: str = Field(min_length=1, max_length=100)
admin_last_name: str = Field(min_length=1, max_length=100)
class TenantUpdate(BaseModel):
name: str | None = Field(None, min_length=2, max_length=255)
plan: str | None = Field(None, max_length=50)
is_active: bool | None = None
class TenantAssignReseller(BaseModel):
"""SUPER_ADMIN: Firma einem Reseller zuordnen (oder lösen mit null)."""
reseller_id: uuid.UUID | None = None
class ResellerOut(BaseModel):
model_config = {"from_attributes": True}
id: uuid.UUID
email: str
first_name: str
last_name: str
is_active: bool
created_at: datetime | None = None
company_count: int = 0
class ResellerCreate(BaseModel):
email: EmailStr
first_name: str = Field(min_length=1, max_length=100)
last_name: str = Field(min_length=1, max_length=100)