dodil/erp-brick-projects

src/brick_projects/application/process.yaml

# The brick's process — module.yaml's workflows, copied (pattern.md §15). BRICK.declare_process serves
# it as BPMN 2.0 at GET /process/bpmn; it is identical to `erp-compose bpmn --from module.yaml`.
# A transition's key (or its derived <entity>_<from>_to_<to>) is frozen once signed: it is the BPMN id.
id: projects
name: Projects & service delivery
version: 1
actors:
- id: project_lead
  name: Project lead / account manager
- id: contributor
  name: Whoever does the work
- id: client_contact
  name: The client's contact
  external: true
- id: finance
  name: Finance / the biller
- id: manager
  name: Operations manager / the owner
- id: system
  name: The system
workflows:
- entity: item
  states:
  - planned
  - in_progress
  - blocked
  - in_review
  - done
  - cancelled
  terminal:
  - done
  - cancelled
  transitions:
  - key: plan_from_contract
    name: Plan items from what was sold
    from: none
    to: planned
    by: system
    gate: a sale arrived (an active contract or a confirmed order); only lines that are delivered make items
    effect: keyed project|line|n, so planning again creates nothing
  - key: raise_makegood
    name: Raise a makegood (no revenue)
    from: none
    to: planned
    by: project_lead
    gate: the project was reconciled short
    effect: source makegood, no sold line; the short item stays short
  - key: ai_draft_plan
    name: AI suggests dates and owners (suggest)
    from: planned
    to: planned
    by: system
    gate: the step is on
    effect: suggestions only, until the lead accepts them
  - key: start
    name: Do the work
    from: planned
    to: in_progress
    by: contributor
  - key: block
    name: Block, with the reason
    from: in_progress
    to: blocked
    by: contributor
    requires: reason
    effect: stamps blocked_since; blocked days are not our slippage
  - key: ai_chase_brief
    name: AI drafts the reminder for the brief (suggest)
    from: blocked
    to: blocked
    by: system
    gate: blocked on the client past the chase days and the step is on
    effect: a draft message a person may send
  - key: provide_brief
    name: Send the brief or assets
    from: blocked
    to: blocked
    by: client_contact
  - key: unblock
    name: Unblock when the brief arrives
    from: blocked
    to: in_progress
    by: contributor
    effect: accrues blocked days
  - key: submit
    name: Submit for review, with evidence
    from: in_progress
    to: in_review
    by: contributor
    effect: starts the review clock
  - key: review
    name: Review the delivery
    from: in_review
    to: in_review
    by: client_contact
    effect: accepted, changes, or no answer
  - key: send_warning
    name: Send the deemed-acceptance warning
    from: in_review
    to: in_review
    by: project_lead
    gate: no answer within the review window
    effect: a person sends it; the system only shows the clock
  - key: request_changes
    name: Record changes requested
    from: in_review
    to: in_progress
    by: project_lead
    requires: reason
    effect: the same item, revision +1, never a new one
  - key: accept
    name: Record acceptance
    from: in_review
    to: done
    by: [project_lead, manager]
    gate: 'evidence attached, else "Attach the evidence first: a link, a file or a sign-off"; the recorder did not submit
      it, unless their role holds pj:item:accept_own'
    effect: approved_how recorded; a line billed on acceptance asks invoicing for its draft (AR-29)
  - key: accept_deemed
    name: Record deemed acceptance
    from: in_review
    to: done
    by: [project_lead, manager]
    gate: the warning was sent and its notice has ended; evidence attached; the recorder did not submit it, unless their role
      holds pj:item:accept_own
    effect: approved_how deemed; billed as for accept
    timer: the warning notice after the warning was sent
  - key: descope
    name: Descope
    from:
    - planned
    - in_progress
    - blocked
    - in_review
    to: cancelled
    by: project_lead
    requires: reason
    effect: counted as descoped, not short
  note: '"Short" is DERIVED: an item is short when its project''s window has closed and it is not done or descoped. Approval
    and delivery are timestamps on the item, not states. The state NAMES are rows the customer may rename (pj_state); the
    transitions are code. For the screens, the brick answers each item''s and project''s readiness (every gate of the next
    transitions: met or not, the reason in words, a fix link) and the project''s stage (plan, work, review, reconcile, derived
    from its items), so no screen re-derives a rule.'
- entity: project
  states:
  - planned
  - active
  - closed
  - cancelled
  terminal:
  - closed
  - cancelled
  transitions:
  - key: plan_project
    name: Open the project for the sale
    from: none
    to: planned
    by: system
    gate: a contract became active or an order was confirmed (PJ-20, PJ-21)
    effect: keyed pj:<source_kind>:<source_id>
  - key: activate
    name: Start the project
    from: planned
    to: active
    by: project_lead
    gate: the first item started
  - key: reconcile
    name: Reconcile sold vs delivered
    from: active
    to: closed
    by: system
    effect: stores sold, delivered, short, over and descoped per sold line
    timer: the project window ends (ends_on)
  - key: ai_flag_shortfall
    name: AI flags a likely shortfall (suggest)
    from: active
    to: active
    by: system
    gate: the window is closing and the step is on
    effect: a warning with the items at risk, while they can still be delivered
  - key: cancel_project
    name: Cancel the project
    from:
    - planned
    - active
    to: cancelled
    by: project_lead
    requires: reason
  note: 'Reconciliation is a stored RESULT on the closed project, not a state. A project with no deliverable lines is never
    opened: a sale of only monthly or usage lines plans nothing.'