Back to Contractor Management

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

Contractor Management Automation

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

This document gives the FullSpec build team everything needed to implement the Contractor Management automation end to end. It covers the current-state process map with bottlenecks identified, full agent specifications with IO contracts, a traced data-flow diagram, and the recommended build stack. The process owner and finance contact are responsible for granting API credentials and confirming Airtable schema before build begins. FullSpec handles all orchestration, integration wiring, error handling, and testing.

01Process snapshot

Step
Name
Description
1
Create Contractor Onboarding Request
Hiring Manager emails operations to notify them a contractor has been engaged. Request is unstructured and often missing key details. (10 min)
2
Send Onboarding Form to Contractor
Operations manually drafts and sends an email with a form link. The form is not always current. (15 min)
3 BOTTLENECK
Chase Missing Documents
If the contractor does not respond, operations sends follow-up emails, repeating two or three times before a full document set arrives. (20 min)
4
Review and File Compliance Documents
Operations checks each document for completeness, notes expiry dates, and saves files to a manually named Google Drive folder. (25 min)
5
Create Contractor Record in Airtable
A new row is manually added to the Airtable base with contact details, engagement dates, rate, and document status. (15 min)
6 BOTTLENECK
Set Up Contractor as Supplier in Xero
Finance adds the contractor as a supplier in Xero and enters pay details. Frequently delayed by one to two weeks. (20 min)
7
Notify Team of New Contractor
Operations sends a Slack message confirming the contractor is active and providing contact details. (10 min)
8
Receive and Log Contractor Invoices
Each fortnight, operations opens the invoice email, checks the amount against the agreed rate, and forwards it to finance. (15 min)
9 BOTTLENECK
Approve Invoice for Payment
The approving manager is emailed the invoice and must reply to confirm approval. Delays occur when the manager is travelling or not monitoring email. (10 min)
10
Enter Invoice in Xero and Schedule Payment
Finance manually creates a bill in Xero against the supplier record and schedules it for the next payment run. (15 min)
11
Monitor Compliance Document Expiry
Operations periodically reviews Airtable or a calendar reminder to check whether documents are approaching expiry. (20 min)
12
Run Contractor Offboarding
Operations manually removes system access, archives the Drive folder, closes the Xero supplier record, and sends a final confirmation. (25 min) — retained as human step
Time cost summary: Steps 1 through 11 total approximately 200 minutes (3 hrs 20 min) of manual work per contractor engagement cycle, plus recurring weekly invoice work estimated at 40 minutes/week across steps 8, 9, and 10. At 6 engagements/month and the loaded rate of $52/hour, the annualised cost sits at $11,200/year. The automation replaces steps 2, 3, 4, 5, 6, 7 (Contractor Onboarding Agent), steps 8, 9, 10 (Invoice Approval and Payment Agent), and step 11 (Compliance Monitor Agent). Step 12 (offboarding) and discrepancy review within step 9 are retained as human steps.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Contractor Onboarding Agent

Triggered by a new Google Forms submission, this agent orchestrates the full onboarding chain without human intervention. It parses every field from the form response, creates a contractor record in Airtable with document status set to Pending, files submitted compliance documents into a named Google Drive folder, creates a matching supplier entry in Xero using the payment details provided on the form, and posts a formatted Slack notification to the operations channel confirming the contractor is active. This agent replaces the most labour-intensive cluster of manual steps and eliminates the document-chasing loop entirely by capturing all required data at submission time. Complexity is rated Moderate due to the four-tool integration chain and the conditional logic needed for document completeness checking.

Trigger
New Google Forms submission received (webhook or polling interval not exceeding 5 minutes)
Tools
Google Forms, Airtable, Google Drive, Xero, Slack
Replaces steps
2, 4, 5, 6, 7
Estimated build
12 hours — Moderate
// Input
GoogleForms.response -> {
  contractor_name: string,
  email: string,
  phone: string,
  abn_or_tax_id: string,
  bank_bsb: string,
  bank_account: string,
  agreed_rate_usd: number,
  engagement_start_date: date,
  hiring_manager_name: string,
  documents: [{ file_name: string, file_url: string, expiry_date: date|null }]
}

// Output
Airtable.contractor_record -> {
  record_id: string,
  contractor_name: string,
  email: string,
  agreed_rate_usd: number,
  engagement_start_date: date,
  document_status: 'Pending' | 'Complete',
  drive_folder_url: string,
  xero_supplier_id: string,
  compliance_expiry_dates: [{ doc_type: string, expiry_date: date }]
}
GoogleDrive.folder -> named '{contractor_name}_{engagement_start_date}'
Xero.contact -> { contact_id: string, name: contractor_name, bank_account_details: {...} }
Slack.message -> { channel: '#operations', text: 'New contractor active: {contractor_name} from {engagement_start_date}' }
  • Google Forms must use fixed field names matching the Airtable schema exactly. Any form redesign prior to build requires a full field-map review before wiring begins.
  • Airtable base must be confirmed on a paid tier (Plus or above) to allow API access. The base ID and table name must be provided before build starts.
  • Google Drive folder structure must be agreed before build: recommended root is '/Contractors/{Year}/' with subfolders auto-named '{contractor_name}_{engagement_start_date}'. Confirm with the operations manager.
  • Xero supplier creation requires OAuth 2.0 authorisation from a Xero admin (finance manager). The connection must be authorised in a Xero Standard or Premium plan; Starter plan does not support supplier creation via API.
  • Xero rate limit is 60 calls/minute per organisation. At 6 onboardings/month this is well within threshold, but batch testing must not exceed this.
  • Slack webhook must target a confirmed channel (e.g. '#operations'). The Slack app must have 'chat:write' and 'incoming-webhook' scopes.
  • If a required form field is missing or empty, the agent must pause and post a Slack alert to the operations manager naming the missing fields. It must not create a partial Airtable record.
  • Dedupe check: before creating an Airtable record, query the base for an existing row with a matching email field. If found, update the existing record rather than creating a duplicate.
  • Confirm whether the Google Form collects document expiry dates as a date picker or a free-text field. Date picker is required for reliable parsing.
Invoice Approval and Payment Agent

Monitors for incoming contractor invoices, either via a dedicated email inbox or a contractor-facing submission form, and routes them to the correct approver via Slack with a one-click approve or query response. Once the approver confirms, the agent validates the invoice amount against the agreed rate stored in the contractor's Airtable record. If the amount matches within the configured tolerance (default: exact match), it creates a Xero bill against the existing supplier record and updates the Airtable row to reflect payment-scheduled status. If the amount does not match, the agent flags the discrepancy to the finance manager and halts automated processing for that invoice. Complexity is rated Moderate due to the conditional approval routing, rate-matching logic, and two-way Slack interaction pattern.

Trigger
New invoice email detected in monitored inbox (subject-line pattern match on contractor name or reference code) OR contractor submits invoice via a designated form
Tools
Xero, Slack, Airtable
Replaces steps
8, 9, 10
Estimated build
10 hours — Moderate
// Input
InvoiceSource.email | InvoiceSource.form -> {
  invoice_number: string,
  contractor_name: string,
  contractor_email: string,
  invoice_amount_usd: number,
  invoice_date: date,
  invoice_period: string,
  file_attachment_url: string
}

// Lookup
Airtable.contractor_record -> {
  record_id: string,
  agreed_rate_usd: number,
  xero_supplier_id: string,
  hiring_manager_slack_id: string
}

// On approval (amount matches)
Xero.bill -> {
  bill_id: string,
  contact_id: xero_supplier_id,
  amount_usd: invoice_amount_usd,
  due_date: next_payment_run_date,
  status: 'AUTHORISED'
}
Airtable.contractor_record -> { payment_status: 'Scheduled', last_invoice_date: invoice_date }

// On discrepancy (amount does not match)
Slack.message -> { user: finance_manager_slack_id, text: 'Invoice discrepancy: {contractor_name} submitted ${invoice_amount_usd}, agreed rate is ${agreed_rate_usd}. Manual review required.' }
Airtable.contractor_record -> { payment_status: 'Flagged', flag_reason: 'Amount mismatch' }
  • Invoice detection method must be confirmed before build: monitored Gmail inbox (requires Gmail API with 'gmail.readonly' scope and a dedicated label or filter) or a Google Form. A Gmail-based approach requires the inbox address to be a Google Workspace account accessible via service account or OAuth.
  • Contractor name matching between invoice and Airtable relies on consistent naming. Confirm a canonical naming convention (e.g. 'FirstName LastName') and enforce it on the submission side. Mismatches will route to manual review.
  • The Slack approval interaction requires a Slack app with 'chat:write', 'commands', and 'im:write' scopes plus an interactive components endpoint (webhook URL) to receive button-click responses.
  • Xero bill creation requires the supplier's contact_id from the Xero API, which must be stored in Airtable at onboarding time by the Contractor Onboarding Agent. Confirm this field is being written correctly before testing this agent.
  • Rate-matching tolerance is set to exact match by default. If the business allows rounding or GST-inclusive amounts, a tolerance percentage (e.g. plus or minus 1%) must be agreed and documented before build.
  • Confirm the next payment run date logic: fixed day of month, rolling 7-day cycle, or fortnightly. This determines how the Xero bill due date is calculated.
  • The finance manager's Slack user ID must be stored in a configuration table or environment variable, not hardcoded.
Compliance Monitor Agent

Runs on a daily schedule and queries the Airtable contractor records for any compliance document with an expiry date falling within the next 30 days. For each match, it sends a Slack message to the operations manager and a separate notification to the contractor's email address, including the document type, the exact expiry date, the number of days remaining, and a re-upload link pointing to the onboarding form or a dedicated upload endpoint. The agent does not take any automated action on expired documents; it alerts only, and the operations manager owns the follow-up. Complexity is rated Simple because it uses only two tools and contains no branching approval logic.

Trigger
Daily scheduled run (recommended: 08:00 local time, configurable)
Tools
Airtable, Slack
Replaces steps
3 (follow-up loop), 11
Estimated build
6 hours — Simple
// Input
Schedule.daily_trigger -> timestamp
Airtable.compliance_expiry_dates -> [
  {
    record_id: string,
    contractor_name: string,
    contractor_email: string,
    doc_type: string,
    expiry_date: date,
    days_remaining: integer  // computed: expiry_date - today
  }
] where days_remaining <= 30

// Output (per matching record)
Slack.message -> {
  channel: '#operations' | dm to ops_manager_slack_id,
  text: 'Compliance alert: {contractor_name} — {doc_type} expires on {expiry_date} ({days_remaining} days remaining). Re-upload link: {upload_url}'
}
Email.send -> {
  to: contractor_email,
  subject: 'Action required: {doc_type} expiring in {days_remaining} days',
  body: 'Please re-upload your {doc_type} before {expiry_date}. Link: {upload_url}'
}
  • Airtable must store compliance_expiry_dates as a Date field type, not a text field. If currently stored as text, a data migration step is required before this agent is built.
  • The upload_url in alerts must be confirmed: either a static Google Forms link or a pre-filled form URL that includes the contractor's record_id as a hidden field so the re-upload maps back to the correct Airtable row automatically.
  • Email sending for contractor-facing alerts requires a configured SMTP integration or a transactional email service (e.g. SendGrid or Gmail via OAuth). Confirm which service is available before build.
  • If a contractor has multiple compliance documents, the agent sends one alert per expiring document, not a bundled message. Confirm this behaviour is acceptable or adjust to a grouped-digest format.
  • Alert deduplication: the agent must not send the same alert to the same contractor more than once per day. Implement a 'last_alerted_date' field in Airtable and skip records already alerted today.
  • Ops manager Slack ID and email address must be stored in a configuration record or environment variable.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow — Contractor Management Automation
// ─────────────────────────────────────────────────────────────────
// TRIGGER: Google Forms submission received
// ─────────────────────────────────────────────────────────────────
GoogleForms.onSubmit -> {
  contractor_name,
  email,
  phone,
  abn_or_tax_id,
  bank_bsb,
  bank_account,
  agreed_rate_usd,
  engagement_start_date,
  hiring_manager_name,
  documents[]  // [{file_name, file_url, expiry_date}]
}

// ─────────────────────────────────────────────────────────────────
// AGENT 1: Contractor Onboarding Agent
// ─────────────────────────────────────────────────────────────────

// Step 1 — Dedupe check
Airtable.GET contractors WHERE email == form.email
  -> if record exists: UPDATE existing record
  -> if not found: proceed to CREATE

// Step 2 — Create Airtable record
Airtable.POST contractors -> {
  contractor_name,
  email,
  phone,
  abn_or_tax_id,
  agreed_rate_usd,
  engagement_start_date,
  hiring_manager_name,
  document_status: 'Pending',
  payment_status: null,
  xero_supplier_id: null,       // populated at step 4
  drive_folder_url: null,        // populated at step 3
  compliance_expiry_dates: []    // populated at step 3
}
-> record_id returned

// Step 3 — File documents to Google Drive
GoogleDrive.createFolder -> path: '/Contractors/{year}/{contractor_name}_{engagement_start_date}'
  -> folder_id, folder_url
for each document in form.documents:
  GoogleDrive.uploadFile(file_url) -> drive_file_id
Airtable.PATCH record_id -> {
  drive_folder_url: folder_url,
  document_status: 'Complete',
  compliance_expiry_dates: [{doc_type, expiry_date}]
}

// Step 4 — Create Xero supplier
Xero.POST contacts -> {
  name: contractor_name,
  emailAddress: email,
  phones: [{ PhoneType: 'DEFAULT', PhoneNumber: phone }],
  bankAccountDetails: { sortCode: bank_bsb, accountNumber: bank_account },
  isSupplier: true
}
-> xero_contact_id returned
Airtable.PATCH record_id -> { xero_supplier_id: xero_contact_id }

// Step 5 — Slack team notification
Slack.postMessage(channel='#operations') -> {
  text: 'New contractor active: {contractor_name} | Start: {engagement_start_date} | Rate: ${agreed_rate_usd}/day | HM: {hiring_manager_name}'
}

// ─────────────────────────────────────────────────────────────────
// AGENT 2: Invoice Approval and Payment Agent
// ─────────────────────────────────────────────────────────────────

// Trigger: new invoice email or form submission
InvoiceSource.detect -> {
  invoice_number,
  contractor_name,
  contractor_email,
  invoice_amount_usd,
  invoice_date,
  invoice_period,
  file_attachment_url
}

// Step 6 — Lookup contractor record
Airtable.GET contractors WHERE email == contractor_email
  -> { record_id, agreed_rate_usd, xero_supplier_id, hiring_manager_slack_id }

// Step 7 — Route for approval via Slack
Slack.postMessage(user=hiring_manager_slack_id) -> {
  text: 'Invoice received from {contractor_name}: ${invoice_amount_usd} for {invoice_period}.',
  actions: [{ id: 'approve', text: 'Approve' }, { id: 'query', text: 'Query' }]
}
await Slack.interactiveResponse -> { action_id: 'approve' | 'query' }

// Step 8 — Rate match decision
if invoice_amount_usd == agreed_rate_usd:
  // Step 9a — Create Xero bill
  Xero.POST invoices -> {
    type: 'ACCPAY',
    contact: { contactID: xero_supplier_id },
    lineItems: [{ description: invoice_period, unitAmount: invoice_amount_usd, quantity: 1 }],
    date: invoice_date,
    dueDate: next_payment_run_date,
    status: 'AUTHORISED'
  }
  -> xero_bill_id returned
  Airtable.PATCH record_id -> {
    payment_status: 'Scheduled',
    last_invoice_date: invoice_date,
    last_invoice_amount: invoice_amount_usd
  }
else:
  // Step 9b — Flag discrepancy
  Slack.postMessage(user=finance_manager_slack_id) -> {
    text: 'Discrepancy: {contractor_name} invoiced ${invoice_amount_usd}, agreed rate ${agreed_rate_usd}. Manual review required.'
  }
  Airtable.PATCH record_id -> {
    payment_status: 'Flagged',
    flag_reason: 'Amount mismatch — invoice: ${invoice_amount_usd}, agreed: ${agreed_rate_usd}'
  }
  // HUMAN STEP: Finance Manager reviews and resolves

// ─────────────────────────────────────────────────────────────────
// AGENT 3: Compliance Monitor Agent (daily schedule)
// ─────────────────────────────────────────────────────────────────

Schedule.daily(08:00) -> trigger
Airtable.GET contractors
  WHERE compliance_expiry_dates[].expiry_date <= (today + 30 days)
  AND last_alerted_date != today
-> [{ record_id, contractor_name, contractor_email, doc_type, expiry_date, days_remaining }]

for each expiring_doc:
  Slack.postMessage(channel='#operations' | user=ops_manager_slack_id) -> {
    text: 'Alert: {contractor_name} — {doc_type} expires {expiry_date} ({days_remaining} days). Re-upload: {upload_url}'
  }
  Email.send(to=contractor_email) -> {
    subject: '{doc_type} expiring in {days_remaining} days',
    body: 'Please re-upload before {expiry_date}. Link: {upload_url}'
  }
  Airtable.PATCH record_id -> { last_alerted_date: today }

// ─────────────────────────────────────────────────────────────────
// END OF AUTOMATED FLOW
// Retained human steps: Step 12 (offboarding), discrepancy resolution
// ─────────────────────────────────────────────────────────────────
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform (no specific tool mandated at this stage). Recommended structure: one workflow per agent (three workflows total), plus a shared credential store for all API keys and OAuth tokens. Each workflow is independently triggerable and testable.
Webhook configuration
Agent 1: incoming webhook endpoint registered in the automation platform to receive Google Forms POST submissions. Agent 2: outbound webhook or polling on the monitored Gmail label at a 5-minute interval; plus an interactive-components endpoint URL registered in the Slack app to receive approval button callbacks. Agent 3: no inbound webhook; uses a cron-style daily schedule trigger internal to the platform.
Templating approach
Slack message bodies and email subjects use parameterised string templates with named variables (e.g. {contractor_name}, {expiry_date}, {days_remaining}, {upload_url}). Templates are stored as editable constants in the workflow configuration, not hardcoded in logic nodes, so the operations manager can update wording without a rebuild.
Error logging
A dedicated Supabase table (table name: automation_error_log) captures every failed step with fields: workflow_name, step_name, error_message, payload_snapshot (JSON), timestamp, resolved (boolean). On any write to this table, a Slack alert fires to a private '#automation-errors' channel tagging the FullSpec on-call contact. Non-critical warnings (e.g. duplicate record detected, alert already sent today) are logged at info level only and do not trigger Slack alerts.
Testing approach
All agents are built and validated in sandbox environments first: Xero Demo Company for supplier and bill creation, a dedicated Airtable base named '[TEST] Contractors', a test Slack workspace channel '#automation-test', and a staging Google Form mapped to the test Airtable base. Production credentials are not used until UAT. Full end-to-end UAT runs with a live contractor onboarding scenario as per the QA Plan (FS-DOC-06).
Estimated total build time
Contractor Onboarding Agent: 12 hours. Invoice Approval and Payment Agent: 10 hours. Compliance Monitor Agent: 6 hours. End-to-end integration testing and UAT support: 10 hours (included in the 28-hour total build effort). Grand total: 28 hours across a 3 to 4 week delivery window.
Before build begins, the following must be confirmed and provided to FullSpec: (1) Xero OAuth credentials authorised by the finance manager against the live organisation, (2) Airtable base ID and table names for both production and test bases, (3) Google Forms field names matching the agreed schema, (4) Slack app created with required scopes and the interactive-components endpoint registered, (5) email service for contractor-facing alerts confirmed (Gmail OAuth or SendGrid API key), and (6) the upload_url to be included in compliance alerts. Any of these items outstanding at build-start will delay the corresponding agent. Contact support@gofullspec.com to submit credentials securely.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Contractor Management.

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