Adds the first-class task layer the Phase 7 design (docs/plans/phase-7-entity-model.md) calls for, on the mBrian backend: - store.Task: one uniform view-shape, two sources (CalDAV VTODO | mBrian type=['task'] node); TaskReader/TaskWriter capability interfaces (separate from ItemReader/ItemWriter — only the mBrian backend has task nodes). - MBrianReader.TasksForItem: materialises type=['task'] child_of nodes into Task, created-at order (Q5). - Task exclusion at the reader chokepoint: nodeIsTask filters tasks out of ListAll/Roots/MaiOrphans/Search/AllTags, so they never leak into ANY project surface (tree/graph/dashboard/calendar/timeline + MCP list/tree, which all funnel through ListAll/ListByFilters) — implements Q6's intent in one place instead of per-surface. GetByID/GetByPath still resolve a task node. - MBrianWriter task writes: CreateTask (POST type:'task' + slug + child_of edge), SetTaskStatus (done=status, Q2), SetTaskDue, EditTaskTitle, DeleteTask. Uses the now-live POST /api/projax/nodes 'type' field. - Item.Render (metadata.projax.render) + RendersChecklist() for compact checklist mode (Q1); round-tripped via UpdateInput.Render. Unit-tested: nodeIsTask, taskFromNode, dueToJSON, RendersChecklist. Pre-existing TestParityListAll drift (store=65 vs mbrian=66) is unrelated and tracked separately by head.
92 lines
3.9 KiB
Go
92 lines
3.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
// Phase 7 — Task is the uniform view-shape for a unit of work attached to a
|
|
// projax item, materialised from EITHER a CalDAV VTODO or an mBrian
|
|
// type=['task'] node. One shape, two sources; writes dispatch on Source
|
|
// (design §3.3, the slice-B "one Item shape, two backends" pattern applied
|
|
// to tasks). Consumers (the detail Tasks section, future dashboard/timeline
|
|
// rollups) render the uniform shape and don't care which backend produced it.
|
|
type Task struct {
|
|
// ID is a stable per-source identifier: the mBrian node uuid for an
|
|
// mBrian-native task, the VTODO UID for a CalDAV task. Unique within a
|
|
// source; templates key rows on it.
|
|
ID string
|
|
Title string
|
|
Done bool
|
|
Due *time.Time
|
|
// Source is "mbrian" or "caldav" — write handlers dispatch on it.
|
|
Source string
|
|
// Status is the raw lifecycle status for mBrian tasks (active|done|
|
|
// archived). For CalDAV tasks it carries the VTODO STATUS verbatim
|
|
// (NEEDS-ACTION|IN-PROCESS|COMPLETED|CANCELLED) for callers that want it;
|
|
// Done is the normalised boolean either way.
|
|
Status string
|
|
// ParentItemID is the projax item this task hangs under.
|
|
ParentItemID string
|
|
CreatedAt time.Time
|
|
|
|
// --- mBrian-source handle (Source == TaskSourceMBrian) ---
|
|
// NodeID is the mBrian node uuid (== ID); the write API targets it.
|
|
NodeID string
|
|
Slug string
|
|
|
|
// --- CalDAV-source handle (Source == TaskSourceCalDAV) ---
|
|
// CalendarURL + UID address the VTODO for ETag-guarded writeback via the
|
|
// existing caldav write path.
|
|
CalendarURL string
|
|
UID string
|
|
}
|
|
|
|
// Task source discriminators.
|
|
const (
|
|
TaskSourceMBrian = "mbrian"
|
|
TaskSourceCalDAV = "caldav"
|
|
)
|
|
|
|
// TaskCreateInput captures the editable surface of a new mBrian-native task.
|
|
// CalDAV tasks are created through the existing CalDAV write path (VTODO PUT),
|
|
// not this shape — only the mBrian backend creates task nodes.
|
|
type TaskCreateInput struct {
|
|
Title string
|
|
Slug string
|
|
ParentItemID string // the project (or task) this task attaches to via child_of
|
|
Due *time.Time // optional
|
|
}
|
|
|
|
// TaskReader is the read-path contract for mBrian-native task nodes. It is a
|
|
// capability SEPARATE from ItemReader: only the mBrian backend has task nodes,
|
|
// so the legacy *Store does not implement it. Web handlers obtain it via a
|
|
// type-assertion on the active Items backend (see Server.taskBackend).
|
|
type TaskReader interface {
|
|
// TasksForItem returns the mBrian-native tasks (type=['task'] nodes)
|
|
// attached to itemID via a child_of edge, in created-at order (Q5 —
|
|
// created order only; no manual reorder in v1).
|
|
TasksForItem(ctx context.Context, itemID string) ([]*Task, error)
|
|
}
|
|
|
|
// TaskWriter is the write-path contract for mBrian-native task nodes. Twin of
|
|
// TaskReader; implemented only by the mBrian backend (*MBrianWriter). Writes
|
|
// funnel through mBrian's scoped /api/projax HTTP surface so projax-created
|
|
// task nodes are byte-identical to UI/MCP/migration nodes (the slice-C
|
|
// discipline). Delete reuses the node soft-delete the API already exposes.
|
|
type TaskWriter interface {
|
|
// CreateTask POSTs a type=['task'] node (slug honored, metadata.projax
|
|
// carrying status/due) then attaches it to ParentItemID via a child_of
|
|
// edge, and returns the materialised Task.
|
|
CreateTask(ctx context.Context, in TaskCreateInput) (*Task, error)
|
|
// SetTaskStatus PATCHes metadata.projax.status (done|active|archived) —
|
|
// task done-state reuses the existing lifecycle (Q2), no separate field.
|
|
SetTaskStatus(ctx context.Context, nodeID, status string) error
|
|
// SetTaskDue PATCHes metadata.projax.due; a nil due clears it.
|
|
SetTaskDue(ctx context.Context, nodeID string, due *time.Time) error
|
|
// EditTaskTitle PATCHes the node title.
|
|
EditTaskTitle(ctx context.Context, nodeID, title string) error
|
|
// DeleteTask soft-deletes the task node.
|
|
DeleteTask(ctx context.Context, nodeID string) error
|
|
}
|