feat(records): implement native eAkte vertical

This commit is contained in:
2026-08-06 01:43:23 +02:00
parent 59860f7ac0
commit f316523a1d
28 changed files with 5700 additions and 80 deletions
+186
View File
@@ -0,0 +1,186 @@
from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, model_validator
class StrictModel(BaseModel):
model_config = ConfigDict(extra="forbid")
class FilePlanNodeWriteRequest(StrictModel):
node_id: str = Field(min_length=1, max_length=255)
code: str = Field(min_length=1, max_length=120)
label: str = Field(min_length=1, max_length=500)
parent_node_id: str | None = Field(default=None, max_length=255)
description: str | None = Field(default=None, max_length=10_000)
active: bool = True
valid_from: datetime | None = None
valid_to: datetime | None = None
recorded_at: datetime
expected_revision: int | None = Field(default=None, ge=1)
idempotency_key: str = Field(min_length=1, max_length=255)
institutional_context: dict[str, Any] = Field(default_factory=dict)
@model_validator(mode="after")
def validate_interval(self):
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
raise ValueError("valid_to must be after valid_from")
return self
class RecordClassWriteRequest(StrictModel):
class_id: str = Field(min_length=1, max_length=255)
file_plan_node_id: str = Field(min_length=1, max_length=255)
key: str = Field(min_length=1, max_length=120)
label: str = Field(min_length=1, max_length=500)
description: str | None = Field(default=None, max_length=10_000)
metadata_requirements: list[str] = Field(default_factory=list, max_length=100)
allowed_source_types: list[str] = Field(default_factory=list, max_length=100)
retention_period_days: int | None = Field(default=None, ge=0, le=365_000)
closure_trigger: str | None = Field(default=None, max_length=255)
access_mode: Literal["tenant", "restricted"] = "tenant"
active: bool = True
valid_from: datetime | None = None
valid_to: datetime | None = None
recorded_at: datetime
expected_revision: int | None = Field(default=None, ge=1)
idempotency_key: str = Field(min_length=1, max_length=255)
institutional_context: dict[str, Any] = Field(default_factory=dict)
@model_validator(mode="after")
def validate_interval(self):
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
raise ValueError("valid_to must be after valid_from")
return self
class RecordCreateRequest(StrictModel):
record_id: str | None = Field(default=None, max_length=255)
record_number: str = Field(min_length=1, max_length=255)
class_id: str = Field(min_length=1, max_length=255)
file_plan_node_id: str = Field(min_length=1, max_length=255)
title: str = Field(min_length=1, max_length=500)
description: str | None = Field(default=None, max_length=20_000)
state: Literal["planned", "open"] = "open"
source_authority_mode: Literal[
"native_authoritative",
"external_authoritative",
"external_mirror",
"governed_sync",
"governance_overlay",
"linked_reference",
] = "native_authoritative"
access_mode: Literal["tenant", "restricted"] = "tenant"
purpose: str = Field(min_length=1, max_length=255)
classification: str | None = Field(default=None, max_length=120)
responsible_unit_id: str | None = Field(default=None, max_length=255)
responsible_function_id: str | None = Field(default=None, max_length=255)
external_reference: dict[str, Any] = Field(default_factory=dict)
institutional_context: dict[str, Any] = Field(default_factory=dict)
valid_from: datetime | None = None
valid_to: datetime | None = None
recorded_at: datetime
change_reason: str = Field(min_length=1, max_length=2_000)
idempotency_key: str = Field(min_length=1, max_length=255)
@model_validator(mode="after")
def validate_interval(self):
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
raise ValueError("valid_to must be after valid_from")
return self
class RecordUpdateRequest(StrictModel):
expected_revision: int = Field(ge=1)
title: str | None = Field(default=None, min_length=1, max_length=500)
description: str | None = Field(default=None, max_length=20_000)
class_id: str | None = Field(default=None, min_length=1, max_length=255)
file_plan_node_id: str | None = Field(default=None, min_length=1, max_length=255)
state: Literal["planned", "open"] | None = None
access_mode: Literal["tenant", "restricted"] | None = None
purpose: str = Field(min_length=1, max_length=255)
classification: str | None = Field(default=None, max_length=120)
responsible_unit_id: str | None = Field(default=None, max_length=255)
responsible_function_id: str | None = Field(default=None, max_length=255)
institutional_context: dict[str, Any] | None = None
valid_from: datetime | None = None
valid_to: datetime | None = None
recorded_at: datetime
change_reason: str = Field(min_length=1, max_length=2_000)
idempotency_key: str = Field(min_length=1, max_length=255)
@model_validator(mode="after")
def validate_interval(self):
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
raise ValueError("valid_to must be after valid_from")
return self
class RecordVolumeCreateRequest(StrictModel):
volume_id: str | None = Field(default=None, max_length=255)
label: str = Field(min_length=1, max_length=500)
valid_from: datetime | None = None
valid_to: datetime | None = None
recorded_at: datetime
purpose: str = Field(min_length=1, max_length=255)
idempotency_key: str = Field(min_length=1, max_length=255)
class RecordSourceLocatorRequest(StrictModel):
source_module: str = Field(min_length=1, max_length=100)
resource_type: str = Field(min_length=1, max_length=120)
resource_id: str = Field(min_length=1, max_length=500)
source_revision: str = Field(min_length=1, max_length=255)
metadata: dict[str, Any] = Field(default_factory=dict)
class RecordItemCreateRequest(StrictModel):
source: RecordSourceLocatorRequest
purpose: str = Field(min_length=1, max_length=255)
filing_reason: str = Field(min_length=1, max_length=2_000)
idempotency_key: str = Field(min_length=1, max_length=255)
volume_id: str | None = Field(default=None, max_length=255)
relationship: str = Field(default="contains", min_length=1, max_length=120)
institutional_context: dict[str, Any] = Field(default_factory=dict)
metadata: dict[str, Any] = Field(default_factory=dict)
class RecordListResponse(StrictModel):
records: list[dict[str, Any]]
total: int
offset: int
limit: int
class RecordCatalogResponse(StrictModel):
file_plan: list[dict[str, Any]]
classes: list[dict[str, Any]]
class RecordDetailResponse(StrictModel):
record: dict[str, Any]
volumes: list[dict[str, Any]]
items: list[dict[str, Any]]
chronology: list[dict[str, Any]]
access_explanation: dict[str, Any]
class RecordSourceProviderResponse(StrictModel):
providers: list[dict[str, Any]]
__all__ = [
"FilePlanNodeWriteRequest",
"RecordCatalogResponse",
"RecordClassWriteRequest",
"RecordCreateRequest",
"RecordDetailResponse",
"RecordItemCreateRequest",
"RecordListResponse",
"RecordSourceProviderResponse",
"RecordUpdateRequest",
"RecordVolumeCreateRequest",
]