Initial commit: site monorepo with API, web, and infra.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
влад
2026-07-16 10:11:54 +03:00
co-authored by Cursor
commit 016910ffb7
447 changed files with 73972 additions and 0 deletions
+165
View File
@@ -0,0 +1,165 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, Field
ChangeAction = Literal["upsert", "delete"]
ChangeDomain = Literal["global", "report"]
EnterpriseRole = Literal["admin", "zootech", "viewer"]
ConflictResolution = Literal["keep_orchestrator", "keep_hub"]
class ChangeEventIn(BaseModel):
event_id: str
seq: int
domain: ChangeDomain = "global"
table: str = Field(alias="table")
record_id: str
action: ChangeAction
version: int = 1
content_hash: str = ""
payload: dict[str, Any] = Field(default_factory=dict)
emitted_at: datetime
origin_site_id: str | None = None
model_config = {"populate_by_name": True}
class ChangeEventOut(BaseModel):
event_id: str
seq: int
domain: ChangeDomain
table: str
record_id: str
action: ChangeAction
version: int
content_hash: str
payload: dict[str, Any]
emitted_at: datetime
origin_site_id: str | None = None
class PushChangesRequest(BaseModel):
events: list[ChangeEventIn]
class PushChangesResponse(BaseModel):
applied_event_ids: list[str]
held_event_ids: list[str]
conflicts: list[str]
class PullChangesRequest(BaseModel):
cursor: int = 0
limit: int = 100
class PullChangesResponse(BaseModel):
events: list[ChangeEventOut]
next_cursor: int
class AckChangesRequest(BaseModel):
event_ids: list[str]
direction: Literal["inbound", "outbound"] = "inbound"
class AckChangesResponse(BaseModel):
last_acked_seq: int
class SyncCapabilitiesResponse(BaseModel):
protocol_version: str = "1.0"
domains: list[str] = Field(default_factory=lambda: ["global", "report"])
class HeartbeatRequest(BaseModel):
wesp_version: str | None = None
lag_seconds: int | None = None
class HeartbeatResponse(BaseModel):
status: str = "ok"
server_time: datetime
class PairStartRequest(BaseModel):
enterprise_id: str
farm_name: str
class PairStartResponse(BaseModel):
session_id: str
code: str
expires_at: datetime
class PairConfirmRequest(BaseModel):
code: str
hub_site_id: str
hub_name: str | None = None
hub_url: str | None = None
class PairConfirmResponse(BaseModel):
farm_hub_id: str
hub_site_id: str
api_key: str
enterprise_id: str
class ConflictSummary(BaseModel):
id: str
table_name: str
record_id: str
farm_hub_id: str | None
status: str
created_at: datetime
class ConflictDetail(ConflictSummary):
orchestrator_snapshot: dict[str, Any]
hub_snapshot: dict[str, Any]
held_event_ids: list[str]
class ResolveConflictRequest(BaseModel):
resolution: ConflictResolution
class EnterpriseOut(BaseModel):
id: str
name: str
slug: str
status: str
class FarmHubOut(BaseModel):
id: str
enterprise_id: str
name: str
hub_site_id: str
url: str | None
status: str
last_seen: datetime | None
wesp_version: str | None
@dataclass
class HubAuthContext:
farm_hub_id: str
hub_site_id: str
enterprise_id: str
farm_hub: Any
@dataclass
class TenantContext:
enterprise_id: str
enterprise_role: EnterpriseRole | None
user_id: str | None
farm_hub_ids: list[str] | None