mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 16:14:57 +00:00
refactor(store): split TeamStore into focused sub-interfaces
Split monolithic TeamStore (61 methods) into 6 focused interfaces: - TeamCRUDStore: core team + member operations (13 methods) - TaskStore: task CRUD + lifecycle transitions (22 methods) - TaskCommentStore: comments, events, attachments (10 methods) - TaskRecoveryStore: stale detection + recovery (6 methods) - TaskFollowupStore: follow-up scheduling (7 methods) - TeamAccessStore: user access grants (5 methods) TeamStore is now a composed interface embedding all sub-interfaces, maintaining full backward compatibility. No implementation changes.
This commit is contained in:
1 parent
96bf0ddb68
commit
96fbc79cd2
1 file changed
+38
-90
@@ -192,150 +192,98 @@ type ScopeEntry struct {
|
||||
ChatID string `json:"chat_id"`
|
||||
}
|
||||
|
||||
// TeamStore manages agent teams, tasks, and messages.
|
||||
type TeamStore interface {
|
||||
// Team CRUD
|
||||
// TeamCRUDStore manages core team and member operations.
|
||||
type TeamCRUDStore interface {
|
||||
CreateTeam(ctx context.Context, team *TeamData) error
|
||||
GetTeam(ctx context.Context, teamID uuid.UUID) (*TeamData, error)
|
||||
GetTeamUnscoped(ctx context.Context, id uuid.UUID) (*TeamData, error)
|
||||
UpdateTeam(ctx context.Context, teamID uuid.UUID, updates map[string]any) error
|
||||
DeleteTeam(ctx context.Context, teamID uuid.UUID) error
|
||||
ListTeams(ctx context.Context) ([]TeamData, error)
|
||||
|
||||
// Members
|
||||
AddMember(ctx context.Context, teamID, agentID uuid.UUID, role string) error
|
||||
RemoveMember(ctx context.Context, teamID, agentID uuid.UUID) error
|
||||
ListMembers(ctx context.Context, teamID uuid.UUID) ([]TeamMemberData, error)
|
||||
// ListIdleMembers returns team members (non-lead) that have no in_progress tasks.
|
||||
ListIdleMembers(ctx context.Context, teamID uuid.UUID) ([]TeamMemberData, error)
|
||||
|
||||
// GetTeamForAgent returns the team that the given agent belongs to.
|
||||
// Returns nil, nil if the agent is not in any team.
|
||||
GetTeamForAgent(ctx context.Context, agentID uuid.UUID) (*TeamData, error)
|
||||
|
||||
// KnownUserIDs returns distinct user IDs from sessions of team member agents.
|
||||
// Used by team settings UI to populate user select boxes.
|
||||
KnownUserIDs(ctx context.Context, teamID uuid.UUID, limit int) ([]string, error)
|
||||
|
||||
// Scopes (channel+chatID discovery across tasks and workspace)
|
||||
ListTaskScopes(ctx context.Context, teamID uuid.UUID) ([]ScopeEntry, error)
|
||||
}
|
||||
|
||||
// Tasks (shared task list)
|
||||
// TaskStore manages task CRUD, lifecycle transitions, and progress.
|
||||
type TaskStore interface {
|
||||
CreateTask(ctx context.Context, task *TeamTaskData) error
|
||||
UpdateTask(ctx context.Context, taskID uuid.UUID, updates map[string]any) error
|
||||
// ListTasks returns tasks for a team. orderBy: "priority" or "newest".
|
||||
// statusFilter: "" = non-completed (default), "completed", "all".
|
||||
// userID: if non-empty, filter to tasks created by this user.
|
||||
// channel+chatID: if either is non-empty, filter to that exact scope.
|
||||
// limit: max rows to return; 0 uses the default (30).
|
||||
ListTasks(ctx context.Context, teamID uuid.UUID, orderBy string, statusFilter string, userID string, channel string, chatID string, limit int, offset int) ([]TeamTaskData, error)
|
||||
// GetTask returns a single task by ID with joined agent info.
|
||||
GetTask(ctx context.Context, taskID uuid.UUID) (*TeamTaskData, error)
|
||||
// GetTasksByIDs returns multiple tasks by IDs in a single query.
|
||||
GetTasksByIDs(ctx context.Context, ids []uuid.UUID) ([]TeamTaskData, error)
|
||||
// SearchTasks performs FTS search over task subject+description.
|
||||
// userID: if non-empty, filter to tasks created by this user.
|
||||
SearchTasks(ctx context.Context, teamID uuid.UUID, query string, limit int, userID string) ([]TeamTaskData, error)
|
||||
// DeleteTask permanently removes a terminal-status task (completed/failed/cancelled).
|
||||
// Returns ErrTaskNotFound if the task does not exist or is not in a terminal status.
|
||||
DeleteTask(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
// DeleteTasks permanently removes multiple terminal-status tasks in a single query.
|
||||
// Returns the list of IDs that were actually deleted.
|
||||
DeleteTasks(ctx context.Context, taskIDs []uuid.UUID, teamID uuid.UUID) ([]uuid.UUID, error)
|
||||
|
||||
// ClaimTask atomically transitions a task from pending to in_progress.
|
||||
// Only one agent can claim a given task (row-level lock, race-safe).
|
||||
// teamID is validated in the WHERE clause to prevent cross-team task claiming.
|
||||
ClaimTask(ctx context.Context, taskID, agentID, teamID uuid.UUID) error
|
||||
|
||||
// AssignTask admin-assigns a pending task to a specific agent.
|
||||
// teamID is validated in the WHERE clause to prevent cross-team assignment.
|
||||
AssignTask(ctx context.Context, taskID, agentID, teamID uuid.UUID) error
|
||||
|
||||
// CompleteTask marks a task as completed and unblocks dependent tasks.
|
||||
// teamID is validated in the WHERE clause to prevent cross-team task completion.
|
||||
CompleteTask(ctx context.Context, taskID, teamID uuid.UUID, result string) error
|
||||
|
||||
// CancelTask marks a non-completed task as cancelled (status=completed, result="CANCELLED: ..."),
|
||||
// unblocks dependent tasks, and transitions blocked→pending when all blockers are resolved.
|
||||
// Returns error if the task is already completed or not found.
|
||||
CancelTask(ctx context.Context, taskID, teamID uuid.UUID, reason string) error
|
||||
|
||||
// FailTask marks an in_progress task as failed and stores the error message.
|
||||
// Unblocks dependent tasks so they aren't stuck.
|
||||
FailTask(ctx context.Context, taskID, teamID uuid.UUID, errMsg string) error
|
||||
// FailPendingTask marks a pending or blocked task as failed (post-turn validation).
|
||||
// Unlike FailTask, accepts pending/blocked source statuses.
|
||||
FailPendingTask(ctx context.Context, taskID, teamID uuid.UUID, errMsg string) error
|
||||
|
||||
// Review workflow
|
||||
ReviewTask(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
ApproveTask(ctx context.Context, taskID, teamID uuid.UUID, comment string) error
|
||||
RejectTask(ctx context.Context, taskID, teamID uuid.UUID, reason string) error
|
||||
UpdateTaskProgress(ctx context.Context, taskID, teamID uuid.UUID, percent int, step string) error
|
||||
RenewTaskLock(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
ResetTaskStatus(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
}
|
||||
|
||||
// Task comments
|
||||
// TaskCommentStore manages task comments, audit events, and attachments.
|
||||
type TaskCommentStore interface {
|
||||
AddTaskComment(ctx context.Context, comment *TeamTaskCommentData) error
|
||||
ListTaskComments(ctx context.Context, taskID uuid.UUID) ([]TeamTaskCommentData, error)
|
||||
ListRecentTaskComments(ctx context.Context, taskID uuid.UUID, limit int) ([]TeamTaskCommentData, error)
|
||||
|
||||
// Audit events
|
||||
RecordTaskEvent(ctx context.Context, event *TeamTaskEventData) error
|
||||
ListTaskEvents(ctx context.Context, taskID uuid.UUID) ([]TeamTaskEventData, error)
|
||||
// ListTeamEvents returns recent events across all tasks in a team.
|
||||
ListTeamEvents(ctx context.Context, teamID uuid.UUID, limit, offset int) ([]TeamTaskEventData, error)
|
||||
|
||||
// Attachments (path-based, no FK to workspace files)
|
||||
AttachFileToTask(ctx context.Context, att *TeamTaskAttachmentData) error
|
||||
GetAttachment(ctx context.Context, attachmentID uuid.UUID) (*TeamTaskAttachmentData, error)
|
||||
ListTaskAttachments(ctx context.Context, taskID uuid.UUID) ([]TeamTaskAttachmentData, error)
|
||||
DetachFileFromTask(ctx context.Context, taskID uuid.UUID, path string) error
|
||||
}
|
||||
|
||||
// Follow-up reminders
|
||||
// TaskRecoveryStore manages stale task detection and recovery.
|
||||
type TaskRecoveryStore interface {
|
||||
RecoverAllStaleTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
ForceRecoverAllTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
ListRecoverableTasks(ctx context.Context, teamID uuid.UUID) ([]TeamTaskData, error)
|
||||
MarkAllStaleTasks(ctx context.Context, olderThan time.Time) ([]RecoveredTaskInfo, error)
|
||||
MarkInReviewStaleTasks(ctx context.Context, olderThan time.Time) ([]RecoveredTaskInfo, error)
|
||||
FixOrphanedBlockedTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
}
|
||||
|
||||
// TaskFollowupStore manages follow-up reminder scheduling.
|
||||
type TaskFollowupStore interface {
|
||||
SetTaskFollowup(ctx context.Context, taskID, teamID uuid.UUID, followupAt time.Time, max int, message, channel, chatID string) error
|
||||
ClearTaskFollowup(ctx context.Context, taskID uuid.UUID) error
|
||||
// ListAllFollowupDueTasks returns due followup tasks across all v2 active teams (batch).
|
||||
ListAllFollowupDueTasks(ctx context.Context) ([]TeamTaskData, error)
|
||||
IncrementFollowupCount(ctx context.Context, taskID uuid.UUID, nextAt *time.Time) error
|
||||
|
||||
// Auto follow-up guardrails (system-level, no LLM dependency)
|
||||
// ClearFollowupByScope clears followup on all in_progress tasks for a given channel+chatID scope.
|
||||
ClearFollowupByScope(ctx context.Context, channel, chatID string) (int, error)
|
||||
// SetFollowupForActiveTasks sets followup on in_progress tasks that don't already have one.
|
||||
// Matches tasks scoped to the given channel+chatID, or unscoped tasks in the same team.
|
||||
SetFollowupForActiveTasks(ctx context.Context, teamID uuid.UUID, channel, chatID string, followupAt time.Time, max int, message string) (int, error)
|
||||
// HasActiveMemberTasks returns true if there are pending/in_progress/blocked tasks
|
||||
// assigned to agents other than the given agent (typically the lead).
|
||||
// Used to suppress auto-followup when the lead is waiting for teammates, not the user.
|
||||
HasActiveMemberTasks(ctx context.Context, teamID uuid.UUID, excludeAgentID uuid.UUID) (bool, error)
|
||||
}
|
||||
|
||||
// Progress
|
||||
UpdateTaskProgress(ctx context.Context, taskID, teamID uuid.UUID, percent int, step string) error
|
||||
|
||||
// Lock renewal (heartbeat to prevent stale recovery of long-running tasks)
|
||||
RenewTaskLock(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
|
||||
// Stale recovery (batch — all v2 active teams in single query)
|
||||
// RecoverAllStaleTasks resets in_progress tasks with expired locks back to pending.
|
||||
RecoverAllStaleTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
// ForceRecoverAllTasks resets ALL in_progress tasks back to pending (ignoring lock expiry).
|
||||
// Used on startup when no agents are running.
|
||||
ForceRecoverAllTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
// ListRecoverableTasks returns all pending tasks (including stale in_progress with expired locks).
|
||||
// Per-team: used by DispatchUnblockedTasks after task completion.
|
||||
ListRecoverableTasks(ctx context.Context, teamID uuid.UUID) ([]TeamTaskData, error)
|
||||
// MarkAllStaleTasks sets pending tasks older than olderThan to stale status across all v2 active teams.
|
||||
MarkAllStaleTasks(ctx context.Context, olderThan time.Time) ([]RecoveredTaskInfo, error)
|
||||
// MarkInReviewStaleTasks sets in_review tasks older than olderThan to stale across all v2 active teams.
|
||||
MarkInReviewStaleTasks(ctx context.Context, olderThan time.Time) ([]RecoveredTaskInfo, error)
|
||||
// FixOrphanedBlockedTasks unblocks blocked tasks where all blockers reached terminal status.
|
||||
FixOrphanedBlockedTasks(ctx context.Context) ([]RecoveredTaskInfo, error)
|
||||
// ResetTaskStatus resets a stale or failed task back to pending for retry.
|
||||
ResetTaskStatus(ctx context.Context, taskID, teamID uuid.UUID) error
|
||||
|
||||
// Team user grants
|
||||
// TeamAccessStore manages user-level team access grants.
|
||||
type TeamAccessStore interface {
|
||||
GrantTeamAccess(ctx context.Context, teamID uuid.UUID, userID, role, grantedBy string) error
|
||||
RevokeTeamAccess(ctx context.Context, teamID uuid.UUID, userID string) error
|
||||
ListTeamGrants(ctx context.Context, teamID uuid.UUID) ([]TeamUserGrant, error)
|
||||
ListUserTeams(ctx context.Context, userID string) ([]TeamData, error)
|
||||
HasTeamAccess(ctx context.Context, teamID uuid.UUID, userID string) (bool, error)
|
||||
}
|
||||
|
||||
// TeamStore composes all team sub-interfaces for backward compatibility.
|
||||
// New code should depend on the specific sub-interface it needs.
|
||||
type TeamStore interface {
|
||||
TeamCRUDStore
|
||||
TaskStore
|
||||
TaskCommentStore
|
||||
TaskRecoveryStore
|
||||
TaskFollowupStore
|
||||
TeamAccessStore
|
||||
}
|
||||
Reference in new issue
Block a user