Summary
Add an API-backed comment system to case and simulation detail pages so signed-in users can discuss records in-context. V1 should support top-level comments plus one level of replies, optional section anchors, author attribution from existing /users/me auth, and soft deletion/edit history without changing existing case/simulation list payloads.
Is your feature request related to a problem?
Case and simulation pages currently have no persistent collaboration layer. The simulation detail view includes a temporary local-only comment stub, and case pages have no discussion surface at all. Users cannot leave durable context, ask follow-up questions, or capture review notes tied to a specific case/simulation section.
Describe the solution you'd like
Backend
- Add a new
comments feature with a single Comment model using existing IDMixin and TimestampMixin.
- Use one table with nullable
case_id and simulation_id, plus a DB check constraint that exactly one is set.
- Fields:
id, body, case_id, simulation_id, parent_comment_id, anchor_key, created_by, last_updated_by, edited_at, deleted_at, created_at, updated_at.
- Keep replies in the same table; enforce max depth 1 by rejecting replies to replies.
- Store comment body as plain text with preserved newlines in v1. Do not add markdown/rich-text rendering yet.
- Use soft delete for all comments. Deleted comments stay in-place as tombstones so reply threads remain intact.
- Reuse
UserPreview for author info in responses.
API / interface changes
- Add
POST /cases/{case_id}/comments and GET /cases/{case_id}/comments.
- Add
POST /simulations/{sim_id}/comments and GET /simulations/{sim_id}/comments.
- Add
PATCH /comments/{comment_id} and DELETE /comments/{comment_id}.
POST accepts { body, anchorKey?, parentCommentId? }.
PATCH accepts { body }.
GET returns top-level comments with embedded replies, author preview, timestamps, editedAt, deletedAt, anchorKey, and parentCommentId.
- Keep existing
CaseOut and SimulationOut unchanged; comments load separately on detail pages to avoid bloating existing responses.
Rules and behavior
- Any signed-in user can create top-level comments and replies.
- Authors can edit/delete their own comments. Admins can delete any comment for moderation; non-authors cannot edit others’ comments.
- Replies inherit the parent resource and anchor; server rejects mismatched resource IDs or nested reply depth > 1.
anchor_key is optional and frontend-controlled, not hard-enforced as a backend enum. Use stable keys such as case-metadata, reference-simulation, simulation-list, simulation-summary, outputs-logs, notes.
- Sort root comments oldest-first within each anchor group; sort replies oldest-first.
Frontend
- Add a new
frontend/src/features/comments/ module with API helpers, hooks, and a shared CommentsPanel.
- Replace the temporary local-only comments block in the simulation detail view with the shared panel.
- Add the same panel to the case detail page.
- Support: list threads, create comment, reply, edit own comment, delete own comment, read-only empty state for signed-out users, and anchor badge/filter UI.
- Keep mutation handling simple and deterministic: submit, refetch thread list, show toast; no optimistic updates in v1.
Describe alternatives you've considered
resource_type/resource_id polymorphism was rejected because it loses DB-level foreign keys.
- Separate
case_comments and simulation_comments tables were rejected because they duplicate nearly identical logic.
- Inline text-range comments were rejected for v1 because they require DOM anchoring, selection persistence, and brittle reattachment when layouts change.
- Mentions, notifications, reactions, and rich-text/markdown rendering are deferred until basic threaded discussion proves useful.
Test cases and scenarios
- Backend pytest coverage for create/list/edit/delete on both cases and simulations.
- Validate DB/resource rules: exactly one parent target, reply depth limited to 1, replies cannot switch resource/anchor.
- Permission tests: signed-out write rejected, author edit/delete allowed, non-author edit rejected, admin delete allowed.
- Soft-delete tests: deleted comments remain in thread with tombstone state and preserved replies.
- API serialization tests for nested replies and
UserPreview.
- Frontend verification via
make frontend-lint, frontend type-check, and manual smoke on case/simulation detail pages because no frontend test runner is currently configured.
Additional context
- Implement this as a new feature module rather than extending
notes_markdown; notes are record metadata, comments are multi-user discussion.
- Reuse existing auth/session behavior and
/users/me identity for composer state and author attribution.
- No notifications, email, activity feed, or cross-page comment counts in v1.
Assumptions and defaults
- V1 targets page discussion with optional section anchors, not inline text selection.
- Comment threads are one level deep only.
- Comments are visible anywhere the underlying case/simulation is visible.
- Plain-text bodies with newline preservation are sufficient for v1.
- Existing case/simulation detail endpoints remain backward-compatible.
Summary
Add an API-backed comment system to case and simulation detail pages so signed-in users can discuss records in-context. V1 should support top-level comments plus one level of replies, optional section anchors, author attribution from existing
/users/meauth, and soft deletion/edit history without changing existing case/simulation list payloads.Is your feature request related to a problem?
Case and simulation pages currently have no persistent collaboration layer. The simulation detail view includes a temporary local-only comment stub, and case pages have no discussion surface at all. Users cannot leave durable context, ask follow-up questions, or capture review notes tied to a specific case/simulation section.
Describe the solution you'd like
Backend
commentsfeature with a singleCommentmodel using existingIDMixinandTimestampMixin.case_idandsimulation_id, plus a DB check constraint that exactly one is set.id,body,case_id,simulation_id,parent_comment_id,anchor_key,created_by,last_updated_by,edited_at,deleted_at,created_at,updated_at.UserPreviewfor author info in responses.API / interface changes
POST /cases/{case_id}/commentsandGET /cases/{case_id}/comments.POST /simulations/{sim_id}/commentsandGET /simulations/{sim_id}/comments.PATCH /comments/{comment_id}andDELETE /comments/{comment_id}.POSTaccepts{ body, anchorKey?, parentCommentId? }.PATCHaccepts{ body }.GETreturns top-level comments with embeddedreplies, author preview, timestamps,editedAt,deletedAt,anchorKey, andparentCommentId.CaseOutandSimulationOutunchanged; comments load separately on detail pages to avoid bloating existing responses.Rules and behavior
anchor_keyis optional and frontend-controlled, not hard-enforced as a backend enum. Use stable keys such ascase-metadata,reference-simulation,simulation-list,simulation-summary,outputs-logs,notes.Frontend
frontend/src/features/comments/module with API helpers, hooks, and a sharedCommentsPanel.Describe alternatives you've considered
resource_type/resource_idpolymorphism was rejected because it loses DB-level foreign keys.case_commentsandsimulation_commentstables were rejected because they duplicate nearly identical logic.Test cases and scenarios
UserPreview.make frontend-lint, frontend type-check, and manual smoke on case/simulation detail pages because no frontend test runner is currently configured.Additional context
notes_markdown; notes are record metadata, comments are multi-user discussion./users/meidentity for composer state and author attribution.Assumptions and defaults