Back to Policy Acknowledgement Tracking

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Policy Acknowledgement Tracking

[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]

This document is the primary technical reference for the FullSpec team building the Policy Acknowledgement Tracking automation. It covers the current-state process, all three agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. Everything needed to begin implementation is contained here. Where tool credentials and template IDs are still being confirmed, the relevant prerequisite is called out explicitly so that build work is not blocked by a missing dependency.

01Process snapshot

Step
Name
Description
1
Identify Policy Update and Affected Employees
HR reviews the updated policy and manually identifies which employee groups must acknowledge it. The employee list is pulled from BambooHR or a local spreadsheet. Time cost: 30 min/cycle.
2
Prepare Acknowledgement Tracking Spreadsheet
HR creates or duplicates a Google Sheet with one row per employee and columns for email sent date, reminder dates, and sign-off status. Reset each cycle. Time cost: 25 min/cycle.
3
Draft and Send Initial Policy Email
HR drafts the policy notification email, attaches the document or a link, and sends it to the employee list via Gmail. Personalisation is done manually. Time cost: 40 min/cycle.
4
Prepare DocuSign Envelope
HR creates a DocuSign envelope, adds every employee as a signer, and sends it. For large groups this is time-consuming and prone to missed recipients. BOTTLENECK. Time cost: 45 min/cycle.
5
Monitor Signature Status in DocuSign
HR logs into DocuSign daily or every few days to check who has signed and who is pending, then manually copies results back to the tracking spreadsheet. BOTTLENECK. Time cost: 20 min/cycle.
6
Update Tracking Spreadsheet
HR marks each completed signature in the Google Sheet with the date. Employees who have left mid-cycle must be removed manually. Time cost: 15 min/cycle.
7
Send Manual Reminders to Non-Responders
HR identifies unsigned employees by reviewing the spreadsheet then messages them individually via Slack or email. Timing and content vary by sender. BOTTLENECK. Time cost: 30 min/cycle.
8
Escalate Persistent Non-Responders to Manager
If an employee has not responded after two reminders, HR emails their line manager. Sometimes skipped under time pressure. Time cost: 20 min/cycle.
9
Archive Signed Documents
HR downloads completed envelopes from DocuSign and uploads them to the employee record in BambooHR or a shared folder. Time cost: 20 min/cycle.
10
Produce Completion Report
HR manually compiles a completion summary from the spreadsheet and shares it with the compliance lead or relevant stakeholder. Time cost: 25 min/cycle.
Time cost summary: Total manual time per cycle is 270 minutes (4 hours 30 minutes) across all 10 steps. At 3 to 6 cycles per year, this equates to approximately 13 to 27 hours of HR staff time annually, benchmarked at 3 hours/week during active cycles. Steps 1 through 10 are all targeted for automation replacement. Steps 1 to 4 are replaced by the Policy Distribution Agent. Steps 5 to 8 are replaced by the Reminder and Escalation Agent. Steps 9 and 10 are replaced by the Completion and Archiving Agent. The sole remaining human touch point is the judgment call on escalated non-responders (flagged by the automation but resolved by the HR Manager).
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Policy Distribution Agent

Handles the full send-out cycle for a new or updated policy. On trigger, it queries BambooHR for the correct employee list, seeds a new tracking log in Google Sheets, and creates and dispatches DocuSign envelopes programmatically using a pre-approved template. It ensures every active employee in scope receives the correct policy version without any manual envelope setup. Estimated build: 8 hours. Complexity: Moderate.

Trigger
Policy document marked as published in BambooHR, or scheduled review date reached. Delivered via BambooHR webhook (POST to orchestration layer endpoint) or a daily cron check against BambooHR custom fields.
Tools
BambooHR (employee list fetch, API v1), DocuSign (envelope create and send, eSignature REST API v2.1), Google Sheets (row seeding, Sheets API v4)
Replaces steps
Steps 1, 2, 3, and 4
Estimated build
8 hours. Complexity: Moderate
// Input
policy_id: string            // BambooHR custom field or document ID
policy_name: string          // Human-readable label, used in envelope subject and Sheet header
policy_version: string       // Version tag, e.g. 'v2.3', locked to envelope template revision
policy_document_url: string  // Signed S3 or BambooHR-hosted URL for the PDF attachment
target_group: string         // e.g. 'all_active', 'department:engineering', 'location:US'
cycle_deadline: date         // ISO 8601, used to calculate reminder and escalation offsets

// Output
cycle_id: string             // UUID generated for this distribution cycle, written to Sheet col A
employee_list: array         // [{employee_id, full_name, email, department, manager_email}]
sheet_tab_id: string         // Google Sheets tab name, format: 'cycle_{policy_id}_{YYYYMMDD}'
envelope_ids: array          // [{employee_id, docusign_envelope_id, sent_at: ISO 8601}]
distribution_status: string  // 'success' | 'partial' | 'failed', written to Sheet col H
  • BambooHR API tier must include custom fields access and employee directory read scope (OAuth 2.0 scope: employees:read, files:write). Confirm with BambooHR admin before build start.
  • BambooHR employee list query must filter status = 'Active' and exclude employees where employment_status = 'On Leave (Extended)' to prevent sending to unreachable staff.
  • DocuSign envelope template must be pre-approved and version-locked by a DocuSign admin (template_id stored as an environment variable DOCUSIGN_TEMPLATE_ID). The agent must not fall back to a draft or unlocked template under any circumstances.
  • DocuSign bulk send uses the Envelopes: createEnvelope endpoint with composite templates; do not use the legacy BulkRecipient CSV method as it does not support webhook callbacks per envelope.
  • Google Sheets tab naming convention must be enforced: 'cycle_{policy_id}_{YYYYMMDD}' to prevent collision across concurrent cycles. If a tab with that name already exists, the agent appends '_r{n}' and logs a warning.
  • Dedupe: before creating envelopes, the agent checks the Sheet for any existing envelope_id for the same employee and policy_id. If found, it skips re-send and logs 'duplicate_skipped'.
  • Confirm BambooHR webhook or cron fallback approach with process owner before build, as some BambooHR tiers do not emit webhooks on document field changes.
Reminder and Escalation Agent

Runs on a daily schedule after the initial distribution. It polls DocuSign envelope status for each employee in the active cycle, identifies non-responders, sends a day-five Gmail reminder with a direct envelope link, and sends a day-ten Slack direct message to the employee and a separate Slack notification to their line manager. It keeps the Google Sheet status column current after every run. Estimated build: 8 hours. Complexity: Moderate.

Trigger
Daily cron schedule (recommended: 09:00 local HR timezone). Reads all active cycle_ids from the master Google Sheet index tab where cycle_status != 'complete'.
Tools
DocuSign (envelope status poll, GET /envelopes/{envelopeId}), Gmail (reminder send, Gmail API v1 messages.send), Slack (DM and manager alert, Web API chat.postMessage), Google Sheets (status update, Sheets API v4 batchUpdate)
Replaces steps
Steps 5, 6, 7, and 8
Estimated build
8 hours. Complexity: Moderate
// Input
cycle_id: string             // From active cycles index in Google Sheets
employee_id: string          // BambooHR employee ID
envelope_id: string          // DocuSign envelope ID from Policy Distribution Agent output
sent_at: date                // ISO 8601 timestamp of original send, used to calculate day offsets
cycle_deadline: date         // ISO 8601, used to suppress reminders after deadline has passed
manager_email: string        // From BambooHR employee record, used for Slack escalation lookup
manager_slack_id: string     // Slack user ID resolved from manager_email via users.lookupByEmail

// Output
reminder_sent_at: date       // Timestamp written to Sheet col D when day-5 Gmail fires
escalation_sent_at: date     // Timestamp written to Sheet col E when day-10 Slack fires
current_envelope_status: string // 'sent' | 'delivered' | 'completed' | 'declined' | 'voided'
sheet_row_updated: boolean   // True if batchUpdate call succeeded for this employee row

// On escalation
slack_message_employee: string  // DM to employee Slack ID: direct link to DocuSign envelope
slack_message_manager: string   // DM to manager Slack ID: employee name, policy name, days overdue
  • DocuSign status poll must use GET /v2.1/accounts/{accountId}/envelopes?envelope_ids={id} to batch multiple envelope checks per API call. Do not issue one HTTP request per employee; DocuSign rate limit is 1,000 requests per hour per account.
  • Day offset is calculated from sent_at, not from the cron run date, to handle cycles that start mid-week or during a public holiday window.
  • Gmail reminder must use a stored HTML template (environment variable GMAIL_REMINDER_TEMPLATE_ID or an inline template string). The DocuSign envelope signing URL must be fetched fresh per send using GET /envelopes/{id}/recipients to avoid expired URLs.
  • Slack manager notification requires the manager_slack_id to be resolved via Slack users.lookupByEmail before message send. If the lookup fails (manager not in Slack workspace), fall back to a Gmail email to manager_email and log 'slack_fallback_email'.
  • BambooHR reporting-line data must be confirmed as clean before go-live. If manager fields are blank or inconsistent, escalation routing will fail. A one-time data cleanse of supervisor_id in BambooHR is flagged as a prerequisite.
  • Reminders must not fire after cycle_deadline has passed. Add a guard condition: if current_date > cycle_deadline, skip reminder and log 'deadline_passed_no_action'.
  • Employees with envelope status 'declined' or 'voided' must be flagged in the Sheet with tone 'amber' and excluded from standard reminders. These cases route immediately to HR Manager review via a separate Slack alert.
Completion and Archiving Agent

Listens for DocuSign envelope completion webhooks and, on each event, retrieves the signed PDF, attaches it to the correct employee record in BambooHR, and updates the Google Sheet row to 'signed' with a timestamp. When all employees in a cycle have a completed status, the agent generates a completion report summarising the cycle and distributes it to the HR Manager. Estimated build: 6 hours. Complexity: Moderate.

Trigger
DocuSign Connect webhook event (envelope status = 'completed') POST to orchestration layer endpoint, or a fallback cycle-close check when all rows in the Sheet show 'completed' status regardless of webhook receipt.
Tools
DocuSign (signed PDF retrieve, GET /envelopes/{id}/documents/{docId}), BambooHR (document attachment, POST /v1/employees/{id}/files/), Google Sheets (status update and report generation, Sheets API v4)
Replaces steps
Steps 9 and 10
Estimated build
6 hours. Complexity: Moderate
// Input (per webhook event)
envelope_id: string          // From DocuSign Connect payload
envelope_status: string      // Must equal 'completed' to proceed; all others are no-ops
completed_at: date           // ISO 8601 from DocuSign event payload
signer_email: string         // Used to look up employee_id in the Sheet index
document_id: string          // DocuSign document ID within the envelope for PDF download

// Output (per employee completion)
bamboohr_file_id: string     // ID returned by BambooHR after successful document upload
bamboohr_category: string    // Must be set to 'Signed Policies' (exact BambooHR category name)
sheet_status: string         // 'signed' written to col C, completed_at timestamp to col F
cycle_complete: boolean      // True when all employee rows for cycle_id show status = 'signed'

// On cycle completion
completion_report_url: string // Google Sheets export link (PDF or Sheets share), emailed to HR Manager
report_summary: object        // {cycle_id, policy_name, total_employees, signed_count, pending_count, declined_count, completion_pct}
  • BambooHR document upload endpoint is POST /v1/employees/{id}/files/ with multipart/form-data. The category field must match the exact string 'Signed Policies' as configured in the BambooHR document categories admin panel. Confirm this category exists before build.
  • DocuSign signed PDF is retrieved using GET /v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId} with Accept: application/pdf. The document must be streamed directly to BambooHR upload, not written to disk, to avoid PII data at rest on the orchestration server.
  • Webhook reliability: DocuSign Connect may deliver events out of order or with delay. Implement idempotency using envelope_id as the deduplication key. If a completed event is received for an envelope already marked 'signed' in the Sheet, log 'idempotent_skip' and return 200.
  • Completion report generation should use the Google Sheets API to read all rows for the cycle_id and produce a summary object. The report is emailed to the HR Manager via Gmail using a stored template (GMAIL_REPORT_TEMPLATE_ID).
  • If a webhook event is not received within 2 hours of the expected signing window closing, a fallback polling job should run a final DocuSign status sweep and process any missed completions.
  • BambooHR API write access (files:write scope) must be confirmed as part of tool access check milestone (Apr 14). Build cannot be completed without this permission.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full end-to-end data flow: trigger through archiving. Field names match agent IO contracts above.
// ============================================================
// POLICY ACKNOWLEDGEMENT TRACKING: END-TO-END DATA FLOW
// ============================================================

// --- TRIGGER ---
// BambooHR webhook fires on policy publish, or daily cron detects review_date = today
TRIGGER: BambooHR -> orchestration_layer
  payload: {
    policy_id: 'POL-2024-042',
    policy_name: 'Remote Work Policy',
    policy_version: 'v2.3',
    policy_document_url: 'https://api.bamboohr.com/api/gateway.php/[company]/v1/files/...',
    target_group: 'all_active',
    cycle_deadline: '2024-06-15T17:00:00Z'
  }

// --- AGENT 1: POLICY DISTRIBUTION AGENT ---

// Step 1: Fetch active employee list from BambooHR
BambooHR.GET /v1/employees/directory
  filter: status='Active', employment_status!='On Leave (Extended)'
  fields: id, firstName, lastName, workEmail, department, supervisorEmail
  output -> employee_list: [
    { employee_id: 'E001', full_name: 'Jane Smith', email: 'jane@example.com',
      department: 'Engineering', manager_email: 'mgr@example.com' },
    // ... n employees
  ]

// Step 2: Seed Google Sheets tracking tab
GoogleSheets.batchUpdate -> tab: 'cycle_POL-2024-042_20240501'
  columns: [cycle_id, employee_id, full_name, email, department, manager_email,
             envelope_id, status, sent_at, reminder_at, escalation_at,
             signed_at, bamboohr_file_id, notes]
  initial_status: 'pending' (all rows)
  output -> sheet_tab_id: 'cycle_POL-2024-042_20240501'

// Step 3: Create and send DocuSign envelopes (one per employee)
DocuSign.POST /v2.1/accounts/{accountId}/envelopes
  template_id: ENV['DOCUSIGN_TEMPLATE_ID']  // pre-approved, version-locked
  per employee: {
    signers[0].email: employee.email,
    signers[0].name: employee.full_name,
    signers[0].clientUserId: employee.employee_id,  // for embedded signing fallback
    emailSubject: 'Action required: Please acknowledge Remote Work Policy v2.3',
    templateRoles[0].tabs.textTabs: [{ tabLabel: 'PolicyVersion', value: 'v2.3' }]
  }
  output -> envelope_ids: [{ employee_id: 'E001', envelope_id: 'ENV-abc123', sent_at: ISO8601 }]

// Write envelope_ids back to Sheet col G (envelope_id) + col I (sent_at)
GoogleSheets.batchUpdate -> update rows with envelope_id and status='sent'

// ======================= AGENT 1 -> AGENT 2 HANDOFF =======================
// cycle_id, sheet_tab_id, employee_list, envelope_ids written to shared state (Sheet index tab)
// Agent 2 reads these fields on each daily cron run
// =========================================================================

// --- AGENT 2: REMINDER AND ESCALATION AGENT (daily cron 09:00) ---

// Step 4: Poll DocuSign envelope status for all non-completed envelopes
DocuSign.GET /v2.1/accounts/{accountId}/envelopes
  envelope_ids: [batch of active envelope_ids from Sheet]
  fields: envelopeId, status, completedDateTime, declinedDateTime
  output -> status_map: { 'ENV-abc123': 'sent', 'ENV-def456': 'completed', ... }

// Step 5: Update Sheet col C (current_envelope_status) for all rows
GoogleSheets.batchUpdate -> col C = status_map[envelope_id] per row

// Step 6: Day-5 reminder (if days_since_sent >= 5 and status != 'completed')
// Fetch fresh signing URL to avoid expiry
DocuSign.GET /v2.1/accounts/{accountId}/envelopes/{envelopeId}/recipients
  output -> signing_url: 'https://app.docusign.net/signing/...'
Gmail.messages.send
  to: employee.email
  template: ENV['GMAIL_REMINDER_TEMPLATE_ID']
  vars: { employee_name, policy_name, policy_version, signing_url, deadline }
  output -> reminder_sent_at -> Sheet col D

// Step 7: Day-10 escalation (if days_since_sent >= 10 and status != 'completed')
// Resolve manager Slack ID
Slack.users.lookupByEmail -> email: manager_email
  on_success -> manager_slack_id
  on_failure -> fallback: Gmail to manager_email, log 'slack_fallback_email'

// DM employee
Slack.chat.postMessage
  channel: employee_slack_id  // resolved same way as manager
  text: 'Reminder: Your signature on {policy_name} is overdue. Please sign here: {signing_url}'

// DM manager
Slack.chat.postMessage
  channel: manager_slack_id
  text: '{employee_name} has not signed {policy_name} v{version}. {days} days overdue. Deadline: {deadline}.'
  output -> escalation_sent_at -> Sheet col E

// ======================= AGENT 2 -> AGENT 3 HANDOFF =======================
// No direct call: Agent 3 is triggered independently by DocuSign webhook events
// Shared state continues via Google Sheets (cycle_id + employee_id as compound key)
// =========================================================================

// --- AGENT 3: COMPLETION AND ARCHIVING AGENT ---

// Step 8: Receive DocuSign Connect webhook (envelope status = 'completed')
WEBHOOK_RECEIVE: DocuSign -> orchestration_layer POST /webhooks/docusign-complete
  payload: { envelopeId, status, completedDateTime, signers[0].email }
  guard: if status != 'completed' -> return 200 (no-op)
  dedup: if Sheet row already shows status='signed' -> log 'idempotent_skip', return 200

// Step 9: Download signed PDF
DocuSign.GET /v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId}
  Accept: application/pdf
  output -> pdf_stream (in-memory, not written to disk)

// Step 10: Upload to BambooHR employee record
BambooHR.POST /v1/employees/{employee_id}/files/
  Content-Type: multipart/form-data
  fields: { category: 'Signed Policies', fileName: '{policy_name}_v{version}_{employee_id}.pdf',
            share: false }
  body: pdf_stream
  output -> bamboohr_file_id -> Sheet col M

// Step 11: Update Sheet row
GoogleSheets.batchUpdate
  col C (status): 'signed'
  col F (signed_at): completedDateTime (ISO 8601)
  col M (bamboohr_file_id): bamboohr_file_id

// Step 12: Check cycle completion
GoogleSheets.get -> all rows for cycle_id where status != 'signed'
  if pending_count == 0:
    cycle_complete = true
    report_summary = { cycle_id, policy_name, total_employees, signed_count,
                       pending_count: 0, declined_count, completion_pct: '100%' }
    Gmail.messages.send -> HR Manager email
      subject: 'Cycle complete: {policy_name} v{version} acknowledgement report'
      attachment: Google Sheets export PDF URL
  else:
    cycle_complete = false  // Agent 2 continues daily monitoring

// ============================================================
// END OF FLOW
// ============================================================
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation tool with native HTTP request nodes, cron scheduling, and a shared credential store. One workflow per agent (three workflows total): 'Policy Distribution', 'Reminder and Escalation (cron)', and 'Completion and Archiving (webhook)'. Credentials for BambooHR, DocuSign, Gmail, Slack, and Google Sheets are stored in the platform's encrypted credential store and referenced by name, never hard-coded. Environment variables (DOCUSIGN_TEMPLATE_ID, GMAIL_REMINDER_TEMPLATE_ID, GMAIL_REPORT_TEMPLATE_ID, BAMBOOHR_COMPANY_SUBDOMAIN, BAMBOOHR_API_KEY, SLACK_BOT_TOKEN) are managed via the platform's secrets manager or a connected secrets vault.
Webhook configuration
Two inbound webhook endpoints are required. Endpoint 1: DocuSign Connect callback, path /webhooks/docusign-complete, HMAC-SHA256 signature verification using DocuSign Connect HMAC key (stored as env var DOCUSIGN_HMAC_KEY). Endpoint 2: BambooHR policy publish webhook (if supported by BambooHR tier), path /webhooks/bamboohr-policy, verified by a shared secret header. Both endpoints must be on HTTPS with a valid TLS certificate. The cron fallback for BambooHR (daily check at 07:00 UTC) is used if the BambooHR webhook tier is unavailable.
Templating approach
Email bodies for Gmail reminders and completion reports use HTML templates stored as environment variable strings or as template documents in Google Drive (fetched by document ID at runtime). DocuSign envelopes use a single pre-approved DocuSign template (template_id in env var), with per-recipient variable substitution for employee_name, policy_version, and signing_url injected at send time via templateRoles. No inline template construction is permitted, as it risks sending incorrect policy versions.
Error logging
All agent run errors, fallback events, and idempotency skips are written to a Supabase table (table: automation_logs, columns: id UUID, cycle_id, agent_name, employee_id, event_type, event_detail, created_at). On any error where event_type starts with 'error_', a Slack alert is posted to the HR ops Slack channel (#hr-automation-alerts) with the cycle_id, agent_name, and error detail. Non-fatal events (idempotent_skip, slack_fallback_email, duplicate_skipped, deadline_passed_no_action) are logged to Supabase only, without an alert, to avoid noise.
Testing approach
All three agents are built and validated in sandbox environments first. DocuSign sandbox (demo.docusign.net) is used throughout build and QA. BambooHR sandbox or a test company subdomain is used for employee record writes. Gmail sends during testing are routed to a dedicated internal test inbox (e.g. automation-test@[YourCompany.com]) using recipient override. Slack messages during testing are posted to a private #automation-test channel, not to real employee DMs. Google Sheets tests use a dedicated 'TEST_cycle_' prefixed tab to avoid polluting live data. End-to-end testing uses a pilot group of 5 to 10 real employees with a dummy policy document, as described in the delivery plan.
Estimated total build time
Policy Distribution Agent: 8 hours. Reminder and Escalation Agent: 8 hours. Completion and Archiving Agent: 6 hours. End-to-end integration testing and QA: 6 hours (included in the 22-hour build effort total confirmed in the project snapshot). Discovery and tool access confirmation: 2 hours (week 1, not counted as build time). Total build effort: 22 hours.
Before any build work starts, the following must be confirmed: BambooHR API key with employees:read and files:write scopes issued; DocuSign template pre-approved and template_id provided; Slack bot token with users:read.email and chat:write scopes; BambooHR document category 'Signed Policies' verified as existing; and manager/supervisor fields in BambooHR confirmed as populated and accurate. Contact support@gofullspec.com if any prerequisite is blocked.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Policy Acknowledgement Tracking.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View