package service import ( "axolotl/models" "axolotl/store" "fmt" ) // NodeService is the single entry point for all node operations. // All data-model integrity rules are enforced here; callers cannot produce // invalid state by interacting with this interface alone. // // Every NodeService instance is bound to a specific user (see User()). // GetNodeService returns an error when no user is configured. type NodeService interface { // User returns the name/ID of the user this service instance acts on behalf of. User() string // Query GetByID(id string) (*models.Node, error) List(filter ListFilter) ([]*models.Node, error) // Lifecycle Add(input AddInput) (*models.Node, error) Update(id string, input UpdateInput) (*models.Node, error) Delete(id string) error // User management AddUser(name string) (*models.Node, error) ListUsers() ([]*models.Node, error) } // AddInput describes a new node to create. // Tags may include special property tags (_type::, _status::, _prio::); the // service applies defaults (type=issue, status=open for issues) and validates. // Rels may include assignee, in_namespace, blocks, subtask, related, etc.; // user and namespace targets are auto-created as needed. type AddInput struct { Title string Content string DueDate string Tags []string Rels []RelInput } // UpdateInput describes changes to apply to an existing node. // Nil pointer fields mean "no change". // Setting _status::done in AddTags is rejected when the node has open blockers. // Adding assignee or in_namespace rels replaces the previous single target. type UpdateInput struct { Title *string Content *string DueDate *string // nil = no change; pointer to "" = clear due date AddTags []string RemoveTags []string AddRels []RelInput RemoveRels []RelInput } // ListFilter specifies which nodes to return. Empty slices are ignored. // Tags are matched as exact tag values or prefixes (e.g. "_status::open"). // Rels are resolved to node IDs; a missing target returns no results. type ListFilter struct { Tags []string Rels []RelInput } // RelInput is a typed, directed edge with a target that may be a name or node ID. type RelInput struct { Type models.RelType Target string // name or node ID; the service resolves names } func InitNodeService(path string) error { return store.InitSQLiteStore(path) } func GetNodeService(cfg Config) (NodeService, error) { user := cfg.GetUser() if user == "" { return nil, fmt.Errorf("no user configured: run 'ax user set ' first") } st, err := store.FindAndOpenSQLiteStore() if err != nil { return nil, err } return &nodeServiceImpl{store: st, userID: user}, nil }