Files
resolutionflow/docs/plans/archive/2026-03-11-session-closure-design.md
Michael Chihlas cbb4b25671
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
CI / frontend (pull_request) Successful in 6m42s
CI / e2e (pull_request) Successful in 10m11s
CI / backend (pull_request) Successful in 10m43s
fix(ui): drop setState-in-effect in useAuthSessionExpiry
CI surfaced react-hooks/set-state-in-effect on the synchronous
setState(computeState(token)) inside the useEffect body. The earlier
shape mirrored token -> state via an effect, which is exactly the
"you might not need an effect" pattern React 19's eslint rule now
flags.

Switch to derived state: compute during render, use a useReducer
tick to force re-render on the 30s cadence (so relative timestamps
stay current even when token props don't change). Same observable
behavior, no cascading renders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 20:15:11 -04:00

2.4 KiB

Session Closure from History Page — Design

Date: 2026-03-11

Problem

Active sessions on the Session History page only have "View Details" and "Resume" buttons. Engineers have no way to close out sessions that were abandoned, resolved externally, or otherwise no longer needed — without resuming the entire flow.

Design Decisions

  • Outcome model: Hybrid — reuse existing 4 outcomes (resolved, escalated, workaround, unresolved) + add 2 early-closure outcomes (cancelled, resolved_externally)
  • UX: Inline popover anchored to a "Close" button on the session card — no modal, no slide panel
  • Scope: Active sessions only (started but not completed). No bulk close. No AI summary generation.
  • Backend: No new endpoints or migrations. Expand SessionOutcome literal type; existing POST /sessions/{id}/complete handles everything.

Data Model

No new columns. Expand SessionOutcome in backend/app/schemas/session.py:

SessionOutcome = Literal["resolved", "escalated", "workaround", "unresolved", "cancelled", "resolved_externally"]

VARCHAR(20) on session.outcome fits both new values (max 19 chars for resolved_externally).

UI

Close Button

Appears on active session cards (started_at is set, completed_at is null), between "View Details" and "Resume":

[View Details]  [Close]  [Resume]

Secondary button styling (border, muted text). Not shown on prepared or completed sessions.

Close Popover

Anchored below the "Close" button:

  • Outcome selector: <select> with 6 options — Resolved, Escalated, Workaround, Unresolved, Cancelled, Resolved Externally
  • Notes: Optional textarea (2 rows)
  • Confirm: bg-gradient-brand, disabled until outcome selected
  • Cancel / click outside: Closes popover
  • Glass card styling (glass-card-static pattern)

On confirm: calls POST /sessions/{id}/complete with { outcome, outcome_notes }, updates local state, shows toast.

Implementation Scope

Backend (2 files)

  1. backend/app/schemas/session.py — add new outcome values to SessionOutcome
  2. Update frontend outcome type to match

Frontend (2-3 files)

  1. frontend/src/types/ — update SessionOutcome TypeScript type
  2. frontend/src/pages/SessionHistoryPage.tsx — add Close button, popover, outcome label formatting for new values

No new components, endpoints, or migrations.