From 8c36b399d003dc61695eb918c3b3461bf88ed177 Mon Sep 17 00:00:00 2001 From: cottongin Date: Sun, 22 Mar 2026 23:33:36 -0400 Subject: [PATCH] docs: add session notes read/edit/delete design spec Made-with: Cursor --- ...2-session-notes-read-edit-delete-design.md | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-22-session-notes-read-edit-delete-design.md diff --git a/docs/superpowers/specs/2026-03-22-session-notes-read-edit-delete-design.md b/docs/superpowers/specs/2026-03-22-session-notes-read-edit-delete-design.md new file mode 100644 index 0000000..6052ef2 --- /dev/null +++ b/docs/superpowers/specs/2026-03-22-session-notes-read-edit-delete-design.md @@ -0,0 +1,169 @@ +# Session Notes — Read, Edit, Delete + +**Date:** 2026-03-22 +**Status:** Approved + +## Problem + +When an admin/host ends a session, they can write notes via the EndSessionModal. But after that, those notes are effectively invisible — the History page doesn't display them, and there's no way to read, edit, or delete them from the UI. Notes only surface in raw exports. + +## Solution + +Add the ability to view, edit, and delete session notes through two surfaces: + +1. **Notes preview on History page session cards** — inline teaser showing the first paragraph +2. **New Session Detail page** (`/history/:id`) — full rendered markdown notes with inline edit/delete, plus session management actions + +## Approach + +Minimal extension of existing infrastructure (Approach A). No database schema changes. The `sessions.notes` TEXT column stays as-is. Frontend gets a new page and a markdown rendering dependency. + +## Backend API Changes + +### New Endpoints + +#### `PUT /api/sessions/:id/notes` + +- **Auth:** Required (admin token) +- **Body:** `{ "notes": "markdown string" }` +- **Behavior:** Overwrites `sessions.notes` for the given session (no COALESCE merge — full replacement) +- **Response:** Updated session object +- **Errors:** 404 if session not found, 401 if unauthenticated + +#### `DELETE /api/sessions/:id/notes` + +- **Auth:** Required (admin token) +- **Body:** None +- **Behavior:** Sets `sessions.notes = NULL` +- **Response:** `{ success: true }` +- **Errors:** 404 if session not found, 401 if unauthenticated + +### Modified Endpoints + +#### `GET /api/sessions` (list) + +Add two fields to each session object in the response: + +- `has_notes` (boolean) — `true` if `notes IS NOT NULL AND notes != ''` +- `notes_preview` (string | null) — first paragraph of the markdown, truncated to ~150 characters. `null` if no notes. + +These are computed server-side from the existing `notes` column. + +#### `GET /api/sessions/:id` (single session) + +Conditional notes visibility based on auth: + +- **Authenticated request:** Returns full `notes` field (plus `has_notes` and `notes_preview`) +- **Unauthenticated request:** Returns `notes_preview` and `has_notes` only. `notes` field is omitted or null. + +The endpoint currently does not require auth. It will remain publicly accessible but gate the full notes content behind an optional auth check. + +### Unchanged Endpoints + +- `POST /api/sessions` — session creation (unchanged) +- `POST /api/sessions/:id/close` — session close with optional notes (unchanged) +- `DELETE /api/sessions/:id` — session deletion (unchanged) + +## Frontend Changes + +### History Page (`/history` — `History.jsx`) + +#### Session Cards (Sidebar) + +- Add notes preview teaser below the date/games-count line when `has_notes` is true +- Visual treatment: indigo left-border accent, subtle background, truncated text with ellipsis +- Clicking a session card navigates to `/history/:id` (instead of expanding the inline detail panel) + +#### Action Buttons + +- **Active sessions:** "End Session" button stays on the card (opens `EndSessionModal` as before) +- **Closed sessions:** Delete button removed from the card (moved to detail page only) + +#### Removed from History Page + +- The inline session detail panel (right side, `md:col-span-2`) is replaced by navigation to the detail page +- `ChatImportPanel` moves to the detail page +- Export buttons move to the detail page + +### New Session Detail Page (`/history/:id` — `SessionDetail.jsx`) + +New route and component. + +#### Layout + +- **Back link** — "← Back to History" navigates to `/history` +- **Session header** — Session number, created date/time, games count, active badge if applicable +- **Notes section** — Primary content area (see Notes Section below) +- **Games list** — Same as current History detail panel (reuse existing game card markup) +- **Action buttons:** + - Export as TXT / Export as JSON (same as current) + - Import Chat Log (active sessions only, admin only) + - End Session (active sessions only, admin only — opens `EndSessionModal`) + - Delete Session (closed sessions only, admin only — confirmation modal) + +#### Notes Section — View Mode + +- Renders notes as formatted HTML via `react-markdown` +- If no notes exist: shows "No notes" placeholder with "Add Notes" button (admin only) +- Admin sees an "Edit" button in the section header + +#### Notes Section — Edit Mode (Admin Only) + +- Triggered by clicking "Edit" (or "Add Notes" for empty notes) +- Rendered markdown is replaced in-place by a textarea containing the raw markdown +- "Supports Markdown formatting" hint below the textarea +- Action buttons: **Save** (green), **Cancel** (gray), **Delete Notes** (red, with confirmation) +- Save calls `PUT /api/sessions/:id/notes` +- Delete Notes calls `DELETE /api/sessions/:id/notes` after a confirmation prompt +- Cancel reverts to view mode without saving + +#### Notes Section — Public View (Unauthenticated) + +- Shows `notes_preview` text (first paragraph, plain text — not markdown-rendered) +- "Log in to view full notes" hint below the preview +- No edit controls + +### Routing + +Add new route in `App.jsx`: + +``` +/history/:id → +``` + +Existing `/history` route unchanged. + +### New Dependency + +- `react-markdown` — lightweight markdown-to-React renderer. Used only in `SessionDetail.jsx` for rendering notes. + +## What's NOT Changing + +- **Database schema** — no migration, no new tables, no new columns +- **`EndSessionModal`** — still works as-is for writing notes at session close time +- **`POST /api/sessions/:id/close`** — untouched +- **WebSocket events** — no notes-related real-time updates +- **Home page** — still shows `activeSession.notes` as plain text for active sessions (no changes) + +## Permission Model + +| Action | Auth Required | +|--------|--------------| +| View notes preview (list + detail) | No | +| View full notes (detail page) | Yes | +| Edit notes | Yes | +| Delete notes | Yes | +| Delete session | Yes | +| End session | Yes | + +This is consistent with the existing pattern where read-only session data is public and mutations require admin auth. + +## Notes Preview Computation + +Server-side logic for `notes_preview`: + +1. If `notes` is null or empty, `notes_preview = null`, `has_notes = false` +2. Split `notes` on the first double-newline (`\n\n`) to get the first paragraph +3. Strip markdown formatting (bold, links, etc.) for a clean plain-text preview +4. Truncate to 150 characters, append `...` if truncated +5. Return as `notes_preview` string