Files
kandev/backend/internal/task/repository/memory.go
T
jcfs ba919305c2 Initial commit: Kandev with SQLite persistence and agent integration
Features:
- Unified Go binary running Task Service, Agent Manager, and Orchestrator
- SQLite persistence for boards, columns, and tasks
- Docker-based agent execution with ACP message streaming
- Augment Agent integration with session resumption support
- RESTful API for all operations (port 8080)
- In-memory event bus for service communication

Architecture:
- cmd/kandev: Single entry point for all services
- internal/task: Task, board, and column management
- internal/agent: Docker container lifecycle and ACP streaming
- internal/orchestrator: Agent coordination and monitoring
- internal/events: In-memory pub/sub event bus

Documentation:
- README.md: Project overview and quick start
- docs/ARCHITECTURE.md: System architecture (current + planned)
- docs/GETTING_STARTED.md: Development setup guide
- docs/IMPLEMENTATION_PLAN.md: Original microservices plan
- backend/NEXT_STEPS.md: Development roadmap
2026-01-10 01:30:24 +00:00

272 lines
6.1 KiB
Go

package repository
import (
"context"
"fmt"
"sync"
"time"
"github.com/google/uuid"
"github.com/kandev/kandev/internal/task/models"
v1 "github.com/kandev/kandev/pkg/api/v1"
)
// MemoryRepository provides in-memory task storage operations
type MemoryRepository struct {
tasks map[string]*models.Task
boards map[string]*models.Board
columns map[string]*models.Column
mu sync.RWMutex
}
// Ensure MemoryRepository implements Repository interface
var _ Repository = (*MemoryRepository)(nil)
// NewMemoryRepository creates a new in-memory task repository
func NewMemoryRepository() *MemoryRepository {
return &MemoryRepository{
tasks: make(map[string]*models.Task),
boards: make(map[string]*models.Board),
columns: make(map[string]*models.Column),
}
}
// Close is a no-op for in-memory repository
func (r *MemoryRepository) Close() error {
return nil
}
// Task operations
// CreateTask creates a new task
func (r *MemoryRepository) CreateTask(ctx context.Context, task *models.Task) error {
r.mu.Lock()
defer r.mu.Unlock()
if task.ID == "" {
task.ID = uuid.New().String()
}
now := time.Now().UTC()
task.CreatedAt = now
task.UpdatedAt = now
r.tasks[task.ID] = task
return nil
}
// GetTask retrieves a task by ID
func (r *MemoryRepository) GetTask(ctx context.Context, id string) (*models.Task, error) {
r.mu.RLock()
defer r.mu.RUnlock()
task, ok := r.tasks[id]
if !ok {
return nil, fmt.Errorf("task not found: %s", id)
}
return task, nil
}
// UpdateTask updates an existing task
func (r *MemoryRepository) UpdateTask(ctx context.Context, task *models.Task) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.tasks[task.ID]; !ok {
return fmt.Errorf("task not found: %s", task.ID)
}
task.UpdatedAt = time.Now().UTC()
r.tasks[task.ID] = task
return nil
}
// DeleteTask deletes a task by ID
func (r *MemoryRepository) DeleteTask(ctx context.Context, id string) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.tasks[id]; !ok {
return fmt.Errorf("task not found: %s", id)
}
delete(r.tasks, id)
return nil
}
// ListTasks returns all tasks for a board
func (r *MemoryRepository) ListTasks(ctx context.Context, boardID string) ([]*models.Task, error) {
r.mu.RLock()
defer r.mu.RUnlock()
var result []*models.Task
for _, task := range r.tasks {
if task.BoardID == boardID {
result = append(result, task)
}
}
return result, nil
}
// ListTasksByColumn returns all tasks in a column
func (r *MemoryRepository) ListTasksByColumn(ctx context.Context, columnID string) ([]*models.Task, error) {
r.mu.RLock()
defer r.mu.RUnlock()
var result []*models.Task
for _, task := range r.tasks {
if task.ColumnID == columnID {
result = append(result, task)
}
}
return result, nil
}
// UpdateTaskState updates the state of a task
func (r *MemoryRepository) UpdateTaskState(ctx context.Context, id string, state v1.TaskState) error {
r.mu.Lock()
defer r.mu.Unlock()
task, ok := r.tasks[id]
if !ok {
return fmt.Errorf("task not found: %s", id)
}
task.State = state
task.UpdatedAt = time.Now().UTC()
return nil
}
// Board operations
// CreateBoard creates a new board
func (r *MemoryRepository) CreateBoard(ctx context.Context, board *models.Board) error {
r.mu.Lock()
defer r.mu.Unlock()
if board.ID == "" {
board.ID = uuid.New().String()
}
now := time.Now().UTC()
board.CreatedAt = now
board.UpdatedAt = now
r.boards[board.ID] = board
return nil
}
// GetBoard retrieves a board by ID
func (r *MemoryRepository) GetBoard(ctx context.Context, id string) (*models.Board, error) {
r.mu.RLock()
defer r.mu.RUnlock()
board, ok := r.boards[id]
if !ok {
return nil, fmt.Errorf("board not found: %s", id)
}
return board, nil
}
// UpdateBoard updates an existing board
func (r *MemoryRepository) UpdateBoard(ctx context.Context, board *models.Board) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.boards[board.ID]; !ok {
return fmt.Errorf("board not found: %s", board.ID)
}
board.UpdatedAt = time.Now().UTC()
r.boards[board.ID] = board
return nil
}
// DeleteBoard deletes a board by ID
func (r *MemoryRepository) DeleteBoard(ctx context.Context, id string) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.boards[id]; !ok {
return fmt.Errorf("board not found: %s", id)
}
delete(r.boards, id)
return nil
}
// ListBoards returns all boards
func (r *MemoryRepository) ListBoards(ctx context.Context) ([]*models.Board, error) {
r.mu.RLock()
defer r.mu.RUnlock()
result := make([]*models.Board, 0, len(r.boards))
for _, board := range r.boards {
result = append(result, board)
}
return result, nil
}
// Column operations
// CreateColumn creates a new column
func (r *MemoryRepository) CreateColumn(ctx context.Context, column *models.Column) error {
r.mu.Lock()
defer r.mu.Unlock()
if column.ID == "" {
column.ID = uuid.New().String()
}
now := time.Now().UTC()
column.CreatedAt = now
column.UpdatedAt = now
r.columns[column.ID] = column
return nil
}
// GetColumn retrieves a column by ID
func (r *MemoryRepository) GetColumn(ctx context.Context, id string) (*models.Column, error) {
r.mu.RLock()
defer r.mu.RUnlock()
column, ok := r.columns[id]
if !ok {
return nil, fmt.Errorf("column not found: %s", id)
}
return column, nil
}
// UpdateColumn updates an existing column
func (r *MemoryRepository) UpdateColumn(ctx context.Context, column *models.Column) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.columns[column.ID]; !ok {
return fmt.Errorf("column not found: %s", column.ID)
}
column.UpdatedAt = time.Now().UTC()
r.columns[column.ID] = column
return nil
}
// DeleteColumn deletes a column by ID
func (r *MemoryRepository) DeleteColumn(ctx context.Context, id string) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.columns[id]; !ok {
return fmt.Errorf("column not found: %s", id)
}
delete(r.columns, id)
return nil
}
// ListColumns returns all columns for a board
func (r *MemoryRepository) ListColumns(ctx context.Context, boardID string) ([]*models.Column, error) {
r.mu.RLock()
defer r.mu.RUnlock()
var result []*models.Column
for _, column := range r.columns {
if column.BoardID == boardID {
result = append(result, column)
}
}
return result, nil
}