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.
94 lines
3.4 KiB
Python
94 lines
3.4 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, JSON, String, Text, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class WorkflowConfig(Base):
|
|
__tablename__ = "workflow_configs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
character_name: Mapped[str] = mapped_column(String(100), nullable=False, index=True)
|
|
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
steps: Mapped[list] = mapped_column(
|
|
JSON,
|
|
nullable=False,
|
|
default=list,
|
|
comment="JSON array of workflow steps, each with id, name, strategy_type, config, transition",
|
|
)
|
|
loop: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
max_loops: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
server_default=func.now(),
|
|
nullable=False,
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
server_default=func.now(),
|
|
onupdate=func.now(),
|
|
nullable=False,
|
|
)
|
|
|
|
runs: Mapped[list["WorkflowRun"]] = relationship(
|
|
back_populates="workflow",
|
|
cascade="all, delete-orphan",
|
|
order_by="WorkflowRun.started_at.desc()",
|
|
)
|
|
|
|
def __repr__(self) -> str:
|
|
return (
|
|
f"<WorkflowConfig(id={self.id}, name={self.name!r}, "
|
|
f"character={self.character_name!r}, steps={len(self.steps)})>"
|
|
)
|
|
|
|
|
|
class WorkflowRun(Base):
|
|
__tablename__ = "workflow_runs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
workflow_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("workflow_configs.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
index=True,
|
|
)
|
|
status: Mapped[str] = mapped_column(
|
|
String(20),
|
|
nullable=False,
|
|
default="running",
|
|
comment="Status: running, paused, stopped, completed, error",
|
|
)
|
|
current_step_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
current_step_id: Mapped[str] = mapped_column(String(100), nullable=False, default="")
|
|
loop_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
total_actions_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
step_actions_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
started_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
server_default=func.now(),
|
|
nullable=False,
|
|
)
|
|
stopped_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=True,
|
|
)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
step_history: Mapped[list] = mapped_column(
|
|
JSON,
|
|
nullable=False,
|
|
default=list,
|
|
comment="JSON array of completed step records",
|
|
)
|
|
|
|
workflow: Mapped["WorkflowConfig"] = relationship(back_populates="runs")
|
|
|
|
def __repr__(self) -> str:
|
|
return (
|
|
f"<WorkflowRun(id={self.id}, workflow_id={self.workflow_id}, "
|
|
f"status={self.status!r}, step={self.current_step_index})>"
|
|
)
|