artifacts-dashboard/backend/app/schemas/workflow.py
Paweł Orzech 75313b83c0
Add multi-user workflows/pipelines and error tracking
Add multi-user automation features and per-user error tracking.

- Database migrations: add workflow_configs/workflow_runs (004), app_errors (005), pipeline_configs/pipeline_runs (006), and add user_token_hash to app_errors (007).
- Backend: introduce per-request token handling (X-API-Token) via app.api.deps and update many API routes (auth, automations, bank, characters, dashboard, events, exchange, logs) to use user-scoped Artifacts client and character scoping. Auth endpoints no longer store tokens server-side (validate-only); clear is a no-op on server.
- New Errors API and services: endpoint to list, filter, resolve, and report errors scoped to the requesting user; add error models, schemas, middleware/error handler and error_service for recording/hashing tokens.
- Pipelines & Workflows: add API routers, models, schemas and engine modules (pipeline/worker/coordinator, workflow runner/conditions) and action_executor updates to support workflow/pipeline execution.
- Logs: logs endpoint now prefers fetching recent action logs from the game API (with fallback to local DB), supports paging and filtering, and scopes results to the user.
- Frontend: add pipeline/workflow builders, lists, progress components and hooks (use-errors, use-pipelines, use-workflows), sentry client config, and updates to API client/constants/types.
- Misc: add middleware error handler, various engine strategy tweaks, tests adjusted.

Overall this change enables per-user API tokens, scopes DB queries to each user, introduces pipelines/workflows runtime support, and centralizes application error tracking.
2026-03-01 23:02:34 +01:00

146 lines
4.3 KiB
Python

from datetime import datetime
from pydantic import BaseModel, Field
# ---------------------------------------------------------------------------
# Transition conditions
# ---------------------------------------------------------------------------
class TransitionConditionSchema(BaseModel):
"""Defines when a workflow step should transition to the next step."""
type: str = Field(
...,
description=(
"Condition type: strategy_complete, loops_completed, inventory_full, "
"inventory_item_count, bank_item_count, skill_level, gold_amount, "
"actions_count, timer"
),
)
operator: str = Field(
default=">=",
description="Comparison operator: >=, <=, ==, >, <",
)
value: int = Field(
default=0,
description="Target value for the condition",
)
item_code: str = Field(
default="",
description="Item code (for inventory_item_count, bank_item_count)",
)
skill: str = Field(
default="",
description="Skill name (for skill_level condition)",
)
seconds: int = Field(
default=0,
ge=0,
description="Duration in seconds (for timer condition)",
)
# ---------------------------------------------------------------------------
# Workflow steps
# ---------------------------------------------------------------------------
class WorkflowStepSchema(BaseModel):
"""A single step within a workflow pipeline."""
id: str = Field(..., description="Unique step identifier (e.g. 'step_1')")
name: str = Field(..., min_length=1, max_length=100, description="Human-readable step name")
strategy_type: str = Field(
...,
description="Strategy type: combat, gathering, crafting, trading, task, leveling",
)
config: dict = Field(default_factory=dict, description="Strategy-specific configuration")
transition: TransitionConditionSchema | None = Field(
default=None,
description="Condition to advance to the next step (None = run until strategy completes)",
)
# ---------------------------------------------------------------------------
# Request schemas
# ---------------------------------------------------------------------------
class WorkflowConfigCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
character_name: str = Field(..., min_length=1, max_length=100)
description: str = Field(default="")
steps: list[WorkflowStepSchema] = Field(..., min_length=1)
loop: bool = Field(default=False)
max_loops: int = Field(default=0, ge=0)
class WorkflowConfigUpdate(BaseModel):
name: str | None = Field(default=None, min_length=1, max_length=100)
description: str | None = None
steps: list[WorkflowStepSchema] | None = Field(default=None, min_length=1)
loop: bool | None = None
max_loops: int | None = Field(default=None, ge=0)
enabled: bool | None = None
# ---------------------------------------------------------------------------
# Response schemas
# ---------------------------------------------------------------------------
class WorkflowConfigResponse(BaseModel):
id: int
name: str
character_name: str
description: str
steps: list[dict]
loop: bool
max_loops: int
enabled: bool
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
class WorkflowRunResponse(BaseModel):
id: int
workflow_id: int
status: str
current_step_index: int
current_step_id: str
loop_count: int
total_actions_count: int
step_actions_count: int
started_at: datetime
stopped_at: datetime | None = None
error_message: str | None = None
step_history: list[dict] = Field(default_factory=list)
model_config = {"from_attributes": True}
class WorkflowStatusResponse(BaseModel):
workflow_id: int
character_name: str
status: str
run_id: int | None = None
current_step_index: int = 0
current_step_id: str = ""
total_steps: int = 0
loop_count: int = 0
total_actions_count: int = 0
step_actions_count: int = 0
strategy_state: str = ""
model_config = {"from_attributes": True}
class WorkflowConfigDetailResponse(BaseModel):
"""Workflow config with its run history."""
config: WorkflowConfigResponse
runs: list[WorkflowRunResponse] = Field(default_factory=list)