interfaces

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDagDefinitionJSON = stderrs.New("dag_definition is not valid JSON format")

Functions

This section is empty.

Types

type AISummaryRepository added in v0.1.2

type AISummaryRepository interface {
	CreateAISummary(ctx context.Context, item *types.AISummary) error
	GetAISummaryByID(ctx context.Context, id int64) (*types.AISummary, error)
	// ListAISummariesByOwner 按所属对象类型与 ID 查询摘要列表。
	ListAISummariesByOwner(ctx context.Context, ownerType types.SummaryOwnerType, ownerID int64) ([]*types.AISummary, error)
	// PageAISummariesByProjectID 按项目 ID 分页查询摘要列表(不返回 content)。
	PageAISummariesByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.AISummary, int64, error)
	UpdateAISummary(ctx context.Context, item *types.AISummary) error
	DeleteAISummary(ctx context.Context, id int64) error
}

AISummaryRepository 定义 AI 摘要的持久化操作。

type AISummaryService added in v0.1.2

type AISummaryService interface {
	// CreateAISummary 创建摘要记录并投递异步生成事件。
	// profileID 为本次生成使用的 Agent Profile ID(用于按 ID 解析),profile 为其展示名
	// (仅用于展示,可为空);profileID 为 0 表示使用内置 summary Profile。
	// 摘要所属项目 ID 由生成阶段从所属对象(Analysis / AnalysisNode)解析并回填。
	CreateAISummary(ctx context.Context, ownerType types.SummaryOwnerType, ownerID int64, profileID int64, profile string) (*types.AISummary, error)
	// RegenerateAISummary 按摘要 ID 重新投递异步生成事件。
	RegenerateAISummary(ctx context.Context, id int64) (*types.AISummary, error)
	// GetAISummaryByID 按摘要 ID 查询详情,并填充 Prefix
	// (所属对象输出目录对应的 URL 前缀,供前端渲染 content 中的相对链接)。
	GetAISummaryByID(ctx context.Context, id int64) (*types.AISummary, error)
	// ListAISummariesByOwner 按所属对象类型与 ID 查询摘要列表,
	// 正文(content)按文件读取后填充,并填充每个摘要的 Prefix(所属对象输出目录对应的 URL 前缀)。
	ListAISummariesByOwner(ctx context.Context, ownerType types.SummaryOwnerType, ownerID int64) ([]*types.AISummary, error)
	// PageAISummariesByProjectID 按项目 ID 分页查询摘要列表,不返回 content,
	// 也不解析 Prefix(前者由详情接口按 ID 返回,后者仅在渲染正文时需要)。
	PageAISummariesByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.AISummary, int64, error)
	// UpdateAISummary 按摘要 ID 更新标题、内容与 Agent Profile(nil 表示不修改对应字段)。
	// content 写入文件(见 utils.GetAISummaryFile),不落库。
	UpdateAISummary(ctx context.Context, id int64, title, content *string, profileID *int64, profile *string) (*types.AISummary, error)
	// DeleteAISummary 按摘要 ID 删除摘要记录,并删除对应的正文文件(见 utils.GetAISummaryFile)。
	DeleteAISummary(ctx context.Context, id int64) error
	// GetAISummaryInput 按摘要 ID 解析生成该摘要时交给 LLM 的输入信息。
	GetAISummaryInput(ctx context.Context, id int64) (*types.AISummaryInput, error)
}

AISummaryService 定义 AI 摘要的业务操作。

type AnalysisRepository

type AnalysisRepository interface {
	GetAnalysisByID(ctx context.Context, analysisID int64) (*types.Analysis, error)
	GetAnalysisByAnalysisID(ctx context.Context, analysisID string) (*types.Analysis, error)
	ListAnalysisByJobStatus(ctx context.Context, jobStatus string) ([]*types.Analysis, error)
	ListAnalysisByProjectID(ctx context.Context, projectID int64, query *types.AnalysisQuey) ([]*types.Analysis, error)
	PageAnalysisByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64, query *types.AnalysisQuey) ([]*types.Analysis, int64, error)
	GetAnalysisNodeByID(ctx context.Context, id int64) (*types.AnalysisNode, error)
	GetAnalysisNodeByAnalysisNodeID(ctx context.Context, analysisNodeID string) (*types.AnalysisNode, error)
	GetAnalysisNodeByNodeID(ctx context.Context, analysisID int64, nodeID string) (*types.AnalysisNode, error)
	WithTransaction(ctx context.Context, fn func(AnalysisRepository) error) error
	CreateAnalysis(ctx context.Context, item *types.Analysis) error
	TryMarkAnalysisRunning(ctx context.Context, analysisID int64, now time.Time, staleBefore time.Time) (bool, error)
	UpdateAnalysisByAnalysisID(ctx context.Context, analysisID string, values map[string]any) error
	UpdateAnalysisByID(ctx context.Context, analysisID int64, values map[string]any) error

	ListAnalysisNodesByAnalysisID(ctx context.Context, analysisID int64) ([]*types.AnalysisNode, error)
	PageAnalysisNodesByProjectID(ctx context.Context, pagination *types.Pagination, projectID, scriptID, analysisID int64) ([]*types.AnalysisNode, int64, error)
	ListAnalysisNodesByProjectIDAndScriptID(ctx context.Context, projectID, scriptID int64) ([]*types.AnalysisNode, error)
	ListAnalysisNodesByProjectIDAndStatus(ctx context.Context, projectID int64, status string) ([]*types.AnalysisNode, error)
	ListAnalysisEdgesByAnalysisID(ctx context.Context, analysisID int64) ([]*types.AnalysisEdge, error)
	UpdateAnalysisNodeByID(ctx context.Context, id int64, values map[string]any) error
	UpdateAnalysisNodeByAnalysisNodeID(ctx context.Context, analysisNodeID string, values map[string]any) error
	ClaimNextReadyNode(ctx context.Context, analysisID int64, fromStatus string, toStatus string) (*types.AnalysisNode, error)
	DeleteAnalysisNodesByAnalysisID(ctx context.Context, analysisID int64) error
	DeleteAnalysisNodeByID(ctx context.Context, id int64) error
	CreateAnalysisNodes(ctx context.Context, items []*types.AnalysisNode) error
	DeleteAnalysisEdgesByAnalysisID(ctx context.Context, analysisID int64) error
	CreateAnalysisEdges(ctx context.Context, items []*types.AnalysisEdge) error
	DeleteAnalysisByID(ctx context.Context, id int64) error
	ListAnalysisByWorkflowID(ctx context.Context, workflowID int64) ([]*types.Analysis, error)
}

type AnalysisService

type AnalysisService interface {
	UpdateAnalysisByID(ctx context.Context, analysisID int64, values map[string]any) error
	UpdateAnalysisNodeByID(ctx context.Context, analysisNodeID int64, values map[string]any) error
	GetAnalysisByID(ctx context.Context, analysisID int64) (*types.Analysis, error)
	GetAnalysisByAnalysisID(ctx context.Context, analysisID string) (*types.Analysis, error)
	ListAnalysisByProjectID(ctx context.Context, projectID int64, query *types.AnalysisQuey) ([]*types.Analysis, error)
	PageAnalysisByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64, query *types.AnalysisQuey) ([]*types.Analysis, int64, error)
	GetAnalysisNodeByID(ctx context.Context, id int64) (*types.AnalysisNode, error)
	GetAnalysisNodeByAnalysisNodeID(ctx context.Context, analysisNodeID string) (*types.AnalysisNode, error)
	ListAnalysisNodesByAnalysisID(ctx context.Context, analysisID int64) ([]*types.AnalysisNode, error)
	ListAnalysisNodesByProjectIDAndScriptID(ctx context.Context, projectID, scriptID int64) ([]*types.AnalysisNode, error)
	SaveAnalysisController(ctx context.Context, input *types.AnalysisControllerSaveInput) (*types.Analysis, error)
	DeleteAnalysisNode(ctx context.Context, id int64) error
	DeleteAnalysis(ctx context.Context, id int64) error
	ListAnalysisByWorkflowID(ctx context.Context, workflowID int64) ([]*types.Analysis, error)
}

type AuthTokenRepository

type AuthTokenRepository interface {
	// CreateToken creates an auth token
	CreateToken(ctx context.Context, token *types.AuthToken) error
	// GetTokenByValue gets a token by its value
	GetTokenByValue(ctx context.Context, tokenValue string) (*types.AuthToken, error)
	// GetTokensByUserID gets all tokens for a user
	GetTokensByUserID(ctx context.Context, userID int64) ([]*types.AuthToken, error)
	// UpdateToken updates a token
	UpdateToken(ctx context.Context, token *types.AuthToken) error
	// DeleteToken deletes a token
	DeleteToken(ctx context.Context, id int64) error
	// DeleteExpiredTokens deletes all expired tokens
	DeleteExpiredTokens(ctx context.Context) error
	// RevokeTokensByUserID revokes all tokens for a user
	RevokeTokensByUserID(ctx context.Context, userID int64) error
}

AuthTokenRepository defines the auth token repository interface

type ContainerRepository

type ContainerRepository interface {
	WithTransaction(ctx context.Context, fn func(ContainerRepository) error) error

	// ===== 容器模板:共享运行配置(go_container_template_spec)=====
	CreateContainerTemplateSpec(ctx context.Context, item *types.ContainerTemplateSpec) error
	GetContainerTemplateSpecByID(ctx context.Context, id int64) (*types.ContainerTemplateSpec, error)
	UpdateContainerTemplateSpec(ctx context.Context, item *types.ContainerTemplateSpec) error
	DeleteContainerTemplateSpec(ctx context.Context, id int64) error
	ListContainerTemplateSpec(ctx context.Context) ([]*types.ContainerTemplateSpec, error)
	PageContainerTemplateSpec(ctx context.Context, pagination *types.Pagination) ([]*types.ContainerTemplateSpec, int64, error)

	// ===== 容器模板:运行配置 × 镜像 绑定行(go_container_template_definition)=====
	// 绑定行主键即对外 ContainerTemplate.ID,一行唯一确定一个可运行的容器配置
	// (镜像名与拉取策略直接存在绑定行上)。
	CreateContainerTemplateDefinition(ctx context.Context, item *types.ContainerTemplateDefinition) error
	GetContainerTemplateDefinitionByID(ctx context.Context, id int64) (*types.ContainerTemplateDefinition, error)
	UpdateContainerTemplateDefinition(ctx context.Context, item *types.ContainerTemplateDefinition) error
	DeleteContainerTemplateDefinition(ctx context.Context, id int64) error
	// ClearContainerTemplateDefinitionDefault 把全部绑定行的 is_default 置为 false(写入新默认前的互斥清理)。
	ClearContainerTemplateDefinitionDefault(ctx context.Context) error
	// GetDefaultContainerTemplateDefinition 返回当前标记为默认的绑定行;没有默认行时返回 gorm.ErrRecordNotFound。
	GetDefaultContainerTemplateDefinition(ctx context.Context) (*types.ContainerTemplateDefinition, error)
	ListContainerTemplateDefinitionBySpecID(ctx context.Context, specID int64) ([]*types.ContainerTemplateDefinition, error)

	// ===== 容器模板:对外读模型(由 definition + spec 组装,非持久化)=====
	GetContainerTemplateByID(ctx context.Context, id int64) (*types.ContainerTemplate, error)
	ListContainerTemplate(ctx context.Context) ([]*types.ContainerTemplate, error)
	PageContainerTemplate(ctx context.Context, pagination *types.Pagination) ([]*types.ContainerTemplate, int64, error)
	ListContainerTemplateBySpecID(ctx context.Context, specID int64) ([]*types.ContainerTemplate, error)

	CreateAppSession(ctx context.Context, item *types.AppSession) error
	GetAppSessionByID(ctx context.Context, id int64) (*types.AppSession, error)
	UpdateAppSession(ctx context.Context, item *types.AppSession) error
	DeleteAppSession(ctx context.Context, id int64) error
	ListAppSession(ctx context.Context) ([]*types.AppSession, error)
	PageAppSessionByUserID(ctx context.Context, userID int64, pagination *types.Pagination, query *types.AppSessionPageQuery) ([]*types.AppSession, int64, error)

	// CreateContainerInstance 落库容器实例;(owner_type, owner_id) 已存在时原地更新
	// (主键保持不变),否则新建,保证一个 owner 只有一条实例记录。
	CreateContainerInstance(ctx context.Context, item *types.ContainerInstance) error
	GetContainerInstanceByID(ctx context.Context, id int64) (*types.ContainerInstance, error)
	GetContainerInstanceByRuntimeID(ctx context.Context, runtimeID string) (*types.ContainerInstance, error)
	GetContainerInstanceByOwner(ctx context.Context, ownerType types.ContainerOwnerType, ownerID int64) (*types.ContainerInstance, error)
	UpdateContainerInstance(ctx context.Context, item *types.ContainerInstance) error
	DeleteContainerInstance(ctx context.Context, id int64) error
	ListContainerInstance(ctx context.Context) ([]*types.ContainerInstance, error)
	CountContainerInstanceByStatuses(ctx context.Context, statuses []types.ContainerStatus) (int64, error)
	ListContainerInstanceByOwnerTypeAndOwnerIDs(ctx context.Context, ownerType types.ContainerOwnerType, ownerIDs []int64) ([]*types.ContainerInstance, error)
	PageContainerInstance(ctx context.Context, pagination *types.Pagination) ([]*types.ContainerInstance, int64, error)

	CreateOutboxEvent(ctx context.Context, item *types.OutboxEvent) error
	ListPendingOutboxEvent(ctx context.Context, limit int) ([]*types.OutboxEvent, error)
	ListPendingOutboxEventsByType(ctx context.Context, eventType string, limit int) ([]*types.OutboxEvent, error)
	CountPendingOutboxEvents(ctx context.Context, eventTypes ...string) (int64, error)
	CountPendingOutboxEventsByType(ctx context.Context, eventType string) (int64, error)
	MarkOutboxEventProcessing(ctx context.Context, id int64) error
	MarkOutboxEventPending(ctx context.Context, id int64) error
	MarkOutboxEventSent(ctx context.Context, id int64) error
	MarkOutboxEventFailed(ctx context.Context, id int64) error
	PageOutboxEvent(ctx context.Context, pagination *types.Pagination) ([]*types.OutboxEvent, int64, error)
}

type ContainerService

type ContainerService interface {
	// TransitionContainerAndEnqueueOutbox(ctx context.Context, instance *types.ContainerInstance, to types.ContainerStatus, eventType string) error
	// GetMaxConcurrency() int
	RecreateAppSessionContainer(ctx context.Context, userID int64, appSessionID int64) error

	CreateContainerTemplate(ctx context.Context, item *types.ContainerTemplate) error
	GetContainerTemplateByID(ctx context.Context, id int64) (*types.ContainerTemplate, error)
	UpdateContainerTemplate(ctx context.Context, item *types.ContainerTemplate) error
	DeleteContainerTemplate(ctx context.Context, id int64) error
	ListContainerTemplate(ctx context.Context) ([]*types.ContainerTemplate, error)
	// ListContainerTemplateBySpecID 列出同一套共享运行配置下绑定不同镜像的所有对外模板。
	ListContainerTemplateBySpecID(ctx context.Context, specID int64) ([]*types.ContainerTemplate, error)
	PageContainerTemplate(ctx context.Context, pagination *types.Pagination) (*types.PageResult, error)
	// ExportContainerTemplate 导出统一平铺格式(container_template_specs / container_template_definitions),
	// 与 script.json / workflow.json 的容器资产结构完全一致。
	ExportContainerTemplate(ctx context.Context, definitionID int64) (*types.ContainerTemplateBundle, error)
	// ImportContainerTemplate 导入统一平铺格式:两张表按主键 upsert,顺序为运行配置 → 绑定行。
	ImportContainerTemplate(ctx context.Context, bundle *types.ContainerTemplateBundle) (*types.ContainerTemplateBundle, error)

	// ===== 默认容器模板(go_container_template_definition.is_default)=====
	// GetDefaultContainerTemplate 返回默认模板;没有默认行时返回 (nil, nil),由调用方给用户提示。
	GetDefaultContainerTemplate(ctx context.Context) (*types.ContainerTemplate, error)
	// SetDefaultContainerTemplate 把某个绑定行设为唯一默认(先清空其它行的默认标记)。
	SetDefaultContainerTemplate(ctx context.Context, definitionID int64) error

	// ===== 容器模板:按主键直接 upsert 两层实体(安装 script.json / workflow.json 用)=====
	// 安装侧拿到的导出内容已经是拆开的 ContainerTemplateSpec / ContainerTemplateDefinition
	// (各自带主键),不能走 CreateContainerTemplate/UpdateContainerTemplate 那套读模型逻辑:
	// 读模型会重新拼装 spec 与绑定行,无法保留导出文件里的 spec_id / 绑定行主键。
	CreateContainerTemplateSpec(ctx context.Context, item *types.ContainerTemplateSpec) error
	GetContainerTemplateSpecByID(ctx context.Context, id int64) (*types.ContainerTemplateSpec, error)
	UpdateContainerTemplateSpec(ctx context.Context, item *types.ContainerTemplateSpec) error
	// DeleteContainerTemplateSpec 删除共享运行配置;仍被绑定行引用时返回冲突错误。
	DeleteContainerTemplateSpec(ctx context.Context, id int64) error
	ListContainerTemplateSpec(ctx context.Context) ([]*types.ContainerTemplateSpec, error)
	PageContainerTemplateSpec(ctx context.Context, pagination *types.Pagination) (*types.PageResult, error)
	CreateContainerTemplateDefinition(ctx context.Context, item *types.ContainerTemplateDefinition) error
	GetContainerTemplateDefinitionByID(ctx context.Context, id int64) (*types.ContainerTemplateDefinition, error)
	UpdateContainerTemplateDefinition(ctx context.Context, item *types.ContainerTemplateDefinition) error

	CreateAppSessionByTemplate(ctx context.Context, userID int64, projectID int64, containerTemplateID int64, name string) (*types.AppSession, error)
	CreateAppSessionByTemplateForAnalysisNode(ctx context.Context, userID int64, projectID int64, containerTemplateID int64, name string, analysisNodeID int64, workspacePath string) (*types.AppSession, error)
	// CreateTerminalAppSession 按容器模板创建终端会话(AppSession + 常驻容器)。
	// 终端会话与「应用会话」是同一个实体,AgentSessionID / Persistent 区分来源与生命周期;
	// 容器由 terminalKeepAliveCommand 常驻,交互式 shell 由运行时 exec 打开。
	CreateTerminalAppSession(ctx context.Context, in types.TerminalAppSessionInput) (*types.AppSession, error)
	StartAppSession(ctx context.Context, userID int64, appSessionID int64) error
	StopAppSession(ctx context.Context, userID int64, appSessionID int64) error
	DeleteAppSession(ctx context.Context, userID int64, appSessionID int64) error
	GetAppSessionByID(ctx context.Context, userID int64, appSessionID int64) (*types.AppSession, error)
	ListAppSessionByUserID(ctx context.Context, userID int64) ([]*types.AppSession, error)
	PageAppSessionByUserID(ctx context.Context, userID int64, pagination *types.Pagination, query *types.AppSessionPageQuery) (*types.PageResult, error)
	ListContainerInstanceByOwnerTypeAndOwnerIDs(ctx context.Context, ownerType types.ContainerOwnerType, ownerIDs []int64) ([]*types.ContainerInstance, error)
	DeleteContainerInstancesByOwnerTypeAndOwnerIDs(ctx context.Context, ownerType types.ContainerOwnerType, ownerIDs []int64) error

	PageContainerInstance(ctx context.Context, pagination *types.Pagination) (*types.PageResult, error)
	// PageContainerEvent(ctx context.Context, pagination *types.Pagination) (*types.PageResult, error)
	PageOutboxEvent(ctx context.Context, pagination *types.Pagination) (*types.PageResult, error)
}

type DagOrchestrator

type DagOrchestrator interface {
	// Name returns the stable scheduler name persisted in analysis.scheduler_mode.
	// It is also the registry key, so it must never change once released.
	Name() string

	// StartAsync submits (or resumes) the run for analysisID in the background.
	// parseAnalysisResult and dagDefinition carry the already-parsed request
	// payload so schedulers that materialize nodes at runtime do not have to
	// re-parse the request; schedulers that rely on the persisted graph may
	// ignore them.
	StartAsync(ctx context.Context, analysisID int64, parseAnalysisResult map[string]any, dagDefinition map[string]any) error

	// StopAsync asks this scheduler to stop the analysis. Implementations persist
	// the "stopping" signal first and then either cancel the in-process run or
	// converge the analysis to a terminal state themselves.
	StopAsync(ctx context.Context, analysisID int64) error

	// PersistsGraphOnSave reports whether the scheduler needs the compiled
	// analysis graph persisted at save time. Schedulers that materialize nodes at
	// runtime return false and ignore the persisted graph.
	PersistsGraphOnSave() bool

	// RecoverRunningAnalyses adopts a single analysis owned by this scheduler.
	//
	// The container recovery loop fetches every running/stopping analysis and
	// routes each one here according to scheduler_mode, so this method never scans
	// the tables itself:
	//   - running:  restart the run so it can continue after a crash.
	//   - stopping: converge the stop request, cancelling a live run or finalizing.
	//
	// It reports whether a live run is now tracked in this process.
	RecoverRunningAnalyses(ctx context.Context, item *types.Analysis) (bool, error)

	// GetRunningInfo returns the in-memory running entry for analysisID, or nil
	// when the run is not tracked by this process.
	GetRunningInfo(ctx context.Context, analysisID int64) (*DagRunningInfo, error)
}

DagOrchestrator is the single scheduling contract shared by every DAG orchestrator implementation (static graph, dynamic materialization, dataflow).

The concrete implementation that advances an analysis is selected at runtime from analysis.scheduler_mode through dag/scheduler.Registry, so handlers, the stop API and crash recovery all share one entry point instead of hardcoding a scheduler per endpoint.

type DagRunningInfo added in v0.1.4

type DagRunningInfo struct {
	AnalysisID     int64     `json:"analysis_id,string"`
	TaskName       string    `json:"task_name"`
	Status         string    `json:"status"`
	StartedAt      time.Time `json:"started_at"`
	UpdatedAt      time.Time `json:"updated_at"`
	MaxConcurrency int       `json:"max_concurrency"`
	QueueSize      int       `json:"queue_size"`
	PollIntervalMs int64     `json:"poll_interval_ms"`
	TimeoutSeconds int64     `json:"timeout_seconds"`
	StopRequested  bool      `json:"stop_requested"`
}

DagRunningInfo describes an in-flight DAG run tracked by an orchestrator. It mirrors Python brave's running_dag_registry entry that is exposed as the running_info field of /analysis-runtime/snapshot.

type DataRepository

type DataRepository interface {
	CreateDataset(ctx context.Context, dataset *types.Dataset) error
	GetDatasetByID(ctx context.Context, id int64) (*types.Dataset, error)
	UpdateDataset(ctx context.Context, dataset *types.Dataset) error
	DeleteDataset(ctx context.Context, id int64) error
	ListDataset(ctx context.Context) ([]*types.Dataset, error)
	ListDatasetByProjectID(ctx context.Context, projectID int64) ([]*types.Dataset, error)
	PageDatasetByProjectID(ctx context.Context, pagination *types.Pagination, query *types.QueryDataset, projectID int64) ([]*types.Dataset, int64, error)

	CreateProjectDataset(ctx context.Context, projectDataset *types.ProjectDataset) error
	GetProjectDatasetByID(ctx context.Context, id int64) (*types.ProjectDataset, error)
	// GetProjectDatasetByDatasetID returns one project binding of the dataset
	// (newest first), used to derive the dataset workspace path when only the
	// dataset id is known.
	GetProjectDatasetByDatasetID(ctx context.Context, datasetID int64) (*types.ProjectDataset, error)
	UpdateProjectDataset(ctx context.Context, projectDataset *types.ProjectDataset) error
	DeleteProjectDataset(ctx context.Context, id int64) error
	ListProjectDataset(ctx context.Context) ([]*types.ProjectDataset, error)

	CreateFile(ctx context.Context, file *types.File) error
	GetFileByID(ctx context.Context, id int64) (*types.File, error)
	// GetFileByPathAndAssayID resolves a path to its file row for one assay
	// (assayID 0 = files that are not owned by any assay). Paths are unique per
	// assay, not globally.
	GetFileByPathAndAssayID(ctx context.Context, path string, assayID int64) (*types.File, error)
	UpdateFile(ctx context.Context, file *types.File) error
	DeleteFile(ctx context.Context, id int64) error
	ListFile(ctx context.Context) ([]*types.File, error)
	PageFileByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64, roles []string) ([]*types.FileWithDatasetInfo, int64, error)
	ListFileByProjectID(ctx context.Context, projectID int64, roles []string) ([]*types.FileWithDatasetInfo, error)
	ListFileByProjectIDViaAnalysisNode(ctx context.Context, projectID int64) ([]*types.FileWithDatasetInfo, error)
	PageFileByProjectIDViaAnalysisNode(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.FileWithDatasetInfo, int64, error)
	// ListFileByDatasetID returns the files bound to one dataset through
	// go_dataset_file, ordered by binding id (newest first).
	ListFileByDatasetID(ctx context.Context, datasetID int64) ([]*types.FileWithDatasetInfo, error)
	ListFileByAssayID(ctx context.Context, assayID int64) ([]*types.File, error)
	ListFileByAssayIDAndRole(ctx context.Context, assayID int64, roles []string) ([]*types.File, error)
	ListFileByAnalysisNodeID(ctx context.Context, analysisNodeID int64) ([]*types.File, error)

	CreateDatasetFile(ctx context.Context, datasetFile *types.DatasetFile) error
	ExistsDatasetFile(ctx context.Context, datasetID, fileID int64) (bool, error)
	// ExistsFileByPathInDataset reports whether a file with the given physical
	// path is already bound to the dataset (go_file.path +
	// go_dataset_file.dataset_id).
	ExistsFileByPathInDataset(ctx context.Context, datasetID int64, path string) (bool, error)
	WithTransaction(ctx context.Context, fn func(DataRepository) error) error
	GetDatasetFileByID(ctx context.Context, id int64) (*types.DatasetFile, error)
	DeleteDatasetFile(ctx context.Context, id int64) error
	ListDatasetFile(ctx context.Context) ([]*types.DatasetFile, error)

	CreateAssay(ctx context.Context, assay *types.Assay) error
	GetAssayByID(ctx context.Context, id int64) (*types.Assay, error)
	UpdateAssay(ctx context.Context, assay *types.Assay) error
	DeleteAssay(ctx context.Context, id int64) error
	ListAssay(ctx context.Context) ([]*types.Assay, error)
	PageAssayByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.AssayWithDatasetInfo, int64, error)
	ListAssayByProjectID(ctx context.Context, projectID int64, roles []string) ([]*types.AssayWithDatasetInfo, error)

	CreateDatasetAssay(ctx context.Context, datasetAssay *types.DatasetAssay) error
	GetDatasetAssayByID(ctx context.Context, id int64) (*types.DatasetAssay, error)
	GetDatasetAssayByAssayID(ctx context.Context, assayID int64) (*types.DatasetAssay, error)
	UpdateDatasetAssay(ctx context.Context, datasetAssay *types.DatasetAssay) error
	DeleteDatasetAssay(ctx context.Context, id int64) error
	ListDatasetAssay(ctx context.Context) ([]*types.DatasetAssay, error)

	// Import lookups: resolve each hierarchy level by its natural key so the TSV
	// importer can decide between insert and update.
	GetAssayByNameAndDatasetID(ctx context.Context, datasetID int64, sampleName, role string) (*types.Assay, error)
	GetFileByAssayIDAndFileKey(ctx context.Context, assayID int64, fileKey string) (*types.File, error)

	// GetFileByAnalysisNodeIDAndFileKey resolves a file produced by a DAG node by
	// the node it belongs to and its file key, so the completion path can upsert
	// instead of inserting duplicates when a node is re-run.
	GetFileByAnalysisNodeIDAndFileKey(ctx context.Context, analysisNodeID int64, fileKey string) (*types.File, error)

	// SampleName is only unique inside a dataset (per role), so the uniqueness
	// check below is dataset-scoped instead of global.
	//
	// ExistsAssayNameInDataset reports whether another assay with the same
	// sample_name + role (excluding excludeAssayID) is bound to datasetID.
	ExistsAssayNameInDataset(ctx context.Context, datasetID int64, sampleName, role string, excludeAssayID int64) (bool, error)

	ExistsProjectByID(ctx context.Context, id int64) (bool, error)
	ExistsDatasetByID(ctx context.Context, id int64) (bool, error)
	ExistsFileByID(ctx context.Context, id int64) (bool, error)
	ExistsAssayByID(ctx context.Context, id int64) (bool, error)

	DeleteDatasetWithRelations(ctx context.Context, id int64) error
	DeleteFileWithRelations(ctx context.Context, id int64) error
	DeleteAssayWithRelations(ctx context.Context, id int64) error
}

type DataService

type DataService interface {
	// CreateDataset creates a dataset and binds it to the given project.
	CreateDataset(ctx context.Context, dataset *types.Dataset, projectID int64) error
	// EnsureDatasetDir verifies the dataset exists and creates its workspace
	// directory (utils.GetDatasetDir) when missing, returning the path.
	EnsureDatasetDir(ctx context.Context, datasetID int64, projectID int64) (string, error)
	// ListDatasetDirFiles returns the dataset workspace directory path
	// (utils.GetDatasetDir) and every physical file found under it (recursively),
	// flagging the ones already bound to the dataset.
	ListDatasetDirFiles(ctx context.Context, datasetID int64, projectID int64) (string, []*types.DatasetDirFile, error)
	// ImportDatasetDirFiles registers every file under the dataset workspace
	// directory that is not yet bound to the dataset (matched by
	// go_file.path + go_dataset_file.dataset_id).
	ImportDatasetDirFiles(ctx context.Context, datasetID int64, projectID int64, role string) (*types.ImportDatasetDirFilesResult, error)
	// ListDatasetFiles returns every file bound to one dataset (go_dataset_file ->
	// go_file), newest binding first.
	ListDatasetFiles(ctx context.Context, datasetID int64) ([]*types.FileWithDatasetInfo, error)
	GetDatasetByID(ctx context.Context, id int64) (*types.Dataset, error)
	UpdateDataset(ctx context.Context, dataset *types.Dataset) error
	DeleteDataset(ctx context.Context, id int64) error
	ListDataset(ctx context.Context) ([]*types.Dataset, error)
	// ListDatasetByProjectID returns every dataset bound to the project
	// (go_project_dataset -> go_dataset), newest first.
	ListDatasetByProjectID(ctx context.Context, projectID int64) ([]*types.Dataset, error)
	PageDatasetByProjectID(ctx context.Context, pagination *types.Pagination, query *types.QueryDataset, projectID int64) (*types.PageResult, error)

	CreateProjectDataset(ctx context.Context, projectDataset *types.ProjectDataset) error
	GetProjectDatasetByID(ctx context.Context, id int64) (*types.ProjectDataset, error)
	UpdateProjectDataset(ctx context.Context, projectDataset *types.ProjectDataset) error
	DeleteProjectDataset(ctx context.Context, id int64) error
	ListProjectDataset(ctx context.Context) ([]*types.ProjectDataset, error)

	CreateFile(ctx context.Context, file *types.File) error
	GetFileByID(ctx context.Context, id int64) (*types.File, error)
	UpdateFile(ctx context.Context, file *types.File) error
	DeleteFile(ctx context.Context, id int64) error
	ListFile(ctx context.Context) ([]*types.File, error)
	PageFileByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64, roles []string) (*types.PageResult, error)
	ListFileByProjectID(ctx context.Context, projectID int64, roles []string) ([]*types.FileWithDatasetInfo, error)
	ListFileByProjectIDGroupByRole(ctx context.Context, projectID int64) ([]*types.FileByProjectRoleGroup, error)
	// ListFileByProjectIDViaAnalysisNode returns the files produced by the
	// project's analysis nodes, resolved through go_file.analysis_node_id ->
	// analysis_nodes.id (analysis_nodes.project_id carries the numeric project
	// PK). Every node file is returned, keyed by its own go_file.role (the role
	// its output_patterns entry declared, defaulted on write).
	ListFileByProjectIDViaAnalysisNode(ctx context.Context, projectID int64) ([]*types.FileWithDatasetInfo, error)
	// PageFileByProjectIDViaAnalysisNode returns the same analysis-node files as
	// ListFileByProjectIDViaAnalysisNode, paginated.
	PageFileByProjectIDViaAnalysisNode(ctx context.Context, pagination *types.Pagination, projectID int64) (*types.PageResult, error)
	// ListFileByAssayID returns the files owned by one assay; an assay without
	// files yields an empty slice (not an error).
	ListFileByAssayID(ctx context.Context, assayID int64) ([]*types.File, error)
	// ListFileByAssayIDAndRole returns the files owned by one assay, filtered on
	// the owning assay's role (go_assay.role). An empty roles slice adds no role
	// condition, so every file of the assay is returned (mirrors
	// ListAssayByProjectID).
	ListFileByAssayIDAndRole(ctx context.Context, assayID int64, roles []string) ([]*types.File, error)
	// ListFileByAnalysisNodeID returns the files produced by one DAG analysis
	// node, resolved through go_file.analysis_node_id -> analysis_nodes.id. A node
	// without files yields an empty slice (not an error).
	ListFileByAnalysisNodeID(ctx context.Context, analysisNodeID int64) ([]*types.File, error)

	CreateDatasetFile(ctx context.Context, datasetFile *types.DatasetFile) error
	AddFileToDataset(ctx context.Context, req *types.AddFileToDatasetRequest) (*types.AddFileToDatasetResponse, error)
	// UploadFileToDataset stores an uploaded file into the dataset workspace
	// directory and registers it as a dataset file with the given role.
	UploadFileToDataset(ctx context.Context, datasetID int64, projectID int64, role, fileName string, src io.Reader) (*types.AddFileToDatasetResponse, error)
	GetDatasetFileByID(ctx context.Context, id int64) (*types.DatasetFile, error)
	DeleteDatasetFile(ctx context.Context, id int64) error
	ListDatasetFile(ctx context.Context) ([]*types.DatasetFile, error)

	CreateAssay(ctx context.Context, assay *types.Assay) error
	GetAssayByID(ctx context.Context, id int64) (*types.Assay, error)
	UpdateAssay(ctx context.Context, assay *types.Assay) error
	DeleteAssay(ctx context.Context, id int64) error
	ListAssay(ctx context.Context) ([]*types.Assay, error)
	PageAssayByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) (*types.PageResult, error)
	// ListAssayByProjectID returns the project's assays, resolved through the
	// project's datasets (go_project_dataset -> go_dataset_assay -> go_assay).
	// When roles is non-empty the assays are filtered on go_assay.role; an empty
	// roles slice adds no role condition and returns every assay.
	ListAssayByProjectID(ctx context.Context, projectID int64, roles []string) ([]*types.AssayWithDatasetInfo, error)

	CreateDatasetAssay(ctx context.Context, datasetAssay *types.DatasetAssay) error
	GetDatasetAssayByID(ctx context.Context, id int64) (*types.DatasetAssay, error)
	// GetDatasetAssayByAssayID returns the single dataset binding of one assay,
	// or gorm.ErrRecordNotFound when the assay is not bound to any dataset yet.
	GetDatasetAssayByAssayID(ctx context.Context, assayID int64) (*types.DatasetAssay, error)
	UpdateDatasetAssay(ctx context.Context, datasetAssay *types.DatasetAssay) error
	DeleteDatasetAssay(ctx context.Context, id int64) error
	ListDatasetAssay(ctx context.Context) ([]*types.DatasetAssay, error)

	// ImportAssayTSV bulk-imports the Assay -> File tree from a TSV text scoped
	// to one dataset, upserting each level by its natural key
	// (dataset+sample_name+assay_role, assay+file_key).
	ImportAssayTSV(ctx context.Context, req *types.ImportAssayTSVRequest) (*types.ImportAssayTSVResult, error)
}

type LLMRepository

type LLMRepository interface {
	CreateLLMSession(ctx context.Context, session *types.LLMSession) error
	GetLLMSessionByID(ctx context.Context, id int64) (*types.LLMSession, error)
	GetLLMSessionByIDAndProjectID(ctx context.Context, id int64, projectID int64) (*types.LLMSession, error)
	UpdateLLMSession(ctx context.Context, session *types.LLMSession) error
	DeleteLLMSession(ctx context.Context, id int64) error
	ListLLMSessionByProjectID(ctx context.Context, projectID int64) ([]*types.LLMSession, error)
	DeleteLLMSessionWithRelations(ctx context.Context, id int64) error

	CreateLLMConversation(ctx context.Context, conversation *types.LLMConversation) error
	GetLLMConversationByID(ctx context.Context, id int64) (*types.LLMConversation, error)
	GetLLMConversationByIDAndProjectID(ctx context.Context, id int64, projectID int64) (*types.LLMConversation, error)
	UpdateLLMConversation(ctx context.Context, conversation *types.LLMConversation) error
	DeleteLLMConversation(ctx context.Context, id int64) error
	ListLLMConversationBySessionID(ctx context.Context, llmSessionID int64) ([]*types.LLMConversation, error)
}

type LLMService

type LLMService interface {
	CreateLLMSession(ctx context.Context, userID int64, session *types.LLMSession) error
	GetLLMSessionByID(ctx context.Context, userID int64, id int64) (*types.LLMSession, error)
	UpdateLLMSession(ctx context.Context, userID int64, session *types.LLMSession) error
	DeleteLLMSession(ctx context.Context, userID int64, id int64) error
	ListLLMSession(ctx context.Context, userID int64) ([]*types.LLMSession, error)

	CreateLLMConversation(ctx context.Context, userID int64, conversation *types.LLMConversation) error
	GetLLMConversationByID(ctx context.Context, userID int64, id int64) (*types.LLMConversation, error)
	UpdateLLMConversation(ctx context.Context, userID int64, conversation *types.LLMConversation) error
	DeleteLLMConversation(ctx context.Context, userID int64, id int64) error
	ListLLMConversationBySessionID(ctx context.Context, userID int64, llmSessionID int64) ([]*types.LLMConversation, error)
}

type NodeOrchestrator

type NodeOrchestrator interface {
	StartAsync(ctx context.Context, analysisNodeID int64) error
	StopAsync(ctx context.Context, analysisNodeID int64) error
}

NodeOrchestrator dispatches a single analysis node without requiring DAG analysis scheduling.

type ProjectRepository

type ProjectRepository interface {
	ListProjectByUserID(ctx context.Context, userID int64) ([]*types.ProjectListItem, error)
	GetProjectByID(ctx context.Context, id int64) (*types.Project, error)
	GetActiveProjectByUserID(ctx context.Context, userID int64) (*types.Project, error)
	CreateProject(ctx context.Context, project *types.Project) error
	AddUserProject(ctx context.Context, up *types.UserProject) error
	ExistsUserProject(ctx context.Context, userID int64, projectID int64) (bool, error)
	GetUserProject(ctx context.Context, userID int64, projectID int64) (*types.UserProject, error)
	// GetActiveUserProjectByUserID 返回用户当前激活的项目绑定(含该项目下的菜单配置)。
	GetActiveUserProjectByUserID(ctx context.Context, userID int64) (*types.UserProject, error)
	GetUserProjectByShareCode(ctx context.Context, shareCode string) (*types.UserProject, error)
	UpdateProjectSharing(ctx context.Context, userID int64, projectID int64, enabled bool, shareCode string) error
	// UpdateUserProjectMenuConfig 覆盖某个用户在某个项目下的菜单配置。
	UpdateUserProjectMenuConfig(ctx context.Context, userID int64, projectID int64, config types.UserMenuConfig) error
	DeleteUserProject(ctx context.Context, userID int64, projectID int64) error
	ActivateUserProject(ctx context.Context, userID int64, projectID int64) error
	AddProjectReport(ctx context.Context, report *types.ProjectReport) error
	GetProjectReportByID(ctx context.Context, reportID int64) (*types.ProjectReport, error)
	UpdateProjectReport(ctx context.Context, report *types.ProjectReport) error
	DeleteProjectReport(ctx context.Context, projectID int64, reportID int64) error
	ListProjectReportByProjectID(ctx context.Context, projectID int64) ([]*types.ProjectReport, error)
	PageProjectReportByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.ProjectReport, int64, error)
	// ProjectReportItem data access methods.
	AddProjectReportItem(ctx context.Context, item *types.ProjectReportItem) error
	GetProjectReportItemByID(ctx context.Context, itemID int64) (*types.ProjectReportItem, error)
	UpdateProjectReportItem(ctx context.Context, item *types.ProjectReportItem) error
	DeleteProjectReportItem(ctx context.Context, itemID int64) error
	DeleteProjectReportItemsByIDs(ctx context.Context, itemIDs []int64) error
	DeleteProjectReportItemsByReportID(ctx context.Context, reportID int64) error
	// ListProjectReportItemsByReportID 按全局 sort_order 返回原始条目(未按树展开),
	// 需要 tree 顺序时由 service 层调用 flattenProjectReportItems 重排。
	ListProjectReportItemsByReportID(ctx context.Context, reportID int64) ([]*types.ProjectReportItem, error)
	// ExistsProjectReportItemOwner 判断同一报告下是否已存在相同 owner 引用(owner_type + owner_id)的条目。
	// excludeItemID 为需要排除的条目主键(更新场景排除自身),传 0 表示不排除。
	ExistsProjectReportItemOwner(ctx context.Context, reportID int64, ownerType types.ProjectReportItemOwnerType, ownerID int64, excludeItemID int64) (bool, error)
	ReorderProjectReportItems(ctx context.Context, reportID int64, orders []types.ProjectReportItemOrder) error

	// Literature data access methods.
	CreateLiterature(ctx context.Context, literature *types.Literature) error
	GetLiteratureByID(ctx context.Context, literatureID int64) (*types.Literature, error)
	UpdateLiterature(ctx context.Context, literature *types.Literature) error
	DeleteLiterature(ctx context.Context, literatureID int64) error
	ListLiteratureByProjectID(ctx context.Context, projectID int64) ([]*types.Literature, error)
	PageLiteratureByProjectID(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.Literature, int64, error)
	AddProjectLiterature(ctx context.Context, pl *types.ProjectLiterature) error
	ExistsProjectLiterature(ctx context.Context, projectID int64, literatureID int64) (bool, error)
	DeleteProjectLiterature(ctx context.Context, projectID int64, literatureID int64) error
	DeleteProjectLiteratureByLiteratureID(ctx context.Context, literatureID int64) error
	// GetLiteratureOwnerProjectID 返回文献第一条项目绑定所属的 project id。
	GetLiteratureOwnerProjectID(ctx context.Context, literatureID int64) (int64, error)
	PageLiteraturePool(ctx context.Context, pagination *types.Pagination, projectID int64) ([]*types.LiteraturePoolItem, int64, error)
}

ProjectRepository defines project data access methods.

type ProjectService

type ProjectService interface {
	ListProjectByUserID(ctx context.Context, userID int64) ([]*types.ProjectListItem, error)
	GetActiveProjectByUserID(ctx context.Context, userID int64) (*types.Project, error)
	GetActiveProjectDirByUserID(ctx context.Context, userID int64, baseDir string) (*types.Project, string, error)
	GetProjectByID(ctx context.Context, id int64) (*types.Project, error)
	AddUserProject(ctx context.Context, userID int64, projectID int64) error
	AddUserProjectByShareCode(ctx context.Context, userID int64, shareCode string) error
	UpdateProjectSharing(ctx context.Context, userID int64, projectID int64, enabled bool) (string, error)
	ActivateUserProject(ctx context.Context, userID int64, projectID int64) error
	DeleteUserProject(ctx context.Context, userID int64, projectID int64) error
	// GetActiveUserMenuConfig 返回用户在当前激活项目下的菜单配置(主区域标签页 + 底部面板)。
	// 用户没有激活项目时返回空配置,不报错。
	GetActiveUserMenuConfig(ctx context.Context, userID int64) (types.UserMenuConfig, error)
	// UpdateActiveUserMenuConfig 整体覆盖用户在当前激活项目下的菜单配置。
	// 没有激活项目时返回 gorm.ErrRecordNotFound。
	UpdateActiveUserMenuConfig(ctx context.Context, userID int64, config types.UserMenuConfig) error
	CreateDefaultProjectForUser(ctx context.Context, userID int64, username string) error
	CreateProjectForUser(ctx context.Context, userID int64, project *types.Project) (*types.Project, error)
	AddProjectReport(ctx context.Context, userID int64, report *types.ProjectReport) error
	UpdateProjectReport(ctx context.Context, userID int64, report *types.ProjectReport) error
	DeleteProjectReport(ctx context.Context, userID int64, reportID int64) error
	ListProjectReportByProjectID(ctx context.Context, userID int64, projectID int64) ([]*types.ProjectReport, error)
	PageProjectReportByProjectID(ctx context.Context, userID int64, projectID int64, pagination *types.Pagination) ([]*types.ProjectReport, int64, error)
	GetProjectReportDetailByID(ctx context.Context, userID int64, reportID int64) (*types.ProjectReport, error)
	GetProjectReportByID(ctx context.Context, reportID int64) (*types.ProjectReport, error)
	// ProjectReportItem business capabilities.
	// ListProjectReportItemsByReportID 返回报告下全部条目,按树的前序遍历展开(与前端 tree 顺序一致)。
	ListProjectReportItemsByReportID(ctx context.Context, userID int64, reportID int64) ([]*types.ProjectReportItem, error)
	AddProjectReportItem(ctx context.Context, userID int64, item *types.ProjectReportItem) error
	UpdateProjectReportItem(ctx context.Context, userID int64, item *types.ProjectReportItem) error
	DeleteProjectReportItem(ctx context.Context, userID int64, itemID int64) error
	// ReorderProjectReportItems 按拖拽结果批量更新条目的父节点与同级顺序。
	ReorderProjectReportItems(ctx context.Context, userID int64, reportID int64, orders []types.ProjectReportItemOrder) error
	GetProjectReportItemDetailByID(ctx context.Context, userID int64, itemID int64) (*types.ProjectReportItem, error)
	// GetProjectReportItemContent 返回指定条目(入参为 ProjectReportItem ID)渲染后的内容片段。
	GetProjectReportItemContent(ctx context.Context, itemID int64) (*types.ProjectReportItemContent, error)
	// PackageProjectReportItems 按条目树把内容打包到报告工作目录的 results 子目录,返回结果目录路径。
	// custom 写入 README.md;analysis_node 拷贝节点输出目录;ai_summary 拷贝摘要正文文件;analysis 暂不处理。
	PackageProjectReportItems(ctx context.Context, userID int64, reportID int64) (string, error)
	// GetProjectReportContent 汇总报告下所有条目,按顺序拼接成正文,仅返回拼接后的内容。
	GetProjectReportContent(ctx context.Context, reportID int64) (string, error)
	// GetProjectReportFile 读取报告工作目录下的自身 markdown 文件(output.md)内容。
	GetProjectReportFile(ctx context.Context, userID int64, reportID int64) (string, error)
	// UpdateProjectReportFile 覆写报告工作目录下的自身 markdown 文件(output.md)内容。
	// 目录尚不是 git 仓库时会就地初始化(不自动提交),保证报告目录始终处于版本管理下。
	UpdateProjectReportFile(ctx context.Context, userID int64, reportID int64, content string) error
	// GetProjectReportGitDiff 返回报告工作目录的本地未提交改动(报告没有发布目标)。
	GetProjectReportGitDiff(ctx context.Context, userID int64, reportID int64) (*types.ProjectReportGitDiff, error)
	// CommitProjectReport 把报告工作目录的所有改动提交为一个 commit(无改动时不产生空提交)。
	CommitProjectReport(ctx context.Context, userID int64, reportID int64, message string) (*types.ProjectReportCommitResult, error)
	// RevertProjectReportFile 撤回报告工作目录里单个文件的未提交改动(恢复为本地 HEAD 版本)。
	RevertProjectReportFile(ctx context.Context, userID int64, reportID int64, relPath string) error

	// Literature (参考文献) business capabilities.
	AddLiterature(ctx context.Context, userID int64, literature *types.Literature, content string) (*types.Literature, string, error)
	UpdateLiterature(ctx context.Context, userID int64, literature *types.Literature, content string) error
	DeleteLiterature(ctx context.Context, userID int64, literatureID int64) error
	GetLiteratureDetailByID(ctx context.Context, userID int64, literatureID int64) (*types.LiteratureDetail, error)
	ListLiteratureByProjectID(ctx context.Context, userID int64) ([]*types.Literature, error)
	PageLiteratureByProjectID(ctx context.Context, userID int64, pagination *types.Pagination) ([]*types.Literature, int64, error)
	BindLiteratureToProject(ctx context.Context, userID int64, literatureID int64) error
	UnbindLiteratureFromProject(ctx context.Context, userID int64, literatureID int64) error
	PageLiteraturePool(ctx context.Context, userID int64, pagination *types.Pagination) ([]*types.LiteraturePoolItem, int64, error)
}

ProjectService defines project business capabilities.

type SheetFileService

type SheetFileService interface {
	ReadWorkbook(ctx context.Context, filePath, format string) (*WorkbookReadResult, error)
	WriteWorkbook(ctx context.Context, filePath, format string, workbookData map[string]any) (*WorkbookWriteResult, error)
}

SheetFileService defines local sheet file read/write capabilities. Current implementation supports Excel (xlsx), while csv/tsv are reserved for future extension.

type StoreRepository

type StoreRepository interface {
	CreateStore(ctx context.Context, item *types.Store) error
	GetStoreByID(ctx context.Context, id int64) (*types.Store, error)
	GetStoreByStoreID(ctx context.Context, storeID string) (*types.Store, error)
	UpdateStore(ctx context.Context, item *types.Store) error
	DeleteStore(ctx context.Context, id int64) error
	ListStore(ctx context.Context) ([]*types.Store, error)
	PageStore(ctx context.Context, pagination *types.Pagination, query *types.StorePageQuery) ([]*types.Store, int64, error)
	ListInstalledWorkflowMap(ctx context.Context, activeProjectID int64, storeIDs []int64) (map[int64]uint, error)
	ListInstalledScriptMap(ctx context.Context, activeProjectID int64, storeIDs []int64) (map[int64]int64, error)
}

type StoreService

type StoreService interface {
	CreateStore(ctx context.Context, item *types.Store) error
	GetStoreByID(ctx context.Context, id int64) (*types.Store, error)
	GetStoreByStoreID(ctx context.Context, storeID string) (*types.Store, error)
	UpdateStore(ctx context.Context, item *types.Store) error
	DeleteStore(ctx context.Context, id int64) error
	ListStore(ctx context.Context) ([]*types.Store, error)
	PageStore(ctx context.Context, userID int64, pagination *types.Pagination, query *types.StorePageQuery) (*types.PageResult, error)
}

type TaskEnqueuer

type TaskEnqueuer interface {
	Enqueue(task *asynq.Task, opts ...asynq.Option) (*asynq.TaskInfo, error)
}

TaskEnqueuer abstracts task enqueueing. *asynq.Client satisfies this interface. For Lite mode (no Redis), a synchronous implementation dispatches tasks inline.

type UserRepository

type UserRepository interface {
	// CreateUser creates a user
	CreateUser(ctx context.Context, user *types.User) error
	// GetUserByID gets a user by ID
	GetUserByID(ctx context.Context, id int64) (*types.User, error)
	// GetUserByEmail gets a user by email
	GetUserByEmail(ctx context.Context, email string) (*types.User, error)
	// GetUserByUsername gets a user by username
	GetUserByUsername(ctx context.Context, username string) (*types.User, error)
	// GetUserByTenantID gets the first user (owner) of a tenant
	GetUserByTenantID(ctx context.Context, tenantID uint64) (*types.User, error)
	// UpdateUser updates a user
	UpdateUser(ctx context.Context, user *types.User) error
	// DeleteUser deletes a user
	DeleteUser(ctx context.Context, id int64) error
	// ListUsers lists users with pagination
	ListUsers(ctx context.Context, offset, limit int) ([]*types.User, error)
	// SearchUsers searches users by username or email
	SearchUsers(ctx context.Context, query string, limit int) ([]*types.User, error)
}

UserRepository defines the user repository interface

type UserService

type UserService interface {
	// Register creates a new user account
	Register(ctx context.Context, req *types.RegisterRequest) (*types.User, error)
	// Login authenticates a user and returns tokens
	Login(ctx context.Context, req *types.LoginRequest) (*types.LoginResponse, error)
	// GetOIDCAuthorizationURL builds the third-party OIDC authorization URL
	// GetOIDCAuthorizationURL(ctx context.Context, redirectURI string) (*types.OIDCAuthURLResponse, error)
	// LoginWithOIDC exchanges the callback code, auto-provisions users if needed, and completes login
	// LoginWithOIDC(ctx context.Context, code, redirectURI string) (*types.OIDCCallbackResponse, error)
	// GetUserByID gets a user by ID
	GetUserByID(ctx context.Context, id int64) (*types.User, error)
	// GetUserByEmail gets a user by email
	GetUserByEmail(ctx context.Context, email string) (*types.User, error)
	// GetUserByUsername gets a user by username
	GetUserByUsername(ctx context.Context, username string) (*types.User, error)
	// GetUserByTenantID gets the first user (owner) of a tenant
	GetUserByTenantID(ctx context.Context, tenantID uint64) (*types.User, error)
	// UpdateUser updates user information
	UpdateUser(ctx context.Context, user *types.User) error
	// DeleteUser deletes a user
	DeleteUser(ctx context.Context, id int64) error
	// ChangePassword changes user password
	ChangePassword(ctx context.Context, userID int64, oldPassword, newPassword string) error
	// ValidatePassword validates user password
	ValidatePassword(ctx context.Context, userID int64, password string) error
	// GenerateTokens generates access and refresh tokens for user
	GenerateTokens(ctx context.Context, user *types.User) (accessToken, refreshToken string, err error)
	// ValidateToken validates an access token
	ValidateToken(ctx context.Context, token string) (*types.User, error)
	// RefreshToken refreshes access token using refresh token
	RefreshToken(ctx context.Context, refreshToken string) (accessToken, newRefreshToken string, err error)
	// RevokeToken revokes a token
	RevokeToken(ctx context.Context, token string) error
	// GetCurrentUser gets current user from context
	GetCurrentUser(ctx context.Context) (*types.User, error)
	// SearchUsers searches users by username or email
	SearchUsers(ctx context.Context, query string, limit int) ([]*types.User, error)
}

UserService defines the user service interface

type WorkbookReadResult

type WorkbookReadResult struct {
	FilePath     string         `json:"file_path"`
	Format       string         `json:"format"`
	WorkbookData map[string]any `json:"workbook_data"`
	// File is the go_file row the workbook was read from. It is only populated
	// by ReadWorkbookByFileID so the frontend can render the file metadata
	// without an extra request.
	File *types.File `json:"file,omitempty"`
}

type WorkbookWriteResult

type WorkbookWriteResult struct {
	FilePath string `json:"file_path"`
	Format   string `json:"format"`
}

type WorkflowRepository

type WorkflowRepository interface {
	GetWorkflowByID(ctx context.Context, id int64) (*types.Workflow, error)
	PageWorkflow(ctx context.Context, pagination *types.Pagination, query *types.WorkflowPageQuery) ([]*types.Workflow, int64, error)
	ExistsWorkflowInProjectByWorkflowID(ctx context.Context, projectID int64, workflowID string) (*types.Workflow, error)
	PageScript(ctx context.Context, pagination *types.Pagination, query *types.ScriptPageQuery) ([]*types.Script, int64, error)
	GetScriptByID(ctx context.Context, id int64) (*types.Script, error)
	GetScriptByScriptID(ctx context.Context, projectID int64, scriptID string) (*types.Script, error)
	ExistsScriptInProjectByScriptID(ctx context.Context, projectID int64, scriptID string) (*types.Script, error)
	FindScriptsByScriptIDs(ctx context.Context, projectID int64, scriptIDs []string) ([]*types.Script, error)
	GetScriptContainerSnapshotByScriptID(ctx context.Context, scriptID int64) (*types.ScriptContainerSnapshot, error)
	CreateWorkflow(ctx context.Context, workflow *types.Workflow) error
	UpdateWorkflow(ctx context.Context, workflow *types.Workflow) error
	DeleteWorkflowByID(ctx context.Context, id int64) error
	CreateScript(ctx context.Context, script *types.Script) error
	UpdateScript(ctx context.Context, script *types.Script) error
	DeleteScriptByID(ctx context.Context, id int64) error
	ListWorkflowsByProjectID(ctx context.Context, projectID int64) ([]*types.Workflow, error)
}

type WorkflowService

type WorkflowService interface {
	// GetFormJSONByWorkflowID 按工作流主键(int64)返回表单配置。
	GetFormJSONByWorkflowID(ctx context.Context, workflowID int64) ([]any, error)
	// GetScriptFormJSONByID 返回脚本表单配置(io_schema.inputs)以及脚本目录下 io_schema.json 的
	// 完整内容;需要 outputs / scatter / gather 等的调用方复用第二个返回值,避免重复读盘。
	GetScriptFormJSONByID(ctx context.Context, scriptID int64) ([]any, map[string]any, error)
	// GetScriptFormJSONByScript 与 GetScriptFormJSONByID 同口径,但直接接收已加载的脚本对象,
	// 避免调用方手上已有 *types.Script 时再查一次库。
	GetScriptFormJSONByScript(ctx context.Context, script *types.Script) ([]any, map[string]any, error)
	// 后续废除
	// GetFormJSONByScriptID(ctx context.Context, scriptID string) ([]any, error)
	GetWorkflowByID(ctx context.Context, id int64) (*types.Workflow, error)
	// GetWorkflowVisByID(ctx context.Context, workflowID string) (map[string]any, error)
	GetWorkflowVisByWorkflow(ctx context.Context, workflow *types.Workflow) (map[string]any, error)
	// GetWorkflowVisByWorkflowID 按工作流主键(int64)返回可视化 DAG。
	GetWorkflowVisByWorkflowID(ctx context.Context, workflowID int64) (map[string]any, error)
	PageWorkflow(ctx context.Context, pagination *types.Pagination, query *types.WorkflowPageQuery) ([]*types.Workflow, int64, error)
	ExistsWorkflowInProjectByWorkflowID(ctx context.Context, projectID int64, workflowID string) (*types.Workflow, error)
	PageScript(ctx context.Context, pagination *types.Pagination, query *types.ScriptPageQuery) ([]*types.Script, int64, error)
	GetScriptByID(ctx context.Context, id int64) (*types.Script, error)
	GetScriptByScriptID(ctx context.Context, projectID int64, scriptID string) (*types.Script, error)
	ExistsScriptInProjectByScriptID(ctx context.Context, projectID int64, scriptID string) (*types.Script, error)
	// ScriptToNode 返回可直接添加到工作流 DAG 画布的 script 节点(含唯一 node_id)
	ScriptToNode(ctx context.Context, workflowID int64, scriptID int64) (map[string]any, error)
	// 后续废除
	// GetScriptMainFileByScriptID(ctx context.Context, scriptID string) (string, string, error)
	GetScriptFileByScriptID(ctx context.Context, scriptID int64) (string, string, error)
	GetScriptContainerSnapshotByScriptID(ctx context.Context, scriptID int64) (*types.ScriptContainerSnapshot, error)
	GenerateWorkflowJSONByWorkflowID(ctx context.Context, workflowID int64, storageBaseDir string) (*types.WorkflowJSONExportResponse, error)
	GenerateScriptJSONByScriptID(ctx context.Context, scriptID int64) (*types.ScriptJSONExportResponse, error)
	CreateWorkflow(ctx context.Context, workflow *types.Workflow) error
	UpdateWorkflow(ctx context.Context, workflow *types.Workflow) error
	// UpdateWorkflowDagDefinition 仅更新指定 workflow 的 dag_definition,避免整体替换把其他字段写成零值
	UpdateWorkflowDagDefinition(ctx context.Context, workflowID int64, dagDefinition string) error
	DeleteWorkflow(ctx context.Context, id int64) error
	CreateScript(ctx context.Context, script *types.Script) error
	UpdateScript(ctx context.Context, script *types.Script) error
	DeleteScript(ctx context.Context, id int64) error
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL