from __future__ import annotations from dataclasses import dataclass, field from datetime import date, datetime from typing import Optional @dataclass(frozen=True) class Task: """Published task loaded from the database.""" id: str name: Optional[str] title: str description: str start_date: Optional[date] end_date: Optional[date] created_date: datetime skills: list[str] = field(default_factory=list) @dataclass(frozen=True) class Capacity: """A person's available capacity entry from the database.""" id: int owner_name: str role_name: Optional[str] role_level: Optional[str] begin_date: Optional[date] end_date: Optional[date] competences: list[str] = field(default_factory=list) @dataclass(frozen=True) class Requirements: """Structured matching requirements.""" role_name: Optional[str] competences: list[str] date_start: Optional[date] = None date_end: Optional[date] = None description: Optional[str] = None @dataclass(frozen=True) class RankedRole: """A role candidate extracted from a description. Attributes: rank: 1-based rank. role: Role name. rationale: Short explanation for why this role matches. """ rank: int role: str rationale: str @dataclass(frozen=True) class ScoredCapacity: """A `Capacity` plus matching scores and diagnostic lists.""" capacity: Capacity competence_score: float role_score: float overall_score: float category: str matched_competences: list[str] = field(default_factory=list) missing_competences: list[str] = field(default_factory=list) @dataclass(frozen=True) class TeamCompetence: """Eine Team-Kompetenz mit aufgelöstem Namen und Top-Markierung.""" name: str top_competency: bool @dataclass(frozen=True) class TeamReference: """Eine Team-Referenz mit aufgelöstem Partner-Namen und Projekttext. `partner_name` ist leer, wenn `partner_id` `NULL` ist oder der LEFT JOIN auf `teamlandkarte_v_partners_latest` keinen Treffer liefert. `projects` ist bereits getrimmt und nie leer (Whitespace-only-Werte werden im DBClient ausgefiltert). """ partner_name: str projects: str @dataclass(frozen=True) class Team: """Aggregiertes Team-Stammdatum aus dem Data Lake.""" team_id: str ouid: str team_name: str focus_name: str about_us: str offerings: str interests: str competences: list[TeamCompetence] = field(default_factory=list) references: list[TeamReference] = field(default_factory=list) @dataclass(frozen=True) class ScoredTeam: """A `Team` plus matching scores and diagnostic lists (score mode only).""" team: Team competence_score: float role_score: float overall_score: float category: str matched_competences: list[str] = field(default_factory=list) missing_competences: list[str] = field(default_factory=list)