You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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"
Touched by any mutation: add / edit body / reorder / change relevance / change immediacy
Title fallback chain (single FE helper coachingSessionTitle(coachingSession))
coachingSession.title if present →
else first linked goal's title (today's behavior) →
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.
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 linkedgoal 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
Non-goals
Agreement. No change to Agreements.Domain model & naming
coaching_sessionsOption<String>(BE) /Option<string>(FE). Not a new entity.coaching_session_topicsentity, FK → coaching sessioncoaching_session_topicsidcoaching_session_iduser_idbodydisplay_orderrelevanceNeutralNeutral(unset) +Background / Worth exploring / Central(labels TBD)immediacyNeutralNeutral(unset) +Can wait / Soon / Pressing(labels TBD)created_atupdated_atTitle fallback chain (single FE helper
coachingSessionTitle(coachingSession))coachingSession.titleif present →"Coaching Session"(existing default).Topic ordering & wire contract
display_orderindex.It is backend-internal — never read, computed, or sent by the FE.
(
GET /coaching_sessions/{id}/topicsand theCoachingSessionInclude::Topicsinclude)must return topics already sorted in canonical order; the FE relies on array order and
never sorts client-side. The FE
CoachingSessionTopictype does not includedisplay_order.dedicated reorder endpoint; the backend reassigns order from that array. No per-item order
values cross the wire in either direction.
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).
optimistic concurrency can be added later if needed.
Permissions / authz (BE — follow extractor pattern, refactor-group/refactor-platform-rs#218)
/coaching_sessions/{id}/topics*routes gated by the existingCoachingSessionAccessextractor.[Assumption — flag if you want coach-only.]
CoachingSessionTopicAuthorAccessextractor(or
CoachingSessionAccess+ a domain ownership assertion), per [Feature]: Reference blocks of content in a session from previous sessions #218.Roadmap
from existing fields;
Neutraltopics in an "untriaged" bucket); coach-side immediacy signalto surface coach↔coachee gaps as coaching material.
Topics → coaching notes → coaching session transcription (post-completion only). Suggestion
only; never overrides a human Title; sits above the goal fallback when accepted.
Definition of Done (epic-level)
Option<string>; topics returnedpre-sorted; non-null topic enums with
Neutraldefault).Linked issues