feat(sessions): handoff requests and admin force-release with approval workflow #167

Open
opened 2026-03-01 15:39:21 +00:00 by forbes · 0 comments
Owner

Context

Sub-issue of #125 (Context-Aware Part Subscription System).

When a user holds an edit session and another user needs access, the system should support negotiated handoff and administrative override. These actions integrate with the existing approval workflow system.

1. Handoff Request

Endpoint

POST /api/items/{partNumber}/edit-sessions/{sessionId}/request-handoff

Auth: editor

Request:

{
  "message": "I need to fix a dimension in Sketch001, can you save and release?"
}

Server processing:

  1. Validate session exists and is held by a different user
  2. Publish edit.handoff_requested SSE event targeted to the holder's workstation
  3. Record the request (optional: store in a lightweight handoff_requests table or just fire-and-forget via SSE)

SSE event: edit.handoff_requested

{
  "item_id": "uuid",
  "part_number": "F01-0001",
  "session_id": "uuid",
  "requester": "bob",
  "message": "I need to fix a dimension in Sketch001, can you save and release?"
}

Delivered via PublishToWorkstation() to the holder's workstation.

The holder can then:

  • Save a checkpoint and release normally
  • Ignore the request (no obligation)
  • Respond (future: chat/notification integration)

2. Admin Force-Release

Endpoint

DELETE /api/items/{partNumber}/edit-sessions/{sessionId}/force-release

Auth: admin

Request:

{
  "reason": "Production emergency, need to release stuck lock"
}

Server processing:

  1. Validate session exists
  2. Force-release the session (delete from edit_sessions)
  3. Preserve the holder's in-progress work as a checkpoint (if file data available)
  4. Create an audit log entry: edit.force_released with admin, reason, original holder
  5. Publish edit.force_released SSE event to the holder's workstation
  6. Publish edit.session_released SSE event to item watchers

SSE event: edit.force_released

{
  "item_id": "uuid",
  "part_number": "F01-0001",
  "session_id": "uuid",
  "admin": "admin_user",
  "reason": "Production emergency",
  "original_holder": "alice"
}

3. Approval Workflow Integration

Force-release should optionally require an approval workflow rather than allowing any admin to unilaterally release. This integrates with the existing workflows/ YAML system.

New Workflow: session-override.yaml

workflow:
  name: session-override
  version: 1
  description: "Approval required before force-releasing an edit session"
  states: [draft, pending, approved, rejected]
  gates:
    - role: admin
      label: "Admin Authorization"
      required: true
  rules:
    any_reject: rejected
    all_required_approve: approved

Flow

When force-release requires approval:

  1. Admin submits force-release request
  2. Server creates an approval using the session-override workflow
  3. Designated approver(s) sign via existing POST /approvals/{id}/sign
  4. On approval completion (approval.completed with state: approved), the session is auto-released
  5. On rejection, the session remains held

This is optional — configurable per deployment. Simple deployments can allow direct admin force-release without approval.

Config

modules:
  sessions:
    force_release_requires_approval: false   # default: direct admin release
    force_release_workflow: "session-override" # workflow to use when approval required

4. Routes

// Under /api/items/{partNumber}/edit-sessions/{sessionID}:
r.Post("/request-handoff", server.HandleRequestHandoff)
r.Delete("/force-release", server.HandleForceRelease)  // admin only

5. Audit Trail

Both handoff requests and force-releases write to the existing audit_log table:

Action Resource Type Details
edit.handoff_requested edit_session requester, holder, message
edit.force_released edit_session admin, reason, holder, approval_id (if applicable)

Acceptance Criteria

  • POST /request-handoff sends SSE notification to holder's workstation
  • DELETE /force-release releases session (admin only)
  • Force-release creates audit log entry with reason
  • edit.handoff_requested SSE event delivered to holder
  • edit.force_released SSE event delivered to holder
  • Optional: force-release creates approval and waits for sign-off before releasing
  • Config toggle between direct and approval-gated force-release
  • session-override.yaml workflow definition included

Depends On

  • #163 (edit session endpoints)
  • #162 (SSE per-workstation delivery for targeted notifications)
  • Existing approval system (migrations 018-019, internal/api/approval_handlers.go)

Part Of

#125

## Context Sub-issue of #125 (Context-Aware Part Subscription System). When a user holds an edit session and another user needs access, the system should support negotiated handoff and administrative override. These actions integrate with the existing approval workflow system. ## 1. Handoff Request ### Endpoint ``` POST /api/items/{partNumber}/edit-sessions/{sessionId}/request-handoff ``` **Auth:** editor **Request:** ```json { "message": "I need to fix a dimension in Sketch001, can you save and release?" } ``` **Server processing:** 1. Validate session exists and is held by a different user 2. Publish `edit.handoff_requested` SSE event targeted to the holder's workstation 3. Record the request (optional: store in a lightweight `handoff_requests` table or just fire-and-forget via SSE) **SSE event:** `edit.handoff_requested` ```json { "item_id": "uuid", "part_number": "F01-0001", "session_id": "uuid", "requester": "bob", "message": "I need to fix a dimension in Sketch001, can you save and release?" } ``` Delivered via `PublishToWorkstation()` to the holder's workstation. The holder can then: - Save a checkpoint and release normally - Ignore the request (no obligation) - Respond (future: chat/notification integration) ## 2. Admin Force-Release ### Endpoint ``` DELETE /api/items/{partNumber}/edit-sessions/{sessionId}/force-release ``` **Auth:** admin **Request:** ```json { "reason": "Production emergency, need to release stuck lock" } ``` **Server processing:** 1. Validate session exists 2. Force-release the session (delete from edit_sessions) 3. **Preserve the holder's in-progress work as a checkpoint** (if file data available) 4. Create an audit log entry: `edit.force_released` with admin, reason, original holder 5. Publish `edit.force_released` SSE event to the holder's workstation 6. Publish `edit.session_released` SSE event to item watchers **SSE event:** `edit.force_released` ```json { "item_id": "uuid", "part_number": "F01-0001", "session_id": "uuid", "admin": "admin_user", "reason": "Production emergency", "original_holder": "alice" } ``` ## 3. Approval Workflow Integration Force-release should optionally require an approval workflow rather than allowing any admin to unilaterally release. This integrates with the existing `workflows/` YAML system. ### New Workflow: `session-override.yaml` ```yaml workflow: name: session-override version: 1 description: "Approval required before force-releasing an edit session" states: [draft, pending, approved, rejected] gates: - role: admin label: "Admin Authorization" required: true rules: any_reject: rejected all_required_approve: approved ``` ### Flow When `force-release` requires approval: 1. Admin submits force-release request 2. Server creates an approval using the `session-override` workflow 3. Designated approver(s) sign via existing `POST /approvals/{id}/sign` 4. On approval completion (`approval.completed` with `state: approved`), the session is auto-released 5. On rejection, the session remains held This is **optional** — configurable per deployment. Simple deployments can allow direct admin force-release without approval. ### Config ```yaml modules: sessions: force_release_requires_approval: false # default: direct admin release force_release_workflow: "session-override" # workflow to use when approval required ``` ## 4. Routes ```go // Under /api/items/{partNumber}/edit-sessions/{sessionID}: r.Post("/request-handoff", server.HandleRequestHandoff) r.Delete("/force-release", server.HandleForceRelease) // admin only ``` ## 5. Audit Trail Both handoff requests and force-releases write to the existing `audit_log` table: | Action | Resource Type | Details | |--------|--------------|--------| | `edit.handoff_requested` | `edit_session` | requester, holder, message | | `edit.force_released` | `edit_session` | admin, reason, holder, approval_id (if applicable) | ## Acceptance Criteria - [ ] `POST /request-handoff` sends SSE notification to holder's workstation - [ ] `DELETE /force-release` releases session (admin only) - [ ] Force-release creates audit log entry with reason - [ ] `edit.handoff_requested` SSE event delivered to holder - [ ] `edit.force_released` SSE event delivered to holder - [ ] Optional: force-release creates approval and waits for sign-off before releasing - [ ] Config toggle between direct and approval-gated force-release - [ ] `session-override.yaml` workflow definition included ## Depends On - #163 (edit session endpoints) - #162 (SSE per-workstation delivery for targeted notifications) - Existing approval system (migrations 018-019, `internal/api/approval_handlers.go`) ## Part Of #125
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kindred/silo#167