# Origamy playbook spec v1. Reference: /playbooks/spec-format/
spec_version: 1
id: base.feedback-follow-up
title: Feedback form with follow-up
sector: base
source:
  kind: synthesized
  notes: >-
    No customer has run a feedback loop with us yet. The pattern (a form answer starts a
    follow-up through a trigger property filter) is the one a real build used to act on a staff
    decision form; the rating form and the routing are written from the base patterns.
derived_from: null
vocabulary:
  person: person
  people: people
  group: team
summary: >-
  Asks people how it went with a short rating form. Low scores give your team a task to call
  and put things right, and everyone gets a thank-you with a link to leave a review.
when_to_use:
  - After a purchase, a visit, an appointment, a class or a support case.
  - You want unhappy people called quickly, and everyone asked for a review.

requires:
  data_in:
    - how: public_form
      what: "The Feedback form this playbook creates; send its link after the visit, or print it as a QR code."
  channels:
    - channel: email
      for: The thank-you and review request
      needs: A verified sending domain for {{ params.email_from }}.
  events:
    - onboarding.submitted
  traits:
    - last_rating

parameters:
  - key: org_name
    ask: true
    question: What should messages call your organisation?
    label: Organisation name
    type: string
    example: Northwind
  - key: about_what
    ask: true
    question: What are you asking about? (as the form will say it, e.g. "your visit")
    label: Asking about
    type: string
    default: your experience
  - key: care_team
    ask: true
    question: Which team calls people who gave a low score?
    label: Care team
    type: team_name
    default: Customer care
  - key: review_url
    ask: true
    question: Where should people leave a review? (leave empty to just say thank you)
    label: Review link
    type: url
    default: ""
  - key: low_score
    ask: true
    question: Which scores count as unhappy? (out of 5)
    label: Unhappy at or below
    type: number
    default: 2
  - key: email_from
    label: Sender address
    type: email
    default: "{{ workspace.default_sender }}"
  - key: call_due_hours
    label: Hours the care team has to call
    type: hours
    default: 24
  - key: greeting_fallback
    label: Greeting when a first name is missing
    type: string
    default: there

timings:
  - A score of {{ params.low_score }} or lower creates a call task straight away, due in {{ params.call_due_hours }} hours, escalating to the same team's attention at the due time.
  - Everyone gets the thank-you email an hour later. Asking only happy customers for reviews ("review gating") breaks Google's and most review sites' rules.
  - Every score is saved on the profile as last_rating.

customer_must:
  - Send the form's link after the moment you're asking about, for example from a follow-up that runs after a purchase or appointment, or print it as a QR code.
  - Add people to the {{ params.care_team }} team.
  - Publish the form, then switch both follow-ups on.

objects:
  - ref: team_care
    kind: team
    about: Calls people who gave a low score.
    body: { name: "{{ params.care_team }}" }
  - ref: form_feedback
    kind: form
    about: A one-page rating form with an optional comment. The score is saved on the profile.
    body:
      name: Feedback
      slug: feedback
      description: "How was {{ params.about_what }}?"
      draft_state:
        version: 1
        meta: { layout: classic, submit_label: Send, success_message: Thank you for telling us. }
        pages:
          - id: p1
            title: "How was {{ params.about_what }}?"
            description: It takes ten seconds.
            fields:
              - { id: f_rating, key: rating, type: rating, label: "How would you rate {{ params.about_what }}?", required: true, maps_to: { mode: custom, key: last_rating, trait: true }, validation: { min: 1, max: 5 } }
              - { id: f_comment, key: comment, type: long_text, label: Anything you'd like to tell us?, required: false, maps_to: { mode: custom, key: comment } }
              - { id: f_email, key: email, type: email, label: Your email (so we can reply), required: false, maps_to: { mode: mapped, slot: profile.email } }
      verification_settings: { required: false }
  - ref: tmpl_thanks
    kind: template
    about: Thank-you email, with a review link if you gave one.
    body:
      name: Thanks for your feedback (email)
      channel: email
      category: Feedback
      style: html
      status: active
      subject: "Thank you, {{ traits.first_name | default: \"{{ params.greeting_fallback }}\" }}"
      metadata: { email: { from: "{{ params.email_from }}", preview_text: "" } }
      variables: {}
      body: >-
        <p>Hi {{ traits.first_name | default: "{{ params.greeting_fallback }}" }},</p>
        <p>Thank you for telling us about {{ params.about_what }}. It means a lot to the
        whole team at {{ params.org_name }}.</p>
        {% if "{{ params.review_url }}" != "" %}<p>Would you share it with others?
        <a href="{{ params.review_url }}">Leave a review</a></p>{% endif %}
        <p style="font-size:12px;color:#6b6b80"><a href="{{ unsubscribe_url }}">Unsubscribe</a></p>
  - ref: wf_low
    kind: workflow
    about: A low score gives the care team a call task; the outcome is saved on the profile.
    body:
      name: "Feedback: low score call"
      description: When a score at or below the unhappy line comes in, the care team calls.
      enabled: false
      trigger_type: event
      trigger_config:
        event_name: onboarding.submitted
        form_id: "{{ ref.form_feedback.id }}"
        property_filters: [{ property: rating, cond_operator: lte, value: "{{ params.low_score }}" }]
        properties: { $origamy_property_filters: true }
      steps:
        - id: s1
          type: human_task
          config:
            human_task:
              title: "Unhappy feedback: {{ traits.first_name }} {{ traits.last_name }}"
              instructions: |-
                {{ traits.first_name | default: "Someone" }} rated {{ params.about_what }} {{ properties.rating }} out of 5.
                Their comment: {{ properties.comment | default: "none" }}
                Contact: {{ traits.phone }} {{ traits.email }}

                Call or email them, listen, and put it right if you can. Note what you agreed.
              assignee_refs: [{ type: team, id: "{{ ref.team_care.id }}" }]
              strategy: round_robin
              completion_policy: first_response_wins
              outcome_options:
                - { id: resolved, label: Resolved, intent: positive }
                - { id: follow_up, label: Needs more follow-up, intent: neutral }
                - { id: not_reached, label: Could not reach, intent: negative }
              due_hours: "{{ params.call_due_hours }}"
              wait: true
              wait_timeout_hours: 168
              notify: immediate
        - { id: s2, type: action, config: { action_type: set_trait, traits: { feedback_follow_up: "{{ properties.task_outcome | default: \"unknown\" }}", feedback_note: "{{ properties.task_note }}" } } }
      re_entry_policy: every_time
      re_entry_cooldown_hours: 0
      goal: {}
      exit_conditions: []
  - ref: wf_high
    kind: workflow
    about: Everyone gets the thank-you (and review link) an hour later.
    body:
      name: "Feedback: thank you"
      description: The thank-you email, for everyone who gives feedback.
      enabled: false
      trigger_type: event
      trigger_config:
        event_name: onboarding.submitted
        form_id: "{{ ref.form_feedback.id }}"
      steps:
        - { id: s1, type: delay, config: { duration: 1h } }
        - { id: s2, type: action, config: { action_type: send_message, channel_config: { mode: single, single: { channel: email, template_id: "{{ ref.tmpl_thanks.id }}" } } } }
      re_entry_policy: cooldown
      re_entry_cooldown_hours: 720
      goal: {}
      exit_conditions: []

eval:
  name: 67_base_feedback_follow_up
  mode: task
  vertical: ""
  prompt: >-
    Make a short feedback form that asks people to rate their visit out of 5. If someone gives
    1 or 2, our customer care team should get a task to call them within a day. Send everyone a
    thank-you email with a link to leave a review.
  expect_artifacts: [form, workflow, message_template]
  forbid_terms: []
