mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 14:30:13 +00:00
f5a00d5b13
* feat: a collection can be reference material, not work (PLAN-3535 PR 1) The switch, with no counting change yet (PR 2 server, PR 3 web). CollectionSettings.tracks_work: false makes a collection REFERENCE material; absent means work, today's behaviour, so old rows, old writers and a client/server skew are unchanged. One Go predicate (models.CollectionTracksWork) and one TS twin (collectionTracksWork). - New collections: the creator's value, else system collections are reference and others are work iff their done field can finish. New template Docs collections are created as reference (Dave). - Migration 135 / PG 107: existing Conventions and Playbooks become reference; everything else, Docs included, stays work. - Settings are written wholesale, so an update whose settings omit the key KEEPS the stored value (CarryTracksWork), for every writer. - A typed top-level `tracks_work` on POST/PATCH sets just that key server-side. CLI: --tracks-work=true|false (a string flag, so false survives stdio MCP). MCP: pad_collection tracks_work, v0.81. A non-boolean is refused 400; the CLI checks the response, since an older server ignores the member. - Web: the Display tab's "Track as work" toggle; the editor now starts its settings write from the STORED settings (buildCollectionSettings), so keys it does not render (content_template, tracks_work) survive. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): carry tracks_work from the locked row; order the SQLite migration's JSON checks (PLAN-3535, codex) The update now computes the carried settings from the row it re-read under the write lock, so a concurrent settings write cannot be reverted by a carry read before the lock. The SQLite migration evaluates json_type/json_extract only inside a CASE guarded by json_valid, so malformed settings on a system row cannot abort it. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(models): a collection whose options the default terminals close is work (PLAN-3535) DefaultTracksWork required declared terminal_options, but every lifecycle reader falls back to DefaultTerminalStatuses when a done field declares none, so a `status: open, done` collection finishes items and was being created as reference. Work now means one of the done field's options is terminal by the same resolver the readers use. Found by PR 2's store tests, whose fixture collection is exactly that shape. Also corrects api.md's MCP version (0.81). Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
126 lines
4.5 KiB
Go
126 lines
4.5 KiB
Go
package collections
|
|
|
|
import "github.com/PerpetualSoftware/pad/internal/models"
|
|
|
|
// DefaultCollection holds the definition for a default collection that gets
|
|
// created when a workspace is initialized.
|
|
type DefaultCollection struct {
|
|
Name string
|
|
Slug string
|
|
Prefix string // Optional explicit issue-ID prefix; empty means derive from Name
|
|
Icon string
|
|
Description string
|
|
Schema models.CollectionSchema
|
|
Settings models.CollectionSettings
|
|
// Traits declares the collection's kernel traits (SPEC-5). Templates
|
|
// declare them so a NEW workspace gets them at seed time; existing
|
|
// workspaces are backfilled by migration 080 / pg 058. Between the two,
|
|
// no kernel behavior is inferred from a collection's slug any more.
|
|
// TASK-2657.
|
|
Traits models.CollectionTraits
|
|
SortOrder int
|
|
IsSystem bool // System collections (conventions, playbooks) are always visible to members
|
|
}
|
|
|
|
// Defaults returns the six default collections for a new workspace.
|
|
//
|
|
// Tasks and Ideas are extracted into tasksCollection/ideasCollection
|
|
// (templates.go, alongside docsCollection) so templates that want them
|
|
// without a Plans collection — e.g. `spec` (IDEA-2527), where
|
|
// implementation-plan material lives in the spec body instead — can compose
|
|
// the same seeded schema directly. Seeded output here is unchanged.
|
|
func Defaults() []DefaultCollection {
|
|
return []DefaultCollection{
|
|
tasksCollection(0),
|
|
ideasCollection(1),
|
|
{
|
|
Name: "Plans",
|
|
Slug: "plans",
|
|
Icon: "🗺️",
|
|
Description: "Plan and track project plans and milestones",
|
|
SortOrder: 2,
|
|
Schema: models.CollectionSchema{
|
|
Fields: []models.FieldDef{
|
|
{
|
|
Key: "status",
|
|
Label: "Status",
|
|
Type: "select",
|
|
Options: []string{"planned", "active", "completed", "paused"},
|
|
TerminalOptions: []string{"completed"},
|
|
Default: "planned",
|
|
Required: true,
|
|
},
|
|
{
|
|
Key: "start_date",
|
|
Label: "Start Date",
|
|
Type: "date",
|
|
},
|
|
{
|
|
Key: "end_date",
|
|
Label: "End Date",
|
|
Type: "date",
|
|
},
|
|
{
|
|
Key: "progress",
|
|
Label: "Progress",
|
|
Type: "number",
|
|
Suffix: "%",
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
Settings: models.CollectionSettings{
|
|
Layout: "content-primary",
|
|
DefaultView: "board",
|
|
ListSortBy: "sort_order",
|
|
QuickActions: []models.QuickAction{
|
|
{Label: "Plan this", Prompt: "/pad plan {ref} \"{title}\" — outline goals, deliverables, and timeline", Scope: "item", Icon: "📐"},
|
|
{Label: "Break into tasks", Prompt: "/pad break {ref} \"{title}\" into PR-sized tasks", Scope: "item", Icon: "📝"},
|
|
{Label: "Run a retro", Prompt: "/pad run a retrospective on {ref} \"{title}\"", Scope: "item", Icon: "🔄"},
|
|
{Label: "Compare progress", Prompt: "/pad compare progress across all plans", Scope: "collection", Icon: "📊"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Docs",
|
|
Slug: "docs",
|
|
Icon: "📄",
|
|
Description: "Documentation, notes, and reference material",
|
|
SortOrder: 3,
|
|
Schema: models.CollectionSchema{
|
|
Fields: []models.FieldDef{
|
|
{
|
|
Key: "status",
|
|
Label: "Status",
|
|
Type: "select",
|
|
Options: []string{"draft", "published", "archived"},
|
|
TerminalOptions: []string{"archived"},
|
|
Default: "draft",
|
|
Required: true,
|
|
},
|
|
{
|
|
Key: "category",
|
|
Label: "Category",
|
|
Type: "text",
|
|
},
|
|
},
|
|
},
|
|
Settings: models.CollectionSettings{
|
|
Layout: "content-primary",
|
|
DefaultView: "board",
|
|
ListSortBy: "updated_at",
|
|
ListGroupBy: "category",
|
|
TracksWork: reference(), // reference material (PLAN-3535)
|
|
QuickActions: []models.QuickAction{
|
|
{Label: "Review this doc", Prompt: "/pad review {ref} \"{title}\" for accuracy and completeness", Scope: "item", Icon: "👀"},
|
|
{Label: "Update this doc", Prompt: "/pad update {ref} \"{title}\" to reflect the current state of the codebase", Scope: "item", Icon: "✏️"},
|
|
{Label: "Summarize this", Prompt: "/pad summarize {ref} \"{title}\"", Scope: "item", Icon: "📋"},
|
|
{Label: "Find outdated docs", Prompt: "/pad review all docs and identify which are outdated", Scope: "collection", Icon: "🔍"},
|
|
},
|
|
},
|
|
},
|
|
conventionsCollection(4, SoftwareConventionTriggers, SoftwareConventionScopes),
|
|
playbooksCollection(5, SoftwarePlaybookTriggers, SoftwarePlaybookScopes),
|
|
}
|
|
}
|