Skip to content

Contracts — Document Approval Engine

Integration Events

Integration Event Contract (CloudEvents)

Outbound domain events are published as CloudEvents 1.0 (FR-019), emitted via the transactional outbox (FR-020). Delivery is at-least-once; consumers MUST dedupe on id.

Envelope attributes

CloudEvents attribute Source
specversion 1.0
id OutboxEvent.id (UUID) — dedupe key
source /wrkflw/document-approval (service/definition source URI)
type event type (below)
subject flow instance id
time OutboxEvent.occurredAt (RFC 3339 UTC)
datacontenttype application/json
data type-specific payload (below)

Event types

type Emitted when data fields
dev.wrkflw.flow.started A flow instance is created (US1) flowId, definitionKey, documentRef, submitterId, initialState
dev.wrkflw.task.created A human task is created for a stage flowId, taskId, stateName, candidateGroupId
dev.wrkflw.task.claimed A task is claimed flowId, taskId, ownerId
dev.wrkflw.task.released A claimed task is released flowId, taskId
dev.wrkflw.decision.recorded A decision is recorded (US2) flowId, taskId, outcome, actorId, comment?
dev.wrkflw.flow.completed A flow reaches a terminal outcome (US3) flowId, terminalOutcome

Guarantees (SC-006)

  • For every committed state change, exactly one corresponding outbox row is written in the same transaction; it is published exactly once effectively (at-least-once delivery + consumer dedupe on id).
  • No event is published for a rolled-back state change (the outbox row rolls back with it).
  • Events are for external integration only; they never drive internal flow progression (that is Temporal's role — Principle IV).

REST API (OpenAPI)

openapi: 3.0.0
info:
  title: wrkflw Document Approval API
  version: 0.1.0
  description: |-
    REST contract for the document-approval workflow engine.
    Actor identity and group memberships are supplied via trusted headers
    (X-Actor-Id, X-Actor-Groups). All command responses reflect the
    authoritative DB state committed before the corresponding Temporal
    signal is sent.
tags: []
paths:
  /flows:
    get:
      operationId: FlowsApi_list
      description: List flows submitted by the caller (submitter My Submissions view)
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FlowSummary'
    post:
      operationId: FlowsApi_submit
      description: Submit a document for approval — only initiator-group members may start (FR-002)
      parameters: []
      responses:
        '201':
          description: The request has succeeded and a new resource has been created as a result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlowStatus'
        '403':
          description: Access is forbidden.
        '404':
          description: The server cannot find the requested resource.
        '422':
          description: Client error
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitDocumentRequest'
  /flows/{flowId}:
    get:
      operationId: FlowInstancesApi_getStatus
      description: Get flow status, pending tasks, responsible groups, and audit history
      parameters:
        - name: flowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlowStatusWithHistory'
        '404':
          description: The server cannot find the requested resource.
  /tasks/{taskId}/claim:
    post:
      operationId: TaskClaimApi_claim
      description: Claim a pending task — caller must be in the candidate group and task must be PENDING (FR-008)
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskSummary'
        '403':
          description: Access is forbidden.
        '404':
          description: The server cannot find the requested resource.
        '409':
          description: The request conflicts with the current state of the server.
  /tasks/{taskId}/decision:
    post:
      operationId: TaskDecisionApi_decide
      description: Record an approve/reject decision on an owned task (FR-011, FR-012)
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlowStatus'
        '403':
          description: Access is forbidden.
        '404':
          description: The server cannot find the requested resource.
        '409':
          description: The request conflicts with the current state of the server.
        '422':
          description: Client error
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DecisionRequest'
  /tasks/{taskId}/release:
    post:
      operationId: TaskReleaseApi_release
      description: Release a claimed task back to the group (FR-009)
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskSummary'
        '403':
          description: Access is forbidden.
        '404':
          description: The server cannot find the requested resource.
        '409':
          description: The request conflicts with the current state of the server.
  /worklists/group:
    get:
      operationId: GroupWorklistApi_list
      description: Unclaimed tasks actionable by the caller's group(s) (FR-016)
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TaskSummary'
  /worklists/mine:
    get:
      operationId: MyWorklistApi_list
      description: Tasks the caller personally owns (FR-017)
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TaskSummary'
components:
  schemas:
    AuditEntry:
      type: object
      required:
        - type
        - actorId
        - occurredAt
        - detail
      properties:
        type:
          type: string
        actorId:
          type: string
          nullable: true
        occurredAt:
          type: string
          format: date-time
        detail:
          type: object
          additionalProperties: {}
    DecisionOutcome:
      type: string
      enum:
        - APPROVE
        - REJECT
    DecisionRequest:
      type: object
      required:
        - outcome
      properties:
        outcome:
          $ref: '#/components/schemas/DecisionOutcome'
        comment:
          type: string
    FlowRunStatus:
      type: string
      enum:
        - RUNNING
        - COMPLETED
    FlowStatus:
      type: object
      required:
        - flowId
        - definitionKey
        - currentState
        - status
        - terminalOutcome
        - pendingTasks
      properties:
        flowId:
          type: string
          format: uuid
        definitionKey:
          type: string
        currentState:
          type: string
        status:
          $ref: '#/components/schemas/FlowRunStatus'
        terminalOutcome:
          type: string
          nullable: true
        pendingTasks:
          type: array
          items:
            $ref: '#/components/schemas/TaskSummary'
    FlowStatusWithHistory:
      type: object
      required:
        - history
      properties:
        history:
          type: array
          items:
            $ref: '#/components/schemas/AuditEntry'
      allOf:
        - $ref: '#/components/schemas/FlowStatus'
    FlowSummary:
      type: object
      required:
        - flowId
        - definitionKey
        - currentState
        - status
        - terminalOutcome
        - documentRef
        - submitterId
        - updatedAt
      properties:
        flowId:
          type: string
          format: uuid
        definitionKey:
          type: string
        currentState:
          type: string
        status:
          $ref: '#/components/schemas/FlowRunStatus'
        terminalOutcome:
          type: string
          nullable: true
        documentRef:
          type: string
        submitterId:
          type: string
        updatedAt:
          type: string
          format: date-time
    SubmitDocumentRequest:
      type: object
      required:
        - definitionKey
        - documentRef
      properties:
        definitionKey:
          type: string
        documentRef:
          type: string
          description: Reference/identifier of the document
    TaskRunStatus:
      type: string
      enum:
        - PENDING
        - CLAIMED
        - COMPLETED
    TaskSummary:
      type: object
      required:
        - taskId
        - flowId
        - stateName
        - candidateGroupId
        - status
      properties:
        taskId:
          type: string
          format: uuid
        flowId:
          type: string
          format: uuid
        stateName:
          type: string
        candidateGroupId:
          type: string
        status:
          $ref: '#/components/schemas/TaskRunStatus'
        ownerId:
          type: string
          nullable: true
servers:
  - url: /api/v1
    description: Document Approval REST API
    variables: {}