legal-ai-assistant/backend/tools/api/schemas.py

421 lines
19 KiB
Python

from typing import Annotated, List, Literal, Optional
from pydantic import BaseModel, Field, field_validator
class SortableMixin(BaseModel):
sortProperty: Annotated[
Optional[str],
Field(default=None, description="Attribute to sort records by")
] = None
sortDirection: Annotated[
Literal["ASC", "DESC"],
Field(default="ASC", description="Sort direction: 'ASC' (default) or 'DESC'")
] = "ASC"
class PaginatedRequest(SortableMixin):
page: Annotated[
Optional[int],
Field(default=None, ge=0, description="Page number, starts at 0 (not 1)")
] = None
size: Annotated[
Optional[int],
Field(default=None, ge=1, description="Number of records per page")
] = None
####################################################################################################################
# .../v1/sud — Courts
####################################################################################################################
class CourtSearch(PaginatedRequest):
"""List of courts with optional filters. GET /v1/sud"""
query: Annotated[
Optional[str],
Field(default=None, description="Search term or phrase")
] = None
typSuduFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Court type facet filter, e.g. ['Okresný súd', 'Krajský súd']")
] = None
krajFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Region facet filter, e.g. ['Bratislavský kraj']")
] = None
okresFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="District facet filter, e.g. ['Okres Bratislava I']")
] = None
zahrnutZaniknuteSudy: Annotated[
Optional[bool],
Field(default=None, description="True = include dissolved courts, False = active only")
] = None
indexDatumOd: Annotated[
Optional[str],
Field(default=None, description="Index date from, format DD.MM.YYYY")
] = None
indexDatumDo: Annotated[
Optional[str],
Field(default=None, description="Index date to, format DD.MM.YYYY")
] = None
class CourtByID(BaseModel):
"""Single court by ID. GET /v1/sud/{id}"""
id: Annotated[str, Field(description="Court identifier, e.g. 'sud_175'")]
@field_validator("id")
@classmethod
def normalize(cls, v: str) -> str:
v = v.strip()
return f"sud_{v}" if v.isdigit() else v
class CourtAutocomplete(BaseModel):
"""Autocomplete for court names. GET /v1/sud/autocomplete
PREFERRED tool when searching court by name — use before CourtSearch.
"""
query: Annotated[Optional[str], Field(default=None, description="Partial court name")] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None
####################################################################################################################
# .../v1/sudca — Judges
####################################################################################################################
class JudgeSearch(PaginatedRequest):
"""List of judges with optional filters. GET /v1/sudca"""
query: Annotated[
Optional[str],
Field(default=None, description="Search term or phrase")
] = None
funkciaFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Function facet filter, e.g. ['Sudca', 'Predseda', 'Podpredseda']")
] = None
typSuduFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Court type facet filter")
] = None
krajFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Region facet filter, e.g. ['Bratislavský kraj']")
] = None
okresFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="District facet filter")
] = None
stavZapisuFacetFilter: Annotated[
Optional[List[str]],
Field(
default=None,
description=(
"Registration status filter. Do not translate values: "
"'label.sudca.aktivny', 'label.sudca.odvolany', "
"'label.sudca.vymazany', "
"'label.sudca.prerusenie vykonu - poberatel', "
"'label.sudca.prerusenie vykonu - ina funkce'"
)
)
] = None
guidSud: Annotated[
Optional[str],
Field(default=None, description="Court identifier, e.g. 'sud_100'")
] = None
indexDatumOd: Annotated[
Optional[str],
Field(default=None, description="Index date from, format DD.MM.YYYY")
] = None
indexDatumDo: Annotated[
Optional[str],
Field(default=None, description="Index date to, format DD.MM.YYYY")
] = None
class JudgeByID(BaseModel):
"""Single judge by ID. GET /v1/sudca/{id}"""
id: Annotated[str, Field(description="Judge identifier, e.g. 'sudca_1'")]
@field_validator("id")
@classmethod
def normalize(cls, v: str) -> str:
v = v.strip()
return f"sudca_{v}" if v.isdigit() else v
class JudgeAutocomplete(BaseModel):
"""Autocomplete for judge names. GET /v1/sudca/autocomplete
PREFERRED tool when searching judge by name — use before JudgeSearch.
"""
query: Annotated[
Optional[str],
Field(default=None, description="Partial judge name")
] = None
guidSud: Annotated[
Optional[str],
Field(default=None, description="Court identifier to narrow results, e.g. 'sud_100'")
] = None
limit: Annotated[
Optional[int],
Field(default=None, ge=1, description="Maximum number of results")
] = None
####################################################################################################################
# .../v1/rozhodnutie — Decisions
####################################################################################################################
class DecisionSearch(PaginatedRequest):
"""List of court decisions with optional filters. GET /v1/rozhodnutie"""
query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None
typSuduFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Court type facet filter")] = None
krajFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Region facet filter")] = None
okresFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="District facet filter")] = None
oblastPravnejUpravyFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Legal area facet filter")
] = None
podOblastPravnejUpravyFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Legal sub-area facet filter")
] = None
formaRozhodnutiaFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Decision form facet filter, e.g. ['Uznesenie', 'Rozsudok', 'Platobný rozkaz']")
] = None
povahaRozhodnutiaFacetFilter: Annotated[
Optional[str],
Field(default=None, description="Decision nature facet filter")
] = None
odkazovanePredpisy: Annotated[
Optional[str],
Field(default=None, description="Referenced legal regulations")
] = None
vydaniaOd: Annotated[Optional[str], Field(default=None, description="Issued date from, format YYYY-MM-DD")] = None
vydaniaDo: Annotated[Optional[str], Field(default=None, description="Issued date to, format YYYY-MM-DD")] = None
ecli: Annotated[
Optional[str],
Field(default=None, description="ECLI identifier, e.g. 'ECLI:SK:OSPO:1965:8114010264.1'")
] = None
spisovaZnacka: Annotated[
Optional[str],
Field(default=None, description="Case reference number, e.g. '7C/221/1991'")
] = None
cisloSpisu: Annotated[Optional[str], Field(default=None, description="Case file number")] = None
guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None
indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None
class DecisionByID(BaseModel):
"""Single court decision by ID. GET /v1/rozhodnutie/{id}"""
id: Annotated[str, Field(description="Decision identifier")]
class DecisionAutocomplete(BaseModel):
"""Autocomplete for court decisions. GET /v1/rozhodnutie/autocomplete"""
query: Annotated[Optional[str], Field(default=None, description="Search term")] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None
####################################################################################################################
# .../v1/zmluvy — Contracts
####################################################################################################################
class ContractSearch(PaginatedRequest):
"""List of court contracts with optional filters. GET /v1/zmluvy"""
query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None
typDokumentuFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Document type facet filter, e.g. ['FAKTURA', 'OBJEDNAVKA', 'ZMLUVA', 'DODATOK']")
] = None
odberatelFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Recipient (court) facet filter, e.g. ['Krajský súd v Bratislave']")
] = None
dodavatelFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Supplier facet filter, e.g. ['Slovak Telekom, a.s.']")
] = None
hodnotaZmluvyFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Contract value range filter: '0-1000', '1000-20000', '20000-100000', '100000-500000', 'Viac ako 500000'")
] = None
datumZverejeneniaOd: Annotated[
Optional[str],
Field(default=None, description="Publication date from, format DD.MM.YYYY")
] = None
datumZverejeneniaDo: Annotated[
Optional[str],
Field(default=None, description="Publication date to, format DD.MM.YYYY")
] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None
indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None
class ContractByID(BaseModel):
"""Single contract by ID. GET /v1/zmluvy/{idZmluvy}"""
idZmluvy: Annotated[str, Field(description="Contract identifier, e.g. '2156252'")]
class ContractAutocomplete(BaseModel):
"""Autocomplete for contracts. GET /v1/zmluvy/autocomplete"""
query: Annotated[Optional[str], Field(default=None, description="Search term")] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None
####################################################################################################################
# .../v1/obcianPojednavania — Civil Proceedings
####################################################################################################################
class CivilProceedingsSearch(PaginatedRequest):
"""List of civil court hearings and publicly announced judgments. GET /v1/obcianPojednavania"""
query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None
typSuduFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Court type facet filter")] = None
krajFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Region facet filter")] = None
okresFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="District facet filter")] = None
usekFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Section facet filter, e.g. ['C', 'O', 'S']")
] = None
formaUkonuFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Action form facet filter, e.g. ['Pojednávanie bez rozhodnutia', 'Pojednávanie a rozhodnutie']")
] = None
pojednavaniaOd: Annotated[
Optional[str],
Field(default=None, description="Hearing date from, format YYYY-MM-DD")
] = None
pojednavaniaDo: Annotated[
Optional[str],
Field(default=None, description="Hearing date to, format YYYY-MM-DD")
] = None
guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
spisovaZnacka: Annotated[
Optional[str],
Field(default=None, description="Case reference number, e.g. '7C/221/1991'")
] = None
verejneVyhlasenie: Annotated[
Optional[bool],
Field(default=None, description="True = publicly announced judgment only")
] = None
indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None
indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None
class CivilProceedingsByID(BaseModel):
"""Single civil hearing by ID. GET /v1/obcianPojednavania/{id}"""
id: Annotated[str, Field(description="Hearing identifier, e.g. '121e4d31-695e-41e1-9191-7c9ad5d8d484'")]
class CivilProceedingsAutocomplete(BaseModel):
"""Autocomplete for civil proceedings. GET /v1/obcianPojednavania/autocomplete"""
query: Annotated[Optional[str], Field(default=None, description="Search term")] = None
guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None
guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None
verejneVyhlasenie: Annotated[
Optional[bool],
Field(default=None, description="True = publicly announced judgment only")
] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None
####################################################################################################################
# .../v1/spravneKonanie — Administrative Proceedings
####################################################################################################################
class AdminProceedingsSearch(PaginatedRequest):
"""List of administrative proceedings. GET /v1/spravneKonanie"""
query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None
druhFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Proceeding type facet filter")
] = None
datumPravoplatnostiOd: Annotated[
Optional[str],
Field(default=None, description="Legal force date from, format YYYY-MM-DD")
] = None
datumPravoplatnostiDo: Annotated[
Optional[str],
Field(default=None, description="Legal force date to, format YYYY-MM-DD")
] = None
class AdminProceedingsByID(BaseModel):
"""Single administrative proceeding by ID. GET /v1/spravneKonanie/{id}"""
id: Annotated[str, Field(description="Proceeding identifier, e.g. 'spravneKonanie_103'")]
@field_validator("id")
@classmethod
def normalize(cls, v: str) -> str:
v = v.strip()
return f"spravneKonanie_{v}" if v.isdigit() else v
class AdminProceedingsAutocomplete(BaseModel):
"""Autocomplete for administrative proceedings. GET /v1/spravneKonanie/autocomplete"""
query: Annotated[Optional[str], Field(default=None, description="Search term")] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None
####################################################################################################################
# .../v1/exekutor — Executor
####################################################################################################################
class ExecutorSearch(PaginatedRequest):
"""List of bailiffs (exekútori). GET /v1/exekutor"""
query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None
sudFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Court facet filter, e.g. 'Krajský súd v Trenčíne'")
] = None
krajFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Region facet filter, e.g. 'Košický kraj'")
] = None
okresFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="District facet filter")
] = None
obecFacetFilter: Annotated[
Optional[List[str]],
Field(default=None, description="Municipality facet filter")
] = None
stavZapisuFacetFilter: Annotated[
Optional[List[str]],
Field(
default=None,
description=(
"Registration status filter. Do not translate values: "
"'label.zapis_stav.aktivny', 'label.zapis_stav.neaktivny'"
)
)
] = None
class ExecutorByID(BaseModel):
"""Single bailiff by ID. GET /v1/exekutor/{id}"""
id: Annotated[str, Field(description="Bailiff identifier, e.g. 'exekutor_154'")]
@field_validator("id")
@classmethod
def normalize(cls, v: str) -> str:
v = v.strip()
return f"exekutor_{v}" if v.isdigit() else v
class ExecutorByECE(BaseModel):
"""Single bailiff by ECE registration number. GET /v1/exekutor/ec/{ece}"""
ece: Annotated[str, Field(description="Bailiff ECE registration number, e.g. '089'")]
@field_validator("ece")
@classmethod
def normalize(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("ece cannot be empty")
return v
class ExecutorAutocomplete(BaseModel):
"""Autocomplete for bailiffs. GET /v1/exekutor/autocomplete"""
query: Annotated[Optional[str], Field(default=None, description="Search term")] = None
limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None