Skip to content

Epic: Coaching Session Title + Topics of Focus #412

Description

@jhodapp

Summary

Add an optional, human-authored Title to a coaching session and a collaborative,
reorderable set of Topics that either party can contribute. The Title replaces the
current practice of borrowing the first linked goal's title as the coaching session's
display name (the goal remains a fallback). Topics can later be triaged by the coachee
along two axes — relevance and immediacy — and visualized as a priority matrix.

Problem

A coaching session has no name of its own. Everywhere we label one (the coaching-session
switcher, selector, cards) we render goalsTitle(coachingSession.goals) — the first linked
goal stands in as the title. That conflates a long-term goal with "what this coaching
session is about," and breaks down when no goal is linked.

Goals

  • One optional, human-authored Title per coaching session.
  • A collaborative, reorderable list of Topics contributed by coach or coachee.
  • Preserve today's behavior via a fallback chain so nothing regresses when Title is unset.

Non-goals

  • Topics are not goals (long-term, cross-session outcomes — own entity + join table).
  • Topics are not the per-coaching-session Agreement. No change to Agreements.

Domain model & naming

Concept Cardinality Shape Notes
Title 0..1 Nullable field on coaching_sessions Option<String> (BE) / Option<string> (FE). Not a new entity.
Topic 0..N New coaching_session_topics entity, FK → coaching session Per-row author + timestamps; rows (not a JSON column) so concurrent edits don't clobber and delete stays author-scoped.

coaching_session_topics

Field Type Notes
id Id (uuid)
coaching_session_id Id (FK)
user_id Id (FK) Author (coach or coachee)
body text The topic text
display_order int Backend-internal — see "Topic ordering & wire contract"
relevance enum, NOT NULL, default Neutral Coachee-set. Neutral (unset) + Background / Worth exploring / Central (labels TBD)
immediacy enum, NOT NULL, default Neutral Coachee-set. Neutral (unset) + Can wait / Soon / Pressing (labels TBD)
created_at timestamptz
updated_at timestamptz Touched by any mutation: add / edit body / reorder / change relevance / change immediacy

Title fallback chain (single FE helper coachingSessionTitle(coachingSession))

  1. coachingSession.title if present →
  2. else first linked goal's title (today's behavior) →
  3. else "Coaching Session" (existing default).

Topic ordering & wire contract

  • Topic order is author-controlled and persisted via the internal display_order index.
    It is backend-internal — never read, computed, or sent by the FE.
  • The wire contract is array order, not the index. Every read path
    (GET /coaching_sessions/{id}/topics and the CoachingSessionInclude::Topics include)
    must return topics already sorted in canonical order; the FE relies on array order and
    never sorts client-side. The FE CoachingSessionTopic type does not include display_order.
  • Reorder is a whole-list operation: the FE sends the full ordered list of topic ids to a
    dedicated reorder endpoint; the backend reassigns order from that array. No per-item order
    values cross the wire in either direction.
  • New topics append to the end; deletes may leave gaps (harmless — only relative order
    matters, and the next reorder normalizes). A reorder request whose id set doesn't match the
    coaching session's current topics is rejected (guards against stale clients corrupting order).
  • Concurrent reorders are last-write-wins for now — acceptable for a small shared list;
    optimistic concurrency can be added later if needed.

Permissions / authz (BE — follow extractor pattern, refactor-group/refactor-platform-rs#218)

  • All /coaching_sessions/{id}/topics* routes gated by the existing CoachingSessionAccess extractor.
  • Title editable by either party in the relationship (last-write-wins).
    [Assumption — flag if you want coach-only.]
  • Topic add / edit / reorder: any party in the relationship (reorder organizes a shared list).
  • Topic delete: author only — new CoachingSessionTopicAuthorAccess extractor
    (or CoachingSessionAccess + a domain ownership assertion), per [Feature]: Reference blocks of content in a session from previous sessions #218.
  • Rating writes: caller must be the coachee of the relationship.

Roadmap

Definition of Done (epic-level)

Linked issues

Metadata

Metadata

Assignees

Labels

feature workSpecifically implementing a new feature

Projects

Status
🏗 In progress

Relationships

None yet

Development

No branches or pull requests

Issue actions