Google Review Response Automation
The Problem
Reviews sit unanswered for weeks or get identical copy-paste replies. Both hurt your SEO and your credibility with potential customers. This automation reads each review, drafts a unique AI response matching the sentiment, and routes sensitive ones to a human.
How It Works
New Google review notification
AI reads sentiment and specifics. Drafts unique response. Positive: thanks with job reference. Negative: empathetic with offline offer. Routes sensitive ones to human.
Every review responded to within hours. Response rate: 10% to 100%. Local SEO boosted.
Importable Templates
PRD
# Product Requirements Document
## Recipe 005 — Review Responder
### AI Trades Platform
---
Recipe Slug: `review-responder`
Recipe Number: 005
Difficulty: Replit Build
Time Estimate: 6–8 hours
Category: Reputation & Reviews
Revenue Impact: $1,200–4,800/mo (retained customers from fast, quality responses)
Hours Saved: 5 hrs/wk
Replaces: Manual review replies + reputation management services ($200–800/mo)
Reusable Modules Referenced:
- Module 0: UX Philosophy (`modules/ux-philosophy-module.md`) — foundational design principles for all screens
- Module: Brand Voice Engine (`modules/brand-voice-engine-module.md`) — voice profiling, tone matching, anti-AI writing
- Module: Review Inbox (`modules/review-inbox-module.md`) — review cards, filters, bulk queue, dashboard metrics
- Module 9: Onboarding Wizard (`modules/onboarding-wizard-module.md`) — multi-step first-run setup
- Module 10: Settings Panel (`modules/settings-panel-module.md`) — centralized settings management
- Module 11: Notification / Toast (`modules/notification-toast-module.md`) — toasts, badges, notification center
- Module 12: Data Table / List View (`modules/data-table-list-view-module.md`) — review list with sorting, filtering
Integration Docs (include with build):
- Google Business Profile (`integrations/google-business-profile.md`) — OAuth, review fetching, reply posting, manual fallback
- Google OAuth (`integrations/google-oauth.md`) — shared OAuth patterns for GBP connection
- OpenAI / Anthropic (`integrations/openai-anthropic.md`) — LLM for review response generation
---
## Table of Contents
4. Multi-Shot Learning from User Edits
5. Google Business Profile Connection
9. Data Model
11. Technical Stack
---
1. Recipe Overview
The Review Responder pulls Google Business Profile reviews, generates human-sounding AI replies using the contractor's actual voice, and lets the contractor edit, approve, and post responses — all from their phone.
The key differentiator: Every time the contractor edits an AI-generated response, that edit becomes a new multi-shot example for the AI. The system gets smarter with every use. After 10–15 edits, the AI writes responses that need zero editing.
Key Capabilities:
- Connect to Google Business Profile via OAuth (with manual fallback)
- Pull reviews automatically on a polling interval
- Generate AI responses using anti-AI writing guidelines + contractor's brand voice
- Contractor edits the response → that edit trains the AI (multi-shot learning)
- Post approved responses back to Google (if API access) or copy-to-clipboard
- Track response rate, average rating, and response quality over time
- Multi-language support (reviews and responses)
- Full PostgreSQL backend with authentication and storage
---
2. Strategy Brief
The Core Problem & Solution Logic
The Pain: "I know I should reply to every review but I don't have time and when I do reply it sounds stiff or like a robot wrote it."
The Diagnosis: Time friction + voice mismatch. Contractors know review responses matter for SEO and customer trust, but writing individual responses takes 5–10 minutes each, and AI tools produce output that sounds obviously generated.
The Product Fix: A review inbox that shows every new review as a card, generates a response that sounds like the contractor actually wrote it, and learns from every edit the contractor makes so it gets better over time. The contractor's job is reduced to: read, tweak if needed, approve. 30 seconds per review.
Feature Expansion
- Standard Approach: "AI writes a review response."
- Strategic Approach: AI writes a response using the contractor's actual phrases, greeting style, humor patterns, and regional language — trained from their real communications and refined by every edit they make. The system maintains a rolling window of the contractor's best approved responses as few-shot examples.
- Reasoning: The #1 reason contractors stop using AI response tools is that the output doesn't sound like them. Multi-shot learning from edits solves this permanently.
Screen/UI Implications
- Onboarding wizard: connect GBP → set language → analyze voice (from website or pasted messages)
- Review inbox: card-based, mobile-first, single-column scroll
- Response panel: review on top, AI response below in editable textarea, approve/edit/regenerate/copy actions
- Settings: language selector, GBP connection status, voice profile editor
Automation Strategy
- Poll GBP for new reviews every 15 minutes (configurable)
- Auto-generate draft responses for new reviews
- Push notification when new review arrives (especially 1–2 star)
- Weekly summary: reviews received, response rate, avg rating trend
---
3. Anti-AI Writing System
The Problem with AI-Generated Responses
AI responses fail a human "smell test" because of predictable patterns:
| AI Tell | Example | Why It Fails |
|---|---|---|
| Opening with gratitude cliché | "Thank you so much for your wonderful review!" | Every AI tool writes this exact sentence |
| Exclamation mark overuse | "We're so glad! Thank you! We look forward to serving you again!" | Real people don't punctuate like this |
| Corporate filler phrases | "We strive to provide exceptional service" | No contractor talks like this |
| Mirroring the review robotically | "We're glad the technician was on time and the repair was done correctly" | Reads like a receipt, not a person |
| Perfect grammar | Zero contractions, no sentence fragments | Real people write "glad we could help" not "We are glad that we were able to assist" |
| Sign-off formula | "We look forward to serving you again in the future!" | Identical across every AI response tool |
Anti-AI Writing Rules (Embedded in System Prompt)
```
ANTI-AI WRITING RULES — MANDATORY
You are writing a review response that must pass as written by a real human contractor.
The following patterns are BANNED. If your output contains any of these, it has failed.
BANNED OPENINGS:
- "Thank you so much for..." (any variation)
- "We truly appreciate..."
- "We're so grateful..."
- "It means the world to us..."
- "We're thrilled to hear..."
BANNED PHRASES:
- "strive to provide"
- "exceptional service"
- "your kind words"
- "look forward to serving you again"
- "don't hesitate to reach out"
- "means a lot to our team"
- "we take pride in"
- "your satisfaction is our priority"
- "valued customer"
- "top-notch"
- "go above and beyond"
- "rest assured"
BANNED PATTERNS:
- More than 1 exclamation mark per response
- Starting with "Thank you" (can thank later in the response, but not as the opener)
- Mirroring the review content back word-for-word
- Using the reviewer's name more than once
- Perfect parallel structure (e.g., "Whether it's X, Y, or Z, we...")
- Ending with "We look forward to..." anything
REQUIRED HUMAN SIGNALS:
- Use contractions ("we're" not "we are", "didn't" not "did not")
- At least one sentence fragment or casual aside is OK
- Keep it under 3 sentences for 5-star reviews (real people don't write essays for good reviews)
- For negative reviews: lead with acknowledging the specific issue, NOT with an apology template
- Reference a specific detail from the review naturally, don't mirror it
- Match the contractor's actual greeting style (loaded from voice profile)
- Match the contractor's actual sign-off (loaded from voice profile)
RESPONSE LENGTH GUIDELINES:
- 5-star reviews: 1–3 sentences. Short and genuine. Like texting back "thanks man, appreciate it"
- 4-star reviews: 2–4 sentences. Acknowledge, maybe address what they noted
- 3-star reviews: 3–5 sentences. Acknowledge the mixed experience, show you heard them
- 1-2 star reviews: 4–6 sentences. Lead with the specific issue, show empathy, offer resolution path (phone number)
EXAMPLES OF GOOD RESPONSES (for calibration):
5-star review about a plumber fixing a leak:
"Glad we could get that sorted for you, Mike. That pipe had seen better days — good thing you caught it when you did."
4-star review about HVAC install:
"Appreciate the kind words, Sarah. Sorry about the scheduling mixup on day one — we've tightened that up. AC should treat you well for a long time."
1-star review about a no-show:
"Jim, that's on us and I'm sorry. We had a crew emergency that morning and should have called you. I'd like to make it right — give me a ring at (555) 123-4567 and we'll get you taken care of."
```
How Anti-AI Rules Integrate with Brand Voice
The anti-AI rules are the foundation. The Brand Voice Engine (from the module) layers the contractor's specific patterns ON TOP:
```
System Prompt Assembly Order:
1. Anti-AI Writing Rules (banned phrases, required signals)
2. Brand Voice Profile (tone, formality, key phrases, greetings, closings)
3. Multi-Shot Examples (contractor's approved/edited responses)
4. Review Context (star rating, review text, reviewer name, extracted service type)
5. Tone Directive (auto-detected from rating, overridable by contractor)
```
---
4. Multi-Shot Learning from User Edits
How It Works
Every time the contractor interacts with an AI-generated response, the system captures the interaction for future prompt improvement.
Interaction Types & Learning
| Interaction | What We Store | How It Trains |
|---|---|---|
| Approve without editing | Original review + AI response + "approved_as_is: true" | This is a good example — add to few-shot pool |
| Edit then approve | Original review + AI draft + contractor's edited version | The EDITED version becomes the few-shot example. The AI draft is stored for comparison but never used as an example. |
| Regenerate | Review + original draft + regeneration count | Signals the first draft was bad. Not used as example. |
| Skip | Review + skip reason (if provided) | Not used as example |
Few-Shot Example Selection
When generating a new response, the system selects the best few-shot examples:
```
Selection Criteria (in priority order):
1. Same star rating as the current review (exact match)
2. Similar service type mentioned (if extractable)
3. Most recent examples first (voice may evolve)
4. Maximum 5 examples in the prompt (balances quality vs. token cost)
5. Prefer edited examples over approved-as-is (edits show the contractor's preferences)
```
Database Schema for Learning
```sql
CREATE TABLE response_examples (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
review_id UUID NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,
-- The review context
star_rating INTEGER NOT NULL,
review_text TEXT,
reviewer_name TEXT,
extracted_service_type TEXT,
-- The response
ai_draft_text TEXT NOT NULL,
final_text TEXT NOT NULL,
was_edited BOOLEAN NOT NULL DEFAULT FALSE,
approved_as_is BOOLEAN NOT NULL DEFAULT FALSE,
-- Metadata
tone_used TEXT,
model_used TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(review_id)
);
CREATE INDEX idx_examples_rating ON response_examples(star_rating);
CREATE INDEX idx_examples_recent ON response_examples(created_at DESC);
```
Prompt Assembly with Multi-Shot Examples
```
System: You are writing a review response for {{BUSINESS_NAME}}.
{{ANTI_AI_WRITING_RULES}}
{{BRAND_VOICE_PROFILE}}
Here are examples of responses that {{CONTRACTOR_FIRST_NAME}} has approved:
---
EXAMPLE 1:
Review ({{EXAMPLE_1_STARS}}★): "{{EXAMPLE_1_REVIEW_TEXT}}"
{{CONTRACTOR_FIRST_NAME}}'s response: "{{EXAMPLE_1_FINAL_TEXT}}"
EXAMPLE 2:
Review ({{EXAMPLE_2_STARS}}★): "{{EXAMPLE_2_REVIEW_TEXT}}"
{{CONTRACTOR_FIRST_NAME}}'s response: "{{EXAMPLE_2_FINAL_TEXT}}"
---
Now write a response for this review:
Review ({{CURRENT_STARS}}★) by {{REVIEWER_NAME}}: "{{REVIEW_TEXT}}"
Tone: {{SELECTED_TONE}}
Max length: {{MAX_RESPONSE_LENGTH}} characters
```
UI for the Edit-and-Learn Flow
```
┌─────────────────────────────────────────────────────────────┐
│ ★★★★★ Mike Johnson 2 days ago │
│ ────────────────────────────────────────────────────────── │
│ "Great experience! They fixed our water heater same day. │
│ Tech was really knowledgeable and fair price." │
│ │
│ ┌─ YOUR RESPONSE ──────────────────────────────────────┐ │
│ │ │ │
│ │ Appreciate it, Mike — same-day was tight but glad │ │
│ │ we made it work. Water heaters are our bread and │ │
│ │ butter. Holler if you need anything. │ │
│ │ │ │
│ │ (editable — your changes teach the AI your style) │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ℹ️ Every edit you make helps the AI learn your voice. │ │
│ │ After a few edits, responses will sound just like │ │
│ │ you wrote them. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ [ 🔄 Regenerate ] [ 📋 Copy ] [ ✅ Approve & Post ] │
└─────────────────────────────────────────────────────────────┘
```
Key UX detail: A subtle info banner explains "Every edit you make helps the AI learn your voice" — this encourages contractors to edit instead of regenerating, which produces better training data.
---
5. Google Business Profile Connection
Connection Flow (Onboarding Step 1)
Primary Path: Google OAuth
```
1. Contractor clicks "Connect Google Business Profile"
2. OAuth consent screen with scope: business.manage
3. On callback: exchange code for tokens, store in database
4. Discover accounts → list locations → contractor picks their business
5. Store account_id + location_id
6. Test API access by fetching 1 review
7. If successful: "Connected! We found [X] reviews."
8. If 403 (no API access): graceful fallback to manual mode
```
Fallback Path: Manual Mode
If GBP API access is denied (common for small apps), the system switches to manual mode:
```
┌─────────────────────────────────────────────────────────────┐
│ Google API access isn't available for your account yet. │
│ No worries — you can still use everything. │
│ │
│ Here's how it works: │
│ 1. We'll give you a link to your Google reviews page │
│ 2. When you get a new review, paste it in here │
│ 3. We generate a response, you copy it back to Google │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Your Google Place ID: [________________] │ │
│ │ │ │
│ │ (Find this by searching your business on Google │ │
│ │ Maps and copying the place_id from the URL) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ [ Save & Continue ] │
└─────────────────────────────────────────────────────────────┘
```
Google Cloud Setup Instructions (Shown in Onboarding)
```
┌─────────────────────────────────────────────────────────────┐
│ 📋 Google Cloud Setup (one-time, ~10 minutes) │
│ ────────────────────────────────────────────────────────── │
│ │
│ Step 1: Go to console.cloud.google.com │
│ Create a new project (or use existing) │
│ │
│ Step 2: Enable these APIs: │
│ • My Business Account Management API │
│ • My Business Business Information API │
│ • My Business Reviews API (this is separate!) │
│ │
│ Step 3: Create OAuth credentials │
│ • Application type: Web application │
│ • Authorized redirect URI: │
│ https://{{APP_DOMAIN}}/api/auth/google/callback │
│ │
│ Step 4: Copy your Client ID and Client Secret │
│ Paste them below: │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Client ID: [________________________________] │ │
│ │ Client Secret: [________________________________] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Step 5: Apply for GBP API access │
│ (link to form — approval takes 2-6 weeks) │
│ Don't wait for this — we'll use manual mode until │
│ it's approved. │
│ │
│ [ Connect with Google ] │
└─────────────────────────────────────────────────────────────┘
```
Token Management
- Store tokens encrypted in the database (`google_business_tokens` table)
- Auto-refresh access tokens 5 minutes before expiry
- If refresh fails (token revoked): notify contractor, switch to manual mode
- See `integrations/google-business-profile.md` Section 2 for full token refresh implementation
---
6. Onboarding Flow
Onboarding Wizard Steps
```
Step 1: Connect Google Business Profile
→ OAuth flow or manual Place ID entry
→ Outcome: GBP connected or manual mode configured
Step 2: Set Language
→ Dropdown: English, Spanish, French, Portuguese, German, etc.
→ "What language do your customers leave reviews in?"
→ "What language should responses be written in?"
→ Can be different (e.g., reviews in Spanish, responses in Spanish)
Step 3: Build Your Voice Profile
→ Option A: "Grab My Website" (paste URL, system scrapes copy)
→ Option B: "Paste My Messages" (paste 3-5 real messages you've sent)
→ System analyzes and builds voice profile
→ Contractor reviews: tone chips, formality slider, key phrases
→ Confirm or re-analyze
Step 4: First Review Test
→ System pulls most recent review (or contractor pastes one)
→ AI generates a response using voice profile + anti-AI rules
→ Contractor sees the result: "Does this sound like you?"
→ If yes: "Great, you're all set."
→ If no: "Edit it how you'd want it — that teaches the AI."
```
Onboarding UI
```
┌─────────────────────────────────────────────────────────────┐
│ │
│ ●━━━○━━━○━━━○ │
│ Step 1 of 4 │
│ │
│ Connect Your Google Reviews │
│ │
│ We'll pull your reviews automatically so you can respond │
│ in seconds instead of minutes. │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 🔗 Connect Google Business Profile │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ or │
│ │
│ [ I'll add reviews manually for now → ] │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
7. Review Inbox & Response UI
Core Flow
```
Contractor opens app
→ Sees review inbox (cards, newest first)
→ Unresponded reviews have amber badge, low-rating reviews have red left border
→ Taps a review card
→ Card expands to show full review + AI-generated response
→ Contractor reads response, optionally edits
→ Taps "Approve & Post" (if API connected) or "Copy Response" (manual mode)
→ Card moves to "Responded" status
→ If contractor edited: the edited version is saved as a training example
```
Review + Response Display
Feature: Review Card with Response Panel
- Visual: Card with star rating, reviewer name, date, review preview. On tap, expands to show full review text + editable response textarea below.
- Trigger: Contractor taps the review card.
- Condition: Review must have status "unresponded" or "pending" (draft exists).
- Result: Card expands inline. If no draft exists, API call generates one. Response appears in editable textarea with typewriter streaming effect.
Feature: Edit Response
- Visual: Textarea with the AI response. Blue "editing" border when focused. Character count shown below.
- Trigger: Contractor taps into the textarea and modifies text.
- Condition: Response must be in draft state (not yet posted).
- Result: Text is editable. "Approve" button text changes to "Approve Edited Response". On approve, the edited text is saved as a multi-shot example with `was_edited: true`.
Feature: Approve & Post
- Visual: Green primary button "Approve & Post" (API mode) or "Copy & Mark Done" (manual mode).
- Trigger: Contractor taps the button.
- Condition: Response text is not empty. If API mode, valid Google token exists.
- Result (API mode): Response posted to Google via GBP API. Status → "Responded". Toast: "Response posted to Google."
- Result (Manual mode): Response copied to clipboard. Status → "Responded". Toast: "Copied! Paste this in Google."
Feature: Regenerate
- Visual: Secondary button with refresh icon. "Regenerate" label.
- Trigger: Contractor taps regenerate.
- Condition: Always available on unresponded reviews.
- Result: New API call with same inputs. Old draft saved to history. New response streams into textarea. Regeneration count incremented (used to track AI quality).
Dashboard Metrics
Follow `modules/review-inbox-module.md` Section 4. Two primary metrics:
1. Response Rate — X of Y reviews responded (percentage bar, green/amber/red)
2. Average Rating — Star average with trend indicator vs. previous period
---
8. Settings & Language
Language Settings
Feature: Response Language Selector
- Visual: Dropdown in Settings page. Label: "Response Language". Options: English, Spanish (Español), French (Français), Portuguese (Português), German (Deutsch), Italian (Italiano), Dutch (Nederlands), Japanese (日本語), Korean (한국어), Chinese Simplified (简体中文).
- Trigger: Contractor selects a language.
- Condition: N/A.
- Result: All AI-generated responses will be written in the selected language. The system prompt includes: "Write the response in {{SELECTED_LANGUAGE}}." Existing drafts are NOT re-generated. Only new responses use the updated language.
Feature: Review Language Detection
- Visual: Small language badge on review cards (e.g., "ES" for Spanish review).
- Trigger: Automatic on review import.
- Condition: Review text is not empty.
- Result: System detects the review language. If different from response language, a subtle note appears: "This review is in Spanish. Your response will be in Spanish." (matches the review language by default, overridable in settings).
Settings Page Layout
```
┌─────────────────────────────────────────────────────────────┐
│ ⚙️ Settings │
│ ────────────────────────────────────────────────────────── │
│ │
│ GOOGLE CONNECTION │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ● Connected to: Joe's Plumbing - Downtown │ │
│ │ Last synced: 5 minutes ago │ │
│ │ [ Disconnect ] [ Sync Now ] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ LANGUAGE │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Response Language: [ English ▾ ] │ │
│ │ │ │
│ │ Auto-match review language: [ ✓ On ] │ │
│ │ (Responds in the same language as the review) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ YOUR VOICE │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Voice Profile: Active (last updated 3 days ago) │ │
│ │ Training Examples: 12 approved responses │ │
│ │ [ Edit Voice Profile ] [ View Training Examples ] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ REVIEW SYNC │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Check for new reviews every: [ 15 minutes ▾ ] │ │
│ │ Auto-generate draft responses: [ ✓ On ] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
9. Data Model
Migration Script
```sql
-- migrations/001_review_responder.sql
-- Business settings
CREATE TABLE business_settings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
business_name TEXT NOT NULL,
trade_type TEXT,
phone TEXT,
website_url TEXT,
google_place_id TEXT,
response_language TEXT DEFAULT 'en',
auto_match_language BOOLEAN DEFAULT TRUE,
review_sync_interval_minutes INTEGER DEFAULT 15,
auto_generate_drafts BOOLEAN DEFAULT TRUE,
onboarding_completed BOOLEAN DEFAULT FALSE,
onboarding_step INTEGER DEFAULT 1,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Google Business Profile tokens
CREATE TABLE google_business_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
access_token TEXT NOT NULL,
refresh_token TEXT,
token_expires_at TIMESTAMPTZ NOT NULL,
gbp_account_id TEXT,
gbp_location_id TEXT,
api_access_verified BOOLEAN DEFAULT FALSE,
connection_mode TEXT DEFAULT 'manual' CHECK (connection_mode IN ('api', 'manual')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Voice profiles
CREATE TABLE voice_profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
profile_data JSONB NOT NULL DEFAULT '{}'::jsonb,
analysis_sources JSONB DEFAULT '{}'::jsonb,
confirmed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Reviews
CREATE TABLE reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('manual', 'google_api', 'import')),
google_review_id TEXT UNIQUE,
platform TEXT NOT NULL DEFAULT 'google',
reviewer_name TEXT NOT NULL,
star_rating INTEGER NOT NULL CHECK (star_rating BETWEEN 1 AND 5),
review_text TEXT,
review_language TEXT DEFAULT 'en',
review_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status TEXT NOT NULL DEFAULT 'unresponded' CHECK (
status IN ('unresponded', 'pending', 'responded', 'skipped')
),
ai_draft_text TEXT,
final_response_text TEXT,
response_language TEXT,
reply_posted_at TIMESTAMPTZ,
reply_posted_via TEXT CHECK (reply_posted_via IN ('api', 'manual_copy')),
was_edited BOOLEAN DEFAULT FALSE,
regeneration_count INTEGER DEFAULT 0,
tone_used TEXT,
model_used TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_reviews_date ON reviews(review_date DESC);
CREATE INDEX idx_reviews_status ON reviews(status);
CREATE INDEX idx_reviews_unreplied ON reviews(id) WHERE status = 'unresponded';
-- Response examples (multi-shot learning)
CREATE TABLE response_examples (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
review_id UUID NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,
star_rating INTEGER NOT NULL,
review_text TEXT,
reviewer_name TEXT,
extracted_service_type TEXT,
ai_draft_text TEXT NOT NULL,
final_text TEXT NOT NULL,
was_edited BOOLEAN NOT NULL DEFAULT FALSE,
approved_as_is BOOLEAN NOT NULL DEFAULT FALSE,
tone_used TEXT,
model_used TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(review_id)
);
CREATE INDEX idx_examples_rating ON response_examples(star_rating);
CREATE INDEX idx_examples_recent ON response_examples(created_at DESC);
```
---
10. Mobile-First Design
Responsive Strategy
This app is designed phone-first. The primary user is a contractor between jobs, checking reviews on their phone.
| Breakpoint | Layout | Notes |
|---|---|---|
| `< 640px` (Mobile) | Single column. Full-width cards. Bottom-sticky action buttons. | Primary design target. 90%+ of usage. |
| `640px – 1023px` (Tablet) | Single column with wider cards. Metrics side-by-side. | |
| `≥ 1024px` (Desktop) | Fixed sidebar nav. Content area with max-width cards. | Secondary. Used for initial setup. |
Mobile Interaction Rules
- All tap targets minimum 44x44px
- Swipe gestures: swipe left on review card to skip, swipe right to quick-approve (if draft exists)
- Bottom sheet for filters (not dropdown menus)
- Response textarea auto-expands to show full response
- "Copy" button triggers haptic feedback on supported devices
- No hover-dependent interactions — everything works on tap
Performance Targets
| Metric | Target |
|---|---|
| First Contentful Paint | < 1.5s on 4G |
| Review list render (20 cards) | < 500ms |
| AI response generation (streaming) | First token < 2s |
| Copy-to-clipboard | < 100ms |
---
11. Technical Stack
| Component | Technology |
|---|---|
| Frontend | React + TypeScript + Vite + Tailwind CSS |
| UI Components | shadcn/ui |
| Routing | wouter |
| Data Fetching | TanStack React Query v5 |
| Backend | Express.js (TypeScript) |
| Database | PostgreSQL (Drizzle ORM) |
| Auth | Authentication (email/password + Google OAuth) |
| AI | Anthropic Claude (primary) + OpenAI GPT-4o (fallback) |
| Google Integration | GBP API v4 + Google OAuth 2.0 |
| Deployment | Replit |
Environment Variables
```
DATABASE_URL=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
ANTHROPIC_API_KEY= (via Replit AI integration)
OPENAI_API_KEY= (via Replit AI integration)
```
---
12. Testing Scenarios
Onboarding
| # | Scenario | Expected Result |
|---|---|---|
| T1 | Complete onboarding with Google OAuth | GBP connected, reviews pulled, voice profile created |
| T2 | Complete onboarding in manual mode | Manual mode configured, can paste reviews |
| T3 | Skip voice profile setup | Can still generate responses (uses default professional tone) |
| T4 | Re-analyze voice with additional samples | Voice profile updated, contractor edits preserved |
Review Response
| # | Scenario | Expected Result |
|---|---|---|
| T5 | Generate response for 5-star review | Response is 1-3 sentences, no banned phrases, uses contractor's voice |
| T6 | Generate response for 1-star review | Response leads with specific issue, empathetic tone, includes phone number |
| T7 | Edit response and approve | Edited version saved as training example |
| T8 | Approve without editing | Response marked as approved_as_is, added to few-shot pool |
| T9 | Regenerate response | New response generated, old draft preserved in history |
| T10 | Copy response (manual mode) | Text copied to clipboard, status → Responded |
| T11 | Post response (API mode) | Response posted to Google, status → Responded |
Multi-Shot Learning
| # | Scenario | Expected Result |
|---|---|---|
| T12 | After 5 edits, generate new response | Response incorporates patterns from edited examples |
| T13 | Mix of star ratings in examples | System selects same-star examples for few-shot |
| T14 | No examples yet (first use) | System uses brand voice + anti-AI rules only |
Language
| # | Scenario | Expected Result |
|---|---|---|
| T15 | Spanish review, auto-match ON | Response generated in Spanish |
| T16 | Spanish review, auto-match OFF, language = English | Response generated in English |
| T17 | Change language in settings | New drafts use new language, existing drafts unchanged |
Edge Cases
| # | Scenario | Expected Result |
|---|---|---|
| T18 | Rating-only review (no text) | Shorter response acknowledging the rating |
| T19 | Google token revoked | Graceful switch to manual mode, notification shown |
| T20 | AI generation fails | Error message shown, manual textarea remains editable |
| T21 | Bulk generate 20 responses | Progress bar, concurrent limit respected, queue completion screen |