Skip to content

Secure and structure runtime-template administration #157

Description

@alexeygrigorev

Status

Groomed and ready for implementation.

Problem

The canonical frontend exposes runtime-template create, edit, and delete controls to every authenticated operator. The backend receives no verified actor context on template routes, so it cannot enforce privileged mutations. Editing is a raw JSON textarea, writes have no concurrency token, deletion does not protect referenced templates, and the current tests do not prove authorization or saved-definition instantiation fidelity.

In this issue, the intended maintainer/admin boundary maps to the existing User.role = admin role. Adding a new maintainer role is out of scope.

Scope

Deliver a server-enforced, admin-only runtime-template administration flow in the canonical frontend and API.

Authorization

  • Route template mutations through the repository's verified server-side actor path. Do not trust role, user ID, or forwarding headers supplied by the browser.
  • POST, PUT, and DELETE are allowed only for an authenticated active admin.
  • Unauthenticated requests return JSON 401; authenticated non-admin requests return JSON 403; neither path mutates data or writes a success audit event.
  • Operators may continue to list/read templates and instantiate workflows when otherwise authorized.
  • Mutation controls are absent from the operator UI, but UI hiding is not the security boundary.
  • Preserve the existing API error envelope and do not leak template contents, user details, or internal authorization data.

Structured editor

Replace the raw-JSON-first form with structured controls for the complete supported runtime-template contract:

  • template metadata: name, type, emoji, tags, and default assignee;
  • trigger settings: type, schedule, lead time, and enabled state;
  • phases and source/reference or bundle links;
  • ordered task definitions, including ref ID, description, day offset, phase, assignee, instructions/document step, systems, validation, proof requirement, required link/file, completion stage, and artifact/assistant/audit references;
  • add, remove, and keyboard-accessible reorder controls with visible focus and validation tied to the relevant field.

JSON may appear only in a collapsed Advanced JSON disclosure. It is a read-only, normalized representation of the structured draft; the primary create/edit path must not require JSON authoring, and supported fields must not be silently discarded.

Save and concurrency states

  • Add a monotonic integer template version. New templates start at 1; successful updates increment it.
  • Existing records without a version are exposed as version 1 and can be upgraded by the first conditional write without an offline data migration.
  • PUT and DELETE require the client's expectedVersion and use a datastore conditional write. Missing or stale versions return JSON 409 conflict; the response may expose the current version and updatedAt, but not a replacement definition.
  • The editor visibly distinguishes clean/saved, dirty, saving, validation error, permission/network error, and conflict states.
  • Prevent duplicate submissions. A failed or conflicting save preserves the local draft. Conflict recovery offers an explicit reload of the server version and never overwrites either version silently.
  • Closing, navigating away from, cancelling, or switching templates with an unsaved draft requires confirmation.

Safe deletion and audit

  • Hard deletion is allowed only when the template has zero references. The server, not the browser, checks all persisted reference classes, including bundles/tasks with templateId and any scheduler or recurrence reference to the template.
  • A referenced template is not deleted and returns JSON 409 template_in_use with sanitized counts/categories only—no private names, descriptions, or IDs. There is no browser force-delete path.
  • The UI uses a destructive confirmation naming the template and explains that referenced templates cannot be deleted.
  • Record privacy-safe immutable audit events for successful create/update/delete mutations and rejected delete attempts. Include actor ID, template ID, action, outcome/reason, prior/result version where applicable, timestamp, and changed field names; do not store the full definition, credentials, document contents, or other sensitive values.
  • A successful mutation and its success audit record must not diverge: use an atomic write when supported or fail closed with a tested compensating strategy.

Saved-definition fidelity

Prove a real round trip through persistence:

  1. An admin creates or edits a template through the structured editor, including multiple reordered tasks and non-default optional fields.
  2. The UI reloads the saved definition from the API.
  3. A workflow is instantiated from that saved definition.
  4. The resulting bundle/tasks preserve the saved task order and supported values, including offsets, phases, descriptions, instructions, proof requirements, milestones/completion stages, assignees, references, required links/files, and bundle/source links.

The test must fail if instantiation uses a stale client draft, fixture, or hard-coded template instead of the saved record.

Acceptance criteria

  • Verified server-side actor resolution protects all template mutation routes; admin succeeds, operator receives 403, unauthenticated receives 401, and spoofed client identity/role headers do not grant access.
  • The canonical UI exposes mutation controls only to admins and uses the structured, accessible, reorderable editor described above.
  • Advanced JSON is secondary/read-only, and a save/reload round trip loses no supported fields.
  • Dirty, saving, saved, validation, permission/network error, and conflict states are observable and preserve user work as specified.
  • Conditional update/delete behavior returns deterministic 409 responses for stale versions; concurrent requests cannot silently overwrite or delete newer data.
  • Referenced templates cannot be deleted; an unreferenced template can be deleted only by an admin with the current version.
  • Audit events are privacy-safe and mutation/audit consistency is covered by tests.
  • A saved structured definition instantiates with exact task order and field fidelity.
  • Architecture review records the authorization boundary, version/conditional-write contract, reference scan policy, audit consistency, and compatibility behavior for versionless rows.
  • Design evidence shows admin and operator states plus clean, dirty, saving, conflict, error, and delete-blocked behavior at desktop (1440x900) and mobile (390x844) widths.
  • Tests and evidence contain no real credentials, private links, contact details, raw operational documents, or sensitive fixture data.

Required tests

Backend/API tests must cover:

  • admin allow and operator/unauthenticated/spoofed-header denial for each of POST, PUT, and DELETE, with denial proven non-mutating;
  • create at version 1, conditional update increment, missing/stale-version 409, and two-writer concurrency with exactly one winner;
  • versionless-record compatibility;
  • referenced-delete 409, stale-delete 409, unreferenced delete success, and sanitized error bodies;
  • audit content/redaction and mutation/audit failure behavior;
  • full schema save/reload and instantiation fidelity.

Canonical browser tests against the real backend must cover:

  • role-based control visibility plus direct API denial for an operator;
  • structured task add/remove/reorder, validation, dirty-navigation confirmation, saving/saved/error states, and a conflict that preserves the draft;
  • referenced-delete refusal and named confirmation for an eligible delete;
  • create/save/reload/instantiate with API assertions for exact task order and values;
  • desktop and mobile evidence for the states listed above.

Run the relevant repository checks, including backend build/unit/integration tests and canonical frontend E2E. Source-marker or static-bundle assertions alone do not satisfy behavioral acceptance.

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Must havebackendBackend/APIbugSomething is brokendesignDesign and UXfrontendFrontend UIportalShared portal shell and UXtestingTests and QAwork-engineDataTasks task execution engine

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions