Back to Review & Reputation 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

Review and Reputation Management

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

This document is the primary technical reference for the FullSpec team building the Review and Reputation Management automation. It covers the current-state process map, agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. Everything required to configure, wire, and test each agent is contained here. The owner-facing documents cover rollout, training, and SOP; this pack covers construction.

01Process snapshot

Step
Name
Description
1
Check Review Platforms Manually
Marketing Coordinator logs into Google Business Profile, Trustpilot, and other platforms one at a time to look for new reviews. Done every two to three days and easily forgotten. Time cost: 20 min/cycle.
2
Copy Review Text into Tracker
New reviews are copied manually into Notion: star rating, reviewer name, platform, and date entered by hand. Time cost: 15 min/cycle.
3
Assess Sentiment and Urgency
Coordinator reads each review and makes a judgement call on sentiment and escalation need. No scoring system exists. Time cost: 10 min/cycle.
4
Escalate Negative Reviews to Manager
For one- or two-star reviews, the coordinator messages the manager via Slack or email. Manager must decide on approach before drafting begins. Time cost: 10 min/cycle.
5
Draft Response for Each Review
Coordinator writes a reply from scratch for every review, adjusting tone manually. No template system. Slow and inconsistent across team members. Time cost: 45 min/cycle.
6
Get Manager Approval on Negative Replies
Drafted negative responses are emailed to the manager for approval. Back-and-forth edits can add a full day to turnaround. Time cost: 20 min/cycle.
7
Post Response on Review Platform
Coordinator logs back into the relevant platform and manually posts the approved response. Session timeouts add friction. Time cost: 15 min/cycle.
8
Update CRM Contact Record
If the reviewer can be matched to a HubSpot contact, the coordinator updates the record. Skipped most of the time due to time pressure. Time cost: 10 min/cycle.
9
Log Completed Review in Tracker
Coordinator marks the review as responded in Notion and notes the approver and post date. Time cost: 5 min/cycle.
10
Compile Weekly Reputation Report
Manager manually pulls review volume, average rating, response rate, and complaint themes from the Notion tracker each week. Time cost: 30 min/cycle.
Time cost summary: 180 minutes (3 hours) of manual effort per full process cycle. At the observed volume of 60 to 120 reviews per month and a weekly cadence for reporting, this totals approximately 5 hours of manual work per week across the Marketing Coordinator and Marketing Manager. Steps 2, 3, 4, 5, 7, 8, 9, and 10 are fully replaced by automation. Step 6 (manager approval for negative reviews) is retained as a deliberate human gate. Step 1 (platform polling) is replaced by the scheduled trigger.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Review Classifier Agent

Reads each incoming review record and assigns a sentiment category (positive, neutral, or negative), a confidence score between 0 and 1, and a concise one-line topic summary. Its output fields determine which downstream branch the workflow follows: positive and neutral reviews proceed directly to the Response Drafting Agent, while negative reviews (two stars or below) trigger the Slack escalation path. This agent must handle all supported platform formats and gracefully degrade when review text is very short (under 10 words) or in a non-English language.

Trigger
A new review record is detected by the polling trigger (every 15 minutes) and passed to this agent. Fields received: platform, reviewer_name, star_rating, review_text, review_id, review_timestamp.
Tools
Google Business Profile (polling source), Trustpilot (polling source), Notion (write classified record to tracker database)
Replaces steps
Steps 2 and 3: Copy Review Text into Tracker; Assess Sentiment and Urgency
Estimated build
8 hours. Complexity: Moderate
// Input
platform: string          // 'google_business_profile' | 'trustpilot'
reviewer_name: string     // May be 'Anonymous' on some platforms
star_rating: integer      // 1-5
review_text: string       // Raw review body
review_id: string         // Platform-native unique ID (dedup key)
review_timestamp: string  // ISO 8601

// Output
sentiment: string         // 'positive' | 'neutral' | 'negative'
confidence_score: float   // 0.00-1.00
topic_summary: string     // Max 20 words, plain English
is_negative_flag: boolean // true if star_rating <= 2
notion_row_id: string     // ID of newly created Notion tracker row
classification_timestamp: string // ISO 8601
  • Google Business Profile API access requires a verified Business Profile account and the 'My Business API' scope enabled. Confirm this before build; some accounts are restricted to the Business Profile UI only.
  • Trustpilot access requires a Business account on at least the Lite paid tier to enable API read access. Free accounts do not expose review data via API. Confirm account tier with the owner before build.
  • Use review_id as the deduplication key. Before creating a Notion row, check the tracker for an existing row with the same review_id and platform combination. If found, skip and log a duplicate_skipped event.
  • If review_text is fewer than 10 words, set confidence_score to 0.5 and topic_summary to 'Short review, manual check recommended'. Do not block downstream flow.
  • If review_text is detected as non-English (use a lightweight language detection call), append lang_detected: '<code>' to the Notion row and set confidence_score to 0.4. Still pass downstream.
  • The Notion tracker database must have the following properties pre-created: Platform (select), ReviewerName (text), StarRating (number), ReviewText (text), Sentiment (select: positive/neutral/negative), ConfidenceScore (number), TopicSummary (text), IsNegative (checkbox), ResponseStatus (select: pending/approved/posted), ReviewID (text), CreatedAt (date). Confirm database ID before build.
  • Polling interval is every 15 minutes. Use the platform's 'updated_since' or 'start_date' parameter where available to avoid re-processing old reviews on each poll.
Response Drafting Agent

Generates a contextually appropriate reply for each review using the sentiment classification, star rating, review text, and brand voice guidelines stored in the agent's system prompt. Positive and neutral reviews receive an auto-approved draft that proceeds immediately to posting. Negative reviews (is_negative_flag: true) receive a draft that is packaged into a Slack message to the designated manager channel along with an approval link. The agent must not post any response autonomously for negative reviews under any circumstance. Brand voice guidelines must be loaded into the system prompt from a versioned source (a Notion page or a static prompt file in the credential store) so they can be updated without a code change.

Trigger
Classified review record received from the Review Classifier Agent. Required fields: sentiment, star_rating, review_text, topic_summary, is_negative_flag, notion_row_id.
Tools
Slack (send escalation alert with approval link for negative reviews), Gmail (post response via API for platforms that accept email-based replies), Google Business Profile (post response via API for GBP reviews)
Replaces steps
Steps 4, 5, and 7: Escalate Negative Reviews to Manager; Draft Response for Each Review; Post Response on Review Platform
Estimated build
12 hours. Complexity: Complex
// Input
sentiment: string          // From Review Classifier Agent output
star_rating: integer       // 1-5
review_text: string        // Raw review body
topic_summary: string      // From classifier
is_negative_flag: boolean  // Routing gate
notion_row_id: string      // For status update after action
platform: string           // Determines posting method
reviewer_name: string      // Used in response personalisation

// Output (positive/neutral path)
draft_response: string     // Brand-voice reply, max 300 characters
post_status: string        // 'posted' | 'failed'
posted_at: string          // ISO 8601
notion_row_id: string      // Passed to CRM and Reporting Agent

// Output (negative path — Slack escalation)
draft_response: string     // Draft included in Slack message
slack_message_ts: string   // Slack message timestamp (for threading)
approval_link: string      // Deep link to approval action
approval_status: string    // 'pending' | 'approved' | 'rejected'

// On approval (negative path, after manager action)
post_status: string        // 'posted' | 'failed'
posted_at: string          // ISO 8601
approved_by: string        // Slack user ID of approving manager
notion_row_id: string      // Passed to CRM and Reporting Agent
  • Brand voice guidelines must be stored in a dedicated Notion page (or a versioned prompt config file) and loaded into the system prompt at runtime. Never hardcode the brand voice text in the workflow definition. Confirm the owner has prepared this document before build begins; prompt tuning cannot proceed without it.
  • Allow at least one week of prompt tuning after initial build before enabling auto-posting for positive reviews. Run in draft-only mode first, reviewing outputs manually against the brand voice document.
  • The Slack escalation message must include: reviewer name, star rating, platform, review text (truncated to 500 characters), the AI draft response, and a single-click approve button and reject button using Slack interactive components (Block Kit). Slack interactivity requires a Request URL webhook configured in the Slack App manifest.
  • If the manager clicks Reject, the workflow must update the Notion row to ResponseStatus: 'manual_required' and send a follow-up Slack thread message prompting the manager to post a manual reply. Do not post the draft.
  • For Google Business Profile responses, use the My Business API v4.9 'accounts.locations.reviews.updateReply' endpoint. Confirm OAuth 2.0 credentials with the business_management scope are available.
  • For platforms accepting email-based replies (where GBP API is not available), use Gmail via the Gmail API 'users.messages.send' method. The reply-to address must be the platform-registered business email. Confirm this address with the owner.
  • Implement a retry with exponential backoff (3 attempts, 30s/60s/120s) on any posting failure. After three failures, set post_status to 'failed', update the Notion row, and send a Slack alert to the operations channel.
  • The draft_response character limit must respect each platform's reply limit: Google Business Profile allows up to 4,096 characters; set a soft cap of 300 characters for quality and readability. Trustpilot allows 3,000 characters.
CRM and Reporting Agent

Matches the reviewer to an existing HubSpot contact using name and email where available, then logs the review outcome as a timeline activity on the matched contact record. For anonymous reviews or platforms that mask reviewer details, the agent creates a partial record flagged for manual enrichment rather than skipping the step entirely. Additionally, every Monday at 08:00 local time this agent queries the Notion tracker for the prior week's data, compiles a reputation summary, and posts it to the designated Slack channel. The reporting function is time-triggered and independent of the per-review flow.

Trigger
Two triggers: (1) A response has been posted and the notion_row_id is passed from the Response Drafting Agent with post_status: 'posted'. (2) A weekly schedule trigger fires every Monday at 08:00 for the Slack report compilation.
Tools
HubSpot (contact search and timeline activity creation), Notion (query tracker for weekly data; update row completion status), Slack (post weekly reputation report)
Replaces steps
Steps 8, 9, and 10: Update CRM Contact Record; Log Completed Review in Tracker; Compile Weekly Reputation Report
Estimated build
6 hours. Complexity: Moderate
// Input (per-review trigger)
notion_row_id: string      // Completed review row
reviewer_name: string      // Used for HubSpot contact search
reviewer_email: string     // May be null for anonymous reviews
platform: string
star_rating: integer
sentiment: string
post_status: string        // Must be 'posted' to proceed
posted_at: string          // ISO 8601
approved_by: string        // Slack user ID or null for auto-posted

// Input (weekly schedule trigger)
report_week_start: string  // ISO 8601 date, Monday
report_week_end: string    // ISO 8601 date, Sunday

// Output (per-review)
hubspot_contact_id: string // Matched contact ID or 'partial_record_created'
hubspot_activity_id: string // Timeline activity ID
notion_row_updated: boolean // True when ResponseStatus set to 'posted'

// Output (weekly report)
slack_report_ts: string    // Slack message timestamp
report_summary: object     // { total_reviews, avg_rating, response_rate_pct,
                           //   sentiment_breakdown: {positive, neutral, negative},
                           //   top_complaint_themes: string[] }
  • HubSpot contact search uses the CRM Search API v3 endpoint 'crm/v3/objects/contacts/search'. Search by email first; if null or no match, search by firstname and lastname combined. Require a confidence threshold of 90% name match before associating to avoid false positives.
  • If no HubSpot contact is matched, create a new contact with available fields (reviewer_name split into firstname/lastname, platform as a custom property 'review_source') and set a custom property 'review_match_status' to 'partial_unverified'. Do not block the workflow.
  • HubSpot timeline activity is created as a Note on the contact record using the Engagements API v1 'engagements/v1/engagements'. Include: platform, star_rating, sentiment, topic_summary, posted_at, and a link to the Notion row. HubSpot CRM API requires a private app token with contacts.read, contacts.write, and crm.objects.contacts.write scopes.
  • The weekly Slack report must cover: total reviews detected in the week, average star rating, response rate as a percentage, sentiment breakdown (count per category), and up to three recurring complaint themes derived from topic_summary fields. Use a Slack Block Kit formatted message with section headers for readability.
  • Notion query for the weekly report uses the database filter: CreatedAt is on or after report_week_start AND on or before report_week_end. Sort descending by CreatedAt. Page through results if count exceeds 100 (Notion API page size limit).
  • Confirm the HubSpot account tier supports the CRM API and timeline activity creation. Operations Hub Starter or above is required for some timeline features. Confirm with the owner before build.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full end-to-end data flow: trigger to Slack report. Field names match Notion DB properties and agent IO contracts above.
// ============================================================
// REVIEW AND REPUTATION MANAGEMENT: END-TO-END DATA FLOW
// ============================================================

// TRIGGER: Scheduled polling (every 15 minutes)
// Source: Google Business Profile API + Trustpilot API
// Fields captured at trigger:
platform          = 'google_business_profile' | 'trustpilot'
reviewer_name     = string   // e.g. 'Jane Smith' | 'Anonymous'
star_rating       = integer  // 1-5
review_text       = string   // Raw review body
review_id         = string   // Platform-native UID (dedup key)
review_timestamp  = string   // ISO 8601

// DEDUP CHECK: Query Notion tracker for existing review_id + platform
// If match found -> log duplicate_skipped, end workflow
// If no match -> continue

// ============================================================
// AGENT HANDOFF 1: Trigger -> Review Classifier Agent
// Fields passed: platform, reviewer_name, star_rating,
//                review_text, review_id, review_timestamp
// ============================================================

// REVIEW CLASSIFIER AGENT processing:
sentiment            = 'positive' | 'neutral' | 'negative'
confidence_score     = float    // 0.00-1.00
topic_summary        = string   // Max 20 words
is_negative_flag     = boolean  // true if star_rating <= 2

// ACTION: Write classified record to Notion tracker
// Notion DB properties written:
notion_row_id        = string   // Returned by Notion API on create
Platform             = platform
ReviewerName         = reviewer_name
StarRating           = star_rating
ReviewText           = review_text
Sentiment            = sentiment
ConfidenceScore      = confidence_score
TopicSummary         = topic_summary
IsNegative           = is_negative_flag
ResponseStatus       = 'pending'
ReviewID             = review_id
CreatedAt            = review_timestamp

// ============================================================
// AGENT HANDOFF 2: Review Classifier Agent -> Response Drafting Agent
// Fields passed: sentiment, star_rating, review_text,
//                topic_summary, is_negative_flag, notion_row_id,
//                platform, reviewer_name
// ============================================================

// RESPONSE DRAFTING AGENT processing:
// Load brand voice guidelines from Notion config page at runtime
draft_response = string  // Max 300 chars, platform-appropriate tone

// BRANCH A: is_negative_flag == false (positive or neutral)
//   -> Post response directly to platform
//   -> GBP: My Business API v4.9 'accounts.locations.reviews.updateReply'
//   -> Gmail API: 'users.messages.send' for email-reply platforms
post_status      = 'posted' | 'failed'
posted_at        = string   // ISO 8601
//   -> On failure: retry x3 (30s/60s/120s), then alert ops Slack channel
//   -> Update Notion row: ResponseStatus = 'posted'

// BRANCH B: is_negative_flag == true (2 stars or below)
//   -> Send Slack Block Kit message to manager channel
slack_message_ts   = string  // For threading
approval_link      = string  // Interactive component action URL
approval_status    = 'pending'
//   -> Manager clicks Approve:
approved_by        = string  // Slack user ID
approval_status    = 'approved'
post_status        = 'posted' | 'failed'
posted_at          = string  // ISO 8601
//   -> Update Notion row: ResponseStatus = 'posted'
//   -> Manager clicks Reject:
approval_status    = 'rejected'
//   -> Update Notion row: ResponseStatus = 'manual_required'
//   -> Send Slack thread: prompt manager to post manually

// ============================================================
// AGENT HANDOFF 3: Response Drafting Agent -> CRM and Reporting Agent
// Triggered only when post_status == 'posted'
// Fields passed: notion_row_id, reviewer_name, reviewer_email,
//                platform, star_rating, sentiment,
//                post_status, posted_at, approved_by
// ============================================================

// CRM AND REPORTING AGENT processing (per-review):
// Step 1: Search HubSpot by reviewer_email (primary)
//         Fallback: search by firstname + lastname (>=90% match required)
hubspot_contact_id  = string  // Matched ID or 'partial_record_created'

// Step 2: Create HubSpot timeline activity (Engagements API v1)
hubspot_activity_id = string
// Activity fields: platform, star_rating, sentiment,
//                  topic_summary, posted_at, notion_row link

// Step 3: Update Notion row
// ResponseStatus = 'posted'
notion_row_updated  = boolean

// ============================================================
// WEEKLY SCHEDULE TRIGGER: Every Monday 08:00 local time
// -> CRM and Reporting Agent (reporting function)
// ============================================================

// Query Notion tracker: CreatedAt >= report_week_start
//                        AND CreatedAt <= report_week_end
report_summary = {
  total_reviews:         integer,
  avg_rating:            float,
  response_rate_pct:     float,
  sentiment_breakdown:   { positive: int, neutral: int, negative: int },
  top_complaint_themes:  string[]   // Max 3 items from topic_summary
}

// Post Slack Block Kit report to #marketing channel
slack_report_ts = string  // Slack message timestamp

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

04Recommended build stack

Orchestration layer
A workflow automation tool with native HTTP, AI/LLM, and scheduling node support. Structure as three discrete workflows, one per agent, sharing a single centralised credential store. Keep agent workflows loosely coupled: the Classifier workflow calls the Drafting workflow via an internal webhook; the Drafting workflow calls the CRM workflow on post_status == 'posted'. This separation allows individual agents to be tested, redeployed, or swapped without affecting the full pipeline.
Webhook configuration
Two inbound webhooks are required. (1) Slack Interactive Components endpoint: receives the manager approve/reject payload from the negative review Slack message. Must be registered as the Request URL in the Slack App manifest under 'Interactivity and Shortcuts'. Respond with HTTP 200 within 3 seconds; use an async handler for posting logic. (2) Internal agent-to-agent webhook (Classifier to Drafting): a private URL with a shared secret header (X-Internal-Secret) to prevent unauthorised calls. Rotate the secret as part of go-live checklist.
Templating approach
Brand voice guidelines are stored in a dedicated Notion page (page ID stored as an environment variable BRAND_VOICE_NOTION_PAGE_ID). The orchestration layer fetches the page content at the start of each Response Drafting Agent run and injects it into the LLM system prompt. This avoids hardcoding and lets the owner update guidelines without a workflow change. A fallback static prompt string is stored as an environment variable BRAND_VOICE_FALLBACK and used if the Notion fetch fails. Slack report layout uses a reusable Block Kit JSON template stored as an environment variable or a static JSON file in the credential store.
Error logging
All workflow errors, retry events, dedup skips, posting failures, and partial HubSpot matches are written to a dedicated Supabase table (table: automation_error_log). Schema: id (uuid), workflow_name (text), error_type (text), review_id (text), platform (text), error_message (text), occurred_at (timestamptz), resolved (boolean). A Supabase database webhook triggers a Slack alert to the #ops-alerts channel when a new row is inserted with resolved = false. Posting failures and CRM match failures are flagged as amber; workflow crashes are flagged as red with @channel mention.
Testing approach
All three agents are built and tested in a sandbox environment first using fixture review payloads (one per sentiment category, one short review, one non-English review, one anonymous reviewer). Sandbox Notion, HubSpot sandbox account, and a test Slack workspace are used throughout. The Slack interactive approval flow is tested with a staging webhook URL before swapping to production. A two-week parallel run alongside the manual process is completed before the manual workflow is retired, with the FullSpec team reviewing Notion tracker output daily. See the Test and QA Plan (FS-DOC-06) for full test case matrix.
Estimated total build time
Review Classifier Agent: 8 hours. Response Drafting Agent: 12 hours. CRM and Reporting Agent: 6 hours. End-to-end integration testing and parallel run validation: 2 hours. Total: 28 hours.
Credential checklist before build begins: Google Business Profile OAuth 2.0 client ID and secret (scope: business_management); Trustpilot API key (Business account, Lite tier or above confirmed); Slack Bot Token and Signing Secret (scopes: chat:write, chat:write.public, commands, interactivity enabled); HubSpot Private App Token (scopes: contacts.read, contacts.write, crm.objects.contacts.write, engagements.write); Notion Integration Token (access to tracker database and brand voice page); Gmail OAuth 2.0 credentials (scope: gmail.send, business reply-to address confirmed); Supabase project URL and service role key (for error log writes). All credentials are stored in the automation platform's shared credential store and referenced by environment variable name only. No credential values are hardcoded in any workflow node.
Three build constraints require owner confirmation before any build work begins: (1) Trustpilot account tier must be Lite or above for API read access. (2) Brand voice guidelines document must be complete and loaded into the designated Notion page before the Response Drafting Agent prompt tuning phase. (3) The HubSpot account must be on a tier that supports the Engagements API and timeline activity creation. Contact support@gofullspec.com once all three are confirmed and the FullSpec team will schedule the build start.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Review & Reputation 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