Plan: CreatorTrack Workstream A, generic task primitives (dev-capable without a dev mode)¶
URL: https://mkdocs.justinsforge.com/memory/plans/creatortrack-task-dev-primitives-2026-07-11/
Date: 2026-07-11
Branch / slot: feat/task-dev-primitives, worktree /home/justinwieb/forge-suite-wt/feat/task-dev-primitives, dev server http://100.97.43.104:3062, DB ct_feat_task_dev_primitives (own clone). Off main b67e7ca.
Design authority: handoff Workstream A (read its Workstream A section, it is the approved design). This plan is the execution breakdown.
North Star (governs every choice): CreatorTrack becomes a real project/dev tracker WITHOUT ever looking like one. Every primitive must make obvious sense for a content creator too. NEVER build a "dev mode", a "software" label, or a dev-only preset. Same code, same UI, configured differently by the user. If a choice would read as "this is for programmers", reframe it generically.
Out of scope: anything in Workstreams B (done), C, D, E. No merge to main, no deploy. This is an isolated worktree build.
Critical constraints (CT dev gotchas, do not trip on these)¶
- Commit after EVERY task with a conventional message. The dev-slot reaper deletes idle/over-cap worktrees and eats UNCOMMITTED work (there are already 5 live slots vs a cap of 4). Committed work is safe on the branch. Never leave a finished piece uncommitted.
- Dev server is already running on :3062 via
next dev --webpack(turbopack symlink-breaks in a worktree, webpack is required, do not switch). Do NOT start another server. If types look stale, the fix is a stale.nextdev cache, not a code change. - The slot uses
WORKSPACE_DEV_AUTH=1; you are auto-logged-in as the owner over http. NEVER attempt a fresh Google login over http. - Migrations:
python3 ~/forge/scripts/forge_workspace_new_migration.py "desc"to create,PGDATABASE=ct_feat_task_dev_primitives WORKSPACE_MIGRATIONS_DIR=db/migrations python3 ~/forge/scripts/forge_workspace_migrate.pyto apply (idempotent DDL only). Apply ONLY to this slot's DB. - Verify each task with
npx tsc --noEmit(clean) AND a real check against :3062 (open the affected view, confirm the behavior). Do not report a piece done on tsc alone when it has a runtime surface. - No em dashes anywhere. Match surrounding code style.
Key existing structures (verified in handoff)¶
- A task is a row in the generic
nodestable (db/schema.ts:99,type="task"). Typed fields live incollection_props(defs) /collection_values(values) /collection_relations(links) (db/schema.ts:149-183). Logic:lib/tasks.ts. Default props seeded inlib/system-apps.ts(~line 253). - Board:
components/apps/shared/KanbanBoard.tsx->components/apps/projects/ProjectBoardView.tsx, groups by Status only today. - Relations are hardwired self-only (
blockedBy,parentTask). - Note-to-task:
components/apps/tasks/ConvertToTaskModal.tsx. CleanTaskshape:lib/tasks.ts:21-74.
Task list (dependency/leverage order; commit each)¶
Task 1: Generalize the board group-by to any select/status field¶
- Files:
components/apps/shared/KanbanBoard.tsx,components/apps/projects/ProjectBoardView.tsx, the tasks board view wiring. - What: Board groups by Status only today. Generalize so the board can group by ANY select-or-status field (Status, Priority, Type, Milestone, or any user select prop). Add a group-by picker in the board header. Drag between columns writes the value of the grouped field (for Status keep current behavior; for a generic select, set that prop's value). This single change IS "milestones", "swimlanes", and creator campaign-columns at once. Ungrouped/null values get a "No
" column. - Verification:
npx tsc --noEmit; on :3062 open a workspace's tasks board, switch group-by to Priority, drag a card between columns, confirm the priority actually changes and persists on reload. - Commit:
feat(tasks): board group-by any select/status field
Task 2: Seed default Type and Milestone select fields (generic, no dev label)¶
- Files:
lib/system-apps.ts(default-prop seed ~253),lib/tasks.tsif CleanTask needs the field surfaced. - What: Add two default select props to the tasks collection: Type and Milestone, both EMPTY-optioned by default (user adds their own options; a dev types bug/feature/chore, a creator types Reel/Long-form/Sponsored). No preset dev options, no label implying software. They become immediately usable as board group-by fields (Task 1). Ensure existing workspaces get them via the seed/backfill path the app already uses for default props (match how Status/Priority/Tags are seeded, idempotent).
- Verification:
npx tsc --noEmit; on :3062 open a task, confirm Type + Milestone fields appear and are editable; confirm the board group-by picker (Task 1) now lists them. - Commit:
feat(tasks): default Type and Milestone select fields
Task 3: External-URL field type (link prop kind)¶
- Files:
db/schema.ts(if a new prop kind enum value is needed),lib/tasks.ts, the collection prop UI + the task field render components. - What: Add an external-URL prop kind: stores a URL string, renders as a clickable link (opens new tab, safe rel). Dev links a PR/commit; a creator links a published video/Drive asset/deal. Add it as an addable prop kind (not a forced default). Validate/normalize the URL (require http(s) or coerce).
- Verification:
npx tsc --noEmit; on :3062 add a URL field to a task, paste a link, confirm it renders as a working external link. - Commit:
feat(tasks): external-URL field type
Task 4: Task -> page (node-to-node) relation¶
- Files:
db/schema.ts(collection_relations),lib/tasks.ts, the relation-field UI. - What: Relations are hardwired self-only (
blockedBy/parentTask). Generalizecollection_relationsso a task can relate to atype="page"(or other node type) node, not only another task. Add a relation-field UI to link a task to a page/doc (a picker that searches nodes). Dev links an issue to its spec page; a creator links a task to a script/brand doc. Reuse the existing self-relation machinery; un-hardwire the target type. - Verification:
npx tsc --noEmit; on :3062 create a page, then from a task add a relation to that page, confirm the link resolves both directions. - Commit:
feat(tasks): task-to-page node relation
Task 5: Bulk paste -> tasks¶
- Files:
components/apps/tasks/ConvertToTaskModal.tsx(extend) or a new paste handler in the tasks views. - What: Paste a newline-separated list; each non-empty line becomes a task node in the current list/project/workspace. Dev pastes a bug list; a creator pastes a content-idea dump. Trim blank lines; respect the active workspace/list. Idempotent per-invocation (no double-create on a single paste).
- Verification:
npx tsc --noEmit; on :3062 paste a 3-line list into the tasks view, confirm exactly 3 tasks are created with those titles. - Commit:
feat(tasks): bulk paste to tasks
Task 6: Dated timeline / gantt view (net-new)¶
- Files: new view component under
components/apps/tasks/(orcomponents/apps/shared/), register it in the tasks view switcher alongside list/board/matrix/database/search. - What: A timeline/gantt view: tasks laid out as dated bars across a horizontal time axis using
start+due/dueEnd(from CleanTask). Draw dependency links from the existingblockedByrelation. Group rows by any select field (reuse Task 1's group-by), so a dev sees a release timeline and a creator sees a content calendar timeline, same view. Support drag to reschedule (updates start/due) if feasible; if drag is too big for this pass, ship read-only bars + a note, and commit that, then add drag as a follow-up commit. Framed generically (call it "Timeline", not "Gantt/Sprint"). - Verification:
npx tsc --noEmit; on :3062 add a Timeline view to the tasks app, give two tasks dates and a blockedBy link, confirm the bars render on the axis and the dependency draws. - Commit:
feat(tasks): timeline view with dated bars and dependencies(+ a follow-up commit if drag-reschedule lands separately)
Task 7: Register and document¶
- Files:
/home/justinwieb/forge/memory/general/reference_creatortrack_task_primitives.md(new, mkdocs URL line, status BUILT-on-branch-not-deployed),/home/justinwieb/forge/MEMORY.mdindex line under CreatorTrack. - What: Document the new primitives, the "no dev-mode label" framing, files touched, and that Timeline is the gantt. Note merge-day: this touches db/schema + migrations, so prod needs the migration applied on merge.
- Verification: the reference file has the URL line; MEMORY.md line resolves.
- Commit:
docs(memory): creatortrack task primitives reference(forge repo, separate from the worktree)
Reporting¶
Write a running report to /home/justinwieb/forge/comms/results/creatortrack-task-dev-primitives.md after each task (task, commit hash, verification result). When all done, report: branch name, per-task commits, what to review, and anything that had to ship partial (e.g. timeline drag deferred).