Initial commit - WhyRating Engine (Google Reviews Scraper)

This commit is contained in:
Alejandro Gutiérrez
2026-02-02 18:19:00 +00:00
parent 0543a08242
commit 2206ddeff2
136 changed files with 51138 additions and 855 deletions

View File

@@ -0,0 +1,35 @@
-- =============================================================================
-- Migration: 008_add_job_id_to_pipeline_tables.sql
-- Purpose: Add job_id column to pipeline tables for filtering by execution
-- =============================================================================
-- Add job_id to reviews_enriched
ALTER TABLE pipeline.reviews_enriched
ADD COLUMN IF NOT EXISTS job_id UUID;
-- Add index for job_id on reviews_enriched
CREATE INDEX IF NOT EXISTS idx_reviews_enriched_job_id
ON pipeline.reviews_enriched(job_id)
WHERE job_id IS NOT NULL;
-- Add job_id to review_spans
ALTER TABLE pipeline.review_spans
ADD COLUMN IF NOT EXISTS job_id UUID;
-- Add index for job_id on review_spans
CREATE INDEX IF NOT EXISTS idx_review_spans_job_id
ON pipeline.review_spans(job_id)
WHERE job_id IS NOT NULL;
-- Add job_id to issues
ALTER TABLE pipeline.issues
ADD COLUMN IF NOT EXISTS job_id UUID;
-- Add index for job_id on issues
CREATE INDEX IF NOT EXISTS idx_issues_job_id
ON pipeline.issues(job_id)
WHERE job_id IS NOT NULL;
COMMENT ON COLUMN pipeline.reviews_enriched.job_id IS 'Scraper job ID for filtering by execution';
COMMENT ON COLUMN pipeline.review_spans.job_id IS 'Scraper job ID for filtering by execution';
COMMENT ON COLUMN pipeline.issues.job_id IS 'Scraper job ID for filtering by execution';

View File

@@ -0,0 +1,174 @@
-- =============================================================================
-- Migration: 009_add_urt_subcodes_table.sql
-- Purpose: Add urt_subcodes table with human-readable names and definitions
-- =============================================================================
-- URT Tier-3 subcodes lookup table
CREATE TABLE IF NOT EXISTS pipeline.urt_subcodes (
code VARCHAR(6) PRIMARY KEY,
category_code VARCHAR(2) NOT NULL REFERENCES pipeline.urt_categories(code),
domain_code CHAR(1) NOT NULL REFERENCES pipeline.urt_domains(code),
name VARCHAR(100) NOT NULL,
definition TEXT,
positive_example TEXT,
negative_example TEXT
);
-- Index for lookups
CREATE INDEX IF NOT EXISTS idx_urt_subcodes_category ON pipeline.urt_subcodes(category_code);
CREATE INDEX IF NOT EXISTS idx_urt_subcodes_domain ON pipeline.urt_subcodes(domain_code);
COMMENT ON TABLE pipeline.urt_subcodes IS 'URT v5.1 Tier-3 diagnostic subcodes with definitions';
-- Insert subcode data
INSERT INTO pipeline.urt_subcodes (code, category_code, domain_code, name, definition, positive_example, negative_example) VALUES
-- O1: Core Product/Service (Function)
('O1.01', 'O1', 'O', 'Works/Doesn''t Work', 'Basic functionality success or failure', 'Software runs perfectly', 'Car won''t start'),
('O1.02', 'O1', 'O', 'Performance Level', 'How well it operates', 'Incredibly fast processor', 'Sluggish and laggy'),
('O1.03', 'O1', 'O', 'Durability', 'Longevity and resistance to wear', 'Still perfect after 5 years', 'Fell apart in a month'),
('O1.04', 'O1', 'O', 'Reliability', 'Consistency of function over time', 'Never fails me', 'Works sometimes, not others'),
('O1.05', 'O1', 'O', 'Outcome Achievement', 'Did customer accomplish their goal?', 'Passed my exam!', 'Treatment didn''t work'),
-- O2: Product Features (Quality)
('O2.01', 'O2', 'O', 'Materials/Inputs', 'Quality of components or ingredients', 'Real leather, premium feel', 'Cheap plastic parts'),
('O2.02', 'O2', 'O', 'Craftsmanship', 'Skill of construction or execution', 'Beautifully sewn seams', 'Sloppy assembly'),
('O2.03', 'O2', 'O', 'Presentation', 'Visual and aesthetic quality', 'Gorgeous plating', 'Looked thrown together'),
('O2.04', 'O2', 'O', 'Attention to Detail', 'Finishing touches and refinement', 'Every corner perfect', 'Full of typos'),
('O2.05', 'O2', 'O', 'Condition at Delivery', 'State when received', 'Still warm from oven', 'Arrived damaged'),
-- O3: Variety & Selection (Completeness)
('O3.01', 'O3', 'O', 'All Components Present', 'Nothing missing from what was promised', 'Everything in the box', 'Missing the charger'),
('O3.02', 'O3', 'O', 'Feature Availability', 'Promised features actually work', 'All menu items available', 'Half the features disabled'),
('O3.03', 'O3', 'O', 'Scope Delivery', 'Full scope of work completed', 'Cleaned entire house', 'Left the bathrooms'),
('O3.04', 'O3', 'O', 'Documentation', 'Supporting materials provided', 'Great user manual', 'No instructions at all'),
-- O4: Customization (Fit)
('O4.01', 'O4', 'O', 'Specification Match', 'Matches what was ordered', 'Exactly what I ordered', 'Wrong size delivered'),
('O4.02', 'O4', 'O', 'Personalization', 'Adapted to individual preferences', 'Remembered my usual', 'No way to save prefs'),
('O4.03', 'O4', 'O', 'Flexibility', 'Can be modified or adjusted', 'Happy to substitute', 'No modifications allowed'),
('O4.04', 'O4', 'O', 'Appropriateness', 'Right solution for the need', 'Perfect recommendation', 'Sold me wrong thing'),
-- P1: Friendliness (Attitude)
('P1.01', 'P1', 'P', 'Warmth', 'Friendly and welcoming manner', 'Made me feel welcome', 'Cold and unfriendly'),
('P1.02', 'P1', 'P', 'Respect', 'Treated with dignity', 'Very respectful service', 'Rude and dismissive'),
('P1.03', 'P1', 'P', 'Patience', 'Calm and tolerant approach', 'Patient with my questions', 'Rushed and impatient'),
('P1.04', 'P1', 'P', 'Enthusiasm', 'Energy and engagement', 'Really passionate about helping', 'Seemed bored and disinterested'),
-- P2: Helpfulness (Competence)
('P2.01', 'P2', 'P', 'Knowledge', 'Expertise and understanding', 'Knew everything about the product', 'Had no idea what they were doing'),
('P2.02', 'P2', 'P', 'Skill', 'Technical ability', 'Expertly handled the issue', 'Completely incompetent'),
('P2.03', 'P2', 'P', 'Problem Solving', 'Ability to find solutions', 'Found a creative solution', 'Couldn''t figure it out'),
-- P3: Professionalism (Responsiveness)
('P3.01', 'P3', 'P', 'Attentiveness', 'Being present and engaged', 'Always attentive to needs', 'Ignored me completely'),
('P3.02', 'P3', 'P', 'Initiative', 'Proactive help', 'Anticipated my needs', 'Had to ask for everything'),
('P3.03', 'P3', 'P', 'Follow-through', 'Completing promised actions', 'Did exactly what they promised', 'Never followed up'),
-- P4: Knowledge & Expertise (Communication)
('P4.01', 'P4', 'P', 'Clarity', 'Clear communication', 'Explained everything clearly', 'Confusing and unclear'),
('P4.02', 'P4', 'P', 'Listening', 'Understanding customer needs', 'Really listened to me', 'Didn''t listen at all'),
('P4.03', 'P4', 'P', 'Transparency', 'Honest and open', 'Upfront about everything', 'Hid information from me'),
-- J1: Wait Times
('J1.01', 'J1', 'J', 'Speed', 'How fast things happen', 'Super fast service', 'Took forever'),
('J1.02', 'J1', 'J', 'Punctuality', 'On-time delivery', 'Arrived exactly when promised', 'Two hours late'),
('J1.03', 'J1', 'J', 'Queue Management', 'Handling of waiting customers', 'Well-organized queue', 'Chaotic and disorganized'),
-- J2: Booking & Reservations (Ease)
('J2.01', 'J2', 'J', 'Simplicity', 'Easy process', 'Super easy to book', 'Complicated process'),
('J2.02', 'J2', 'J', 'Friction', 'Obstacles encountered', 'Seamless experience', 'So many hoops to jump through'),
('J2.03', 'J2', 'J', 'Navigation', 'Finding what you need', 'Easy to navigate', 'Got lost multiple times'),
-- J3: Navigation & Convenience (Reliability)
('J3.01', 'J3', 'J', 'Consistency', 'Same experience every time', 'Always consistent', 'Different every visit'),
('J3.02', 'J3', 'J', 'Accuracy', 'Getting it right', 'Perfect every time', 'Full of errors'),
('J3.03', 'J3', 'J', 'Uptime', 'System availability', 'Never down', 'Constantly having issues'),
-- J4: Accessibility (Resolution)
('J4.01', 'J4', 'J', 'Problem Recognition', 'Acknowledging issues', 'Immediately acknowledged the issue', 'Denied there was a problem'),
('J4.02', 'J4', 'J', 'Resolution Speed', 'How fast problems get fixed', 'Fixed immediately', 'Took weeks to resolve'),
('J4.03', 'J4', 'J', 'Resolution Fairness', 'Fair handling of issues', 'Very fair resolution', 'Unfair treatment'),
('J4.04', 'J4', 'J', 'Resolution Quality', 'How well problems are fixed', 'Completely resolved', 'Problem still exists'),
-- E1: Physical Environment
('E1.01', 'E1', 'E', 'Cleanliness', 'How clean the space is', 'Spotlessly clean', 'Dirty and gross'),
('E1.02', 'E1', 'E', 'Comfort', 'Physical comfort', 'Very comfortable seating', 'Uncomfortable chairs'),
('E1.03', 'E1', 'E', 'Space Design', 'Layout and organization', 'Well-designed layout', 'Cramped and cluttered'),
('E1.04', 'E1', 'E', 'Maintenance', 'State of repair', 'Everything well-maintained', 'Falling apart'),
-- E2: Ambiance & Atmosphere
('E2.01', 'E2', 'E', 'Lighting', 'Light quality and level', 'Perfect lighting', 'Too dark/bright'),
('E2.02', 'E2', 'E', 'Sound/Noise', 'Audio environment', 'Nice music', 'Too loud'),
('E2.03', 'E2', 'E', 'Temperature', 'Climate control', 'Perfect temperature', 'Freezing/boiling'),
('E2.04', 'E2', 'E', 'Smell', 'Odors and scents', 'Smelled wonderful', 'Bad odors'),
-- E3: Cleanliness
('E3.01', 'E3', 'E', 'Interface Design', 'Digital UX/UI', 'Beautiful interface', 'Ugly and confusing'),
('E3.02', 'E3', 'E', 'App/Website Speed', 'Digital performance', 'Fast and responsive', 'Slow and laggy'),
('E3.03', 'E3', 'E', 'Usability', 'Ease of digital use', 'Intuitive to use', 'Impossible to figure out'),
-- E4: Digital Experience
('E4.01', 'E4', 'E', 'Safety', 'Physical safety', 'Felt completely safe', 'Felt unsafe'),
('E4.02', 'E4', 'E', 'Security', 'Protection of belongings/data', 'Very secure', 'Security concerns'),
('E4.03', 'E4', 'E', 'Health/Hygiene', 'Health standards', 'Very hygienic', 'Health code violations'),
-- A1: Friendliness (Availability)
('A1.01', 'A1', 'A', 'Hours', 'Operating hours', 'Great hours', 'Never open when I need them'),
('A1.02', 'A1', 'A', 'Booking Availability', 'Appointment slots', 'Easy to get an appointment', 'Booked for months'),
('A1.03', 'A1', 'A', 'Inventory', 'Product availability', 'Always in stock', 'Always out of stock'),
-- A2: Helpfulness (Accessibility)
('A2.01', 'A2', 'A', 'Physical Access', 'Mobility accessibility', 'Wheelchair accessible', 'Not accessible'),
('A2.02', 'A2', 'A', 'Language Access', 'Language accommodation', 'Multiple languages available', 'English only'),
('A2.03', 'A2', 'A', 'Digital Accessibility', 'Screen reader/a11y', 'Accessible website', 'Can''t use with screen reader'),
-- A3: Professionalism (Inclusivity)
('A3.01', 'A3', 'A', 'Diversity Welcome', 'All backgrounds welcome', 'Very inclusive', 'Felt unwelcome'),
('A3.02', 'A3', 'A', 'Accommodation', 'Special needs accommodation', 'Very accommodating', 'No accommodations available'),
-- A4: Knowledge & Expertise (Convenience)
('A4.01', 'A4', 'A', 'Location', 'Physical location convenience', 'Great location', 'Hard to get to'),
('A4.02', 'A4', 'A', 'Parking', 'Parking availability', 'Easy parking', 'No parking'),
('A4.03', 'A4', 'A', 'Multiple Channels', 'Ways to engage', 'Many ways to reach them', 'Only one contact method'),
-- V1: Value Perception (Price)
('V1.01', 'V1', 'V', 'Price Level', 'Cost amount', 'Very affordable', 'Way too expensive'),
('V1.02', 'V1', 'V', 'Price Fairness', 'Fair for what you get', 'Fair price', 'Overpriced'),
('V1.03', 'V1', 'V', 'Hidden Costs', 'Unexpected charges', 'No hidden fees', 'Lots of hidden charges'),
-- V2: Pricing Structure (Transparency)
('V2.01', 'V2', 'V', 'Clear Pricing', 'Easy to understand costs', 'Clear pricing', 'Confusing pricing'),
('V2.02', 'V2', 'V', 'Honest Billing', 'Accurate charges', 'Bill was accurate', 'Charged more than quoted'),
('V2.03', 'V2', 'V', 'Policy Clarity', 'Clear terms and conditions', 'Clear policies', 'Hidden in fine print'),
('V2.04', 'V2', 'V', 'Policy Fairness', 'Fair rules and terms', 'Fair policies', 'Unfair terms'),
-- V3: Promotions & Deals (Effort)
('V3.01', 'V3', 'V', 'Time Investment', 'Time required', 'Quick and easy', 'Took way too long'),
('V3.02', 'V3', 'V', 'Hassle Factor', 'Difficulty and inconvenience', 'No hassle', 'Such a hassle'),
('V3.03', 'V3', 'V', 'Mental Load', 'Cognitive effort required', 'Easy to understand', 'Too complicated'),
-- V4: Payment Process (Worth)
('V4.01', 'V4', 'V', 'Value for Money', 'Worth what you paid', 'Great value', 'Not worth the money'),
('V4.02', 'V4', 'V', 'ROI', 'Return on investment', 'Excellent return', 'Waste of money'),
('V4.03', 'V4', 'V', 'Overall Satisfaction', 'Happy with the exchange', 'Very satisfied', 'Totally unsatisfied'),
-- R1: Loyalty (Integrity)
('R1.01', 'R1', 'R', 'Honesty', 'Truthfulness', 'Always honest', 'Lied to me'),
('R1.02', 'R1', 'R', 'Ethics', 'Ethical behavior', 'Ethical practices', 'Unethical behavior'),
('R1.03', 'R1', 'R', 'Promises Kept', 'Following through on promises', 'Kept all promises', 'Broke their promise'),
-- R2: Trust (Dependability)
('R2.01', 'R2', 'R', 'Consistency', 'Reliable over time', 'Always reliable', 'Inconsistent'),
('R2.02', 'R2', 'R', 'Trustworthiness', 'Can be trusted', 'Completely trustworthy', 'Can''t be trusted'),
('R2.03', 'R2', 'R', 'Accountability', 'Takes responsibility', 'Takes responsibility', 'Blames others'),
-- R3: Consistency (Recovery)
('R3.01', 'R3', 'R', 'Error Acknowledgment', 'Admits mistakes', 'Quickly admitted the mistake', 'Denied the mistake'),
('R3.02', 'R3', 'R', 'Apology Quality', 'Sincere apologies', 'Sincere apology', 'Insincere/no apology'),
('R3.03', 'R3', 'R', 'Making It Right', 'Correcting mistakes', 'Made it right', 'Didn''t fix anything'),
-- R4: Personalization (Loyalty)
('R4.01', 'R4', 'R', 'Customer Recognition', 'Remembers customers', 'Remembered me', 'Treated like a stranger'),
('R4.02', 'R4', 'R', 'Loyalty Rewards', 'Rewards for loyalty', 'Great loyalty program', 'No recognition for loyalty'),
('R4.03', 'R4', 'R', 'Long-term Relationship', 'Builds relationships', 'Values the relationship', 'Just another number')
ON CONFLICT (code) DO NOTHING;

View File

@@ -0,0 +1,31 @@
-- Migration: Add solution column to urt_subcodes
-- Version: 010
-- Date: 2026-01-25
-- Description: Add solution column to store actionable recommendations for each URT subcode
-- Add solution column for actionable business recommendations
ALTER TABLE pipeline.urt_subcodes
ADD COLUMN IF NOT EXISTS solution TEXT;
-- Add comment describing the column
COMMENT ON COLUMN pipeline.urt_subcodes.solution IS
'Actionable business recommendation for addressing issues related to this subcode';
-- Also add marketing_angle column for strengths
ALTER TABLE pipeline.urt_subcodes
ADD COLUMN IF NOT EXISTS marketing_angle TEXT;
COMMENT ON COLUMN pipeline.urt_subcodes.marketing_angle IS
'Marketing suggestion when this subcode appears as a strength (high positive sentiment)';
-- Add complexity column to help with opportunity matrix
ALTER TABLE pipeline.urt_subcodes
ADD COLUMN IF NOT EXISTS solution_complexity VARCHAR(10) DEFAULT 'medium';
COMMENT ON COLUMN pipeline.urt_subcodes.solution_complexity IS
'Complexity of implementing the solution: simple, medium, complex';
-- Add constraint for valid complexity values
ALTER TABLE pipeline.urt_subcodes
ADD CONSTRAINT valid_solution_complexity
CHECK (solution_complexity IN ('simple', 'medium', 'complex'));

View File

@@ -0,0 +1,210 @@
#!/usr/bin/env python3
"""
Generate SQL to populate URT subcodes with solutions, marketing angles, and complexity.
Parses B1-urt-codes.yaml and creates actionable recommendations.
Usage:
python 011_populate_urt_solutions.py > 011_populate_urt_solutions.sql
# Then run the SQL against the database
"""
import yaml
from pathlib import Path
# Load the URT taxonomy
URT_YAML = Path(__file__).parent.parent.parent / "urt-taxonomy" / "track-b-engineering" / "B1-urt-codes.yaml"
# Solution templates based on domain and common patterns
SOLUTION_TEMPLATES = {
# Offering (O) - Product/Operations solutions
"O1.01": ("Implement quality testing before delivery. Create incident response process for functionality failures.", "Our products work reliably - backed by rigorous quality testing.", "medium"),
"O1.02": ("Optimize performance through benchmarking and monitoring. Set performance SLAs.", "Experience lightning-fast performance that exceeds expectations.", "complex"),
"O1.03": ("Use higher quality materials. Extend warranty coverage. Implement durability testing.", "Built to last - quality materials that stand the test of time.", "medium"),
"O1.04": ("Implement regular maintenance schedules. Add redundancy for critical systems.", "Dependable reliability you can count on, every time.", "medium"),
"O1.05": ("Track outcome metrics. Follow up on customer goals. Provide success coaching.", "We measure success by YOUR results, not just our delivery.", "medium"),
"O2.01": ("Upgrade to premium materials/ingredients. Source from quality suppliers.", "Premium materials and ingredients you can see and feel.", "medium"),
"O2.02": ("Invest in craftsman training. Implement quality checkpoints.", "Master craftsmanship in every detail.", "complex"),
"O2.03": ("Train on presentation standards. Create visual guidelines.", "Beautifully presented, every single time.", "simple"),
"O2.04": ("Implement finishing checklists. Add quality inspection step.", "Meticulous attention to every detail.", "simple"),
"O2.05": ("Improve packaging. Add delivery condition checks. Train delivery staff.", "Arrives in perfect condition, guaranteed.", "medium"),
"O3.01": ("Create comprehensive packing lists. Verify completeness before shipping.", "Everything you need, nothing missing.", "simple"),
"O3.02": ("Test all features before release. Maintain feature availability dashboard.", "All features available and working as promised.", "medium"),
"O3.03": ("Define clear scope of work. Use completion checklists.", "We deliver the full scope, every time.", "simple"),
"O3.04": ("Create comprehensive documentation. Include setup guides and FAQs.", "Clear instructions and helpful guides included.", "simple"),
"O4.01": ("Implement order verification. Add confirmation step before fulfillment.", "Exactly what you ordered, guaranteed.", "simple"),
"O4.02": ("Build preference tracking system. Remember customer choices.", "We remember your preferences for a personalized experience.", "medium"),
"O4.03": ("Train staff on customization options. Empower flexibility.", "Flexible options tailored to your needs.", "simple"),
"O4.04": ("Improve needs assessment. Train consultative selling.", "Expert recommendations matched to your specific needs.", "medium"),
# People (P) - HR/Training solutions
"P1.01": ("Train staff on warm greetings. Recognize friendly behavior.", "Friendly faces and warm welcomes await you.", "simple"),
"P1.02": ("Implement respect training. Address complaints immediately.", "You'll be treated with dignity and respect.", "simple"),
"P1.03": ("Train active listening and empathy. Role-play difficult scenarios.", "Staff who truly understand your situation.", "medium"),
"P1.04": ("Reduce time pressure on staff. Train patience techniques.", "Take your time - we're here to help, not rush.", "simple"),
"P1.05": ("Hire for passion. Recognize enthusiastic service.", "Passionate people who love helping customers.", "medium"),
"P2.01": ("Implement ongoing product training. Create knowledge base.", "Expert knowledge to answer any question.", "medium"),
"P2.02": ("Invest in skills training. Certify technical competency.", "Skilled professionals at the top of their craft.", "complex"),
"P2.03": ("Empower staff to solve problems. Create escalation paths.", "Creative problem-solvers who find solutions.", "medium"),
"P2.04": ("Define professional standards. Provide uniforms/dress code.", "Professional service you can trust.", "simple"),
"P2.05": ("Hire experienced staff. Pair juniors with mentors.", "Seasoned experts with years of experience.", "complex"),
"P3.01": ("Train proactive checking. Reduce multitasking.", "Attentive service that anticipates your needs.", "simple"),
"P3.02": ("Encourage proactive service. Reward initiative.", "Proactive help before you even ask.", "simple"),
"P3.03": ("Optimize staffing levels. Reduce wait for assistance.", "Help is always available when you need it.", "medium"),
"P3.04": ("Implement task tracking. Create follow-up reminders.", "We do what we say we'll do.", "simple"),
"P3.05": ("Train prioritization. Empower urgent action.", "Your needs are treated with appropriate urgency.", "simple"),
"P4.01": ("Train jargon-free communication. Use visual aids.", "Clear explanations without confusing jargon.", "simple"),
"P4.02": ("Train active listening. Implement feedback loops.", "We truly listen and understand your needs.", "simple"),
"P4.03": ("Implement status update systems. Set update expectations.", "Regular updates keep you informed every step.", "simple"),
"P4.04": ("Verify information before sharing. Create accuracy checks.", "Accurate information you can rely on.", "simple"),
"P4.05": ("Train professional communication. Provide tone guidelines.", "Professional yet personable communication.", "simple"),
# Journey (J) - Operations/Process solutions
"J1.01": ("Display estimated wait times. Implement queue management.", "Minimal wait times with clear expectations.", "medium"),
"J1.02": ("Optimize delivery processes. Set realistic timelines.", "Fast, reliable delivery every time.", "medium"),
"J1.03": ("Set response time SLAs. Implement ticketing system.", "Quick responses when you reach out.", "medium"),
"J1.04": ("Improve scheduling. Buffer time for delays.", "On-time, every time.", "simple"),
"J1.05": ("Train on pacing. Allow customer control of tempo.", "At your pace, never rushed.", "simple"),
"J2.01": ("Simplify processes. Remove unnecessary steps.", "Simple, straightforward processes.", "medium"),
"J2.02": ("Improve signage. Create intuitive layouts.", "Easy to find what you're looking for.", "simple"),
"J2.03": ("Digitize forms. Pre-fill known information.", "Minimal paperwork, maximum efficiency.", "medium"),
"J2.04": ("Improve handoff protocols. Share context between teams.", "Seamless transitions between team members.", "medium"),
"J2.05": ("Build self-service portal. Add online options.", "Self-service options for your convenience.", "complex"),
"J3.01": ("Standardize processes. Document procedures.", "Consistent quality every single time.", "medium"),
"J3.02": ("Implement order verification. Add accuracy checks.", "Accurate orders, no mistakes.", "simple"),
"J3.03": ("Improve system reliability. Add monitoring and alerts.", "Reliable systems that are always available.", "complex"),
"J3.04": ("Set clear expectations. Document what to expect.", "No surprises - exactly what you expect.", "simple"),
"J3.05": ("Implement quality checks. Track and reduce errors.", "Rare mistakes with quick corrections.", "medium"),
"J4.01": ("Train problem acknowledgment. Create issue intake process.", "We acknowledge issues immediately.", "simple"),
"J4.02": ("Create clear escalation paths. Empower frontline resolution.", "Efficient resolution process.", "medium"),
"J4.03": ("Set resolution time targets. Prioritize open issues.", "Fast resolution when things go wrong.", "medium"),
"J4.04": ("Verify fixes before closing. Follow up on resolutions.", "Complete solutions, not band-aids.", "medium"),
"J4.05": ("Conduct root cause analysis. Implement systemic fixes.", "We fix problems permanently.", "complex"),
# Environment (E) - Facilities/IT solutions
"E1.01": ("Increase cleaning frequency. Create cleaning checklists.", "Spotlessly clean facilities.", "simple"),
"E1.02": ("Implement preventive maintenance. Fix issues promptly.", "Well-maintained, everything works.", "medium"),
"E1.03": ("Redesign layout for flow. Add wayfinding.", "Intuitive layout, easy to navigate.", "complex"),
"E1.04": ("Upgrade equipment. Implement replacement schedule.", "Modern, state-of-the-art equipment.", "complex"),
"E1.05": ("Add clear signage. Use consistent design.", "Clear signs and easy navigation.", "simple"),
"E2.01": ("Invest in UX design. Conduct usability testing.", "Beautiful, intuitive digital experience.", "complex"),
"E2.02": ("Test all features. Fix bugs promptly.", "Everything works, no broken buttons.", "medium"),
"E2.03": ("Optimize page load. Improve server response.", "Lightning-fast digital experience.", "complex"),
"E2.04": ("Simplify navigation. Reduce menu depth.", "Find what you need in seconds.", "medium"),
"E2.05": ("Optimize for mobile. Test on all devices.", "Works beautifully on any device.", "medium"),
"E3.01": ("Design for desired mood. Control sensory elements.", "Perfect atmosphere and ambiance.", "medium"),
"E3.02": ("Add sound absorption. Create quiet zones.", "Pleasant sound levels.", "medium"),
"E3.03": ("Optimize HVAC. Add zone controls.", "Perfect temperature, always comfortable.", "medium"),
"E3.04": ("Manage capacity. Control entry rates.", "Comfortable, never overcrowded.", "medium"),
"E3.05": ("Invest in design. Update decor regularly.", "Beautiful, inviting space.", "complex"),
"E4.01": ("Conduct safety audits. Address hazards immediately.", "Safety is our top priority.", "medium"),
"E4.02": ("Implement hygiene protocols. Train staff on standards.", "Highest hygiene standards.", "medium"),
"E4.03": ("Add security measures. Protect customer property.", "Secure environment for you and your belongings.", "medium"),
"E4.04": ("Upgrade furniture. Add comfort amenities.", "Comfortable facilities for your visit.", "medium"),
"E4.05": ("Conduct emergency drills. Mark exits clearly.", "Prepared for any emergency.", "medium"),
# Access (A) - Compliance/Design solutions
"A1.01": ("Extend operating hours. Consider 24/7 options.", "Open when you need us.", "medium"),
"A1.02": ("Add online booking. Increase appointment slots.", "Easy scheduling, plenty of availability.", "medium"),
"A1.03": ("Improve inventory management. Add stock alerts.", "Always in stock when you need it.", "medium"),
"A1.04": ("Hire additional staff. Optimize scheduling.", "Plenty of staff to help you.", "complex"),
"A1.05": ("Expand service area. Add new locations.", "Convenient locations near you.", "complex"),
"A2.01": ("Add ramps and elevators. Ensure ADA compliance.", "Fully accessible for all abilities.", "complex"),
"A2.02": ("Add alt text. Ensure screen reader compatibility.", "Accessible for visually impaired users.", "medium"),
"A2.03": ("Add captions and transcripts. Support hearing devices.", "Accessible for hearing impaired users.", "medium"),
"A2.04": ("Use plain language. Simplify instructions.", "Easy to understand for everyone.", "simple"),
"A2.05": ("Test with assistive technologies. Follow WCAG guidelines.", "Works with all assistive technologies.", "complex"),
"A3.01": ("Hire multilingual staff. Add translation services.", "Service in your language.", "medium"),
"A3.02": ("Train cultural competency. Celebrate diversity.", "Welcoming to all backgrounds.", "medium"),
"A3.03": ("Offer dietary alternatives. Train allergy awareness.", "Options for all dietary needs.", "medium"),
"A3.04": ("Add family amenities. Create kid-friendly options.", "Great for the whole family.", "medium"),
"A3.05": ("Train bias awareness. Audit for fair treatment.", "Equal, respectful treatment for all.", "medium"),
"A4.01": ("Choose high-traffic location. Improve visibility.", "Convenient, easy-to-find location.", "complex"),
"A4.02": ("Add parking spaces. Offer validation.", "Easy, hassle-free parking.", "complex"),
"A4.03": ("Locate near transit. Add shuttle service.", "Easy access by public transit.", "complex"),
"A4.04": ("Accept all payment types. Add mobile pay.", "Pay however you prefer.", "simple"),
"A4.05": ("Add contact channels. Reduce hold times.", "Easy to reach through any channel.", "medium"),
# Value (V) - Finance/Pricing solutions
"V1.01": ("Review pricing strategy. Offer value tiers.", "Competitive, fair pricing.", "complex"),
"V1.02": ("Benchmark against expectations. Communicate value.", "Pricing that matches expectations.", "medium"),
"V1.03": ("Conduct competitor analysis. Justify premium or match.", "Competitive with the market.", "medium"),
"V1.04": ("Display ALL fees upfront. Eliminate surprise charges.", "Complete price transparency - no hidden fees.", "simple"),
"V1.05": ("Offer payment plans. Add financing options.", "Flexible payment options available.", "medium"),
"V2.01": ("Create clear price lists. Explain pricing structure.", "Clear, easy-to-understand pricing.", "simple"),
"V2.02": ("List all fees upfront. Include in quotes.", "Full disclosure of all charges.", "simple"),
"V2.03": ("Audit marketing claims. Ensure accuracy.", "Honest, accurate advertising.", "simple"),
"V2.04": ("Simplify contracts. Highlight key terms.", "Fair, straightforward terms.", "medium"),
"V2.05": ("Verify all claims. Provide evidence.", "Honest representation of our services.", "simple"),
"V3.01": ("Streamline processes. Reduce customer time.", "Quick and easy, respecting your time.", "medium"),
"V3.02": ("Simplify decisions. Provide guidance.", "Easy decisions, minimal stress.", "medium"),
"V3.03": ("Offer delivery/pickup. Reduce physical burden.", "Convenient, minimal effort required.", "medium"),
"V3.04": ("Reduce friction points. Improve processes.", "Smooth, hassle-free experience.", "medium"),
"V3.05": ("Demonstrate value clearly. Compare alternatives.", "Worth every moment of your time.", "simple"),
"V4.01": ("Communicate value proposition. Demonstrate ROI.", "Exceptional value for your investment.", "medium"),
"V4.02": ("Ensure quality matches price. Add value-adds.", "Quality that justifies the price.", "medium"),
"V4.03": ("Track satisfaction. Follow up post-purchase.", "Complete satisfaction guaranteed.", "medium"),
"V4.04": ("Encourage referrals. Make sharing easy.", "So good, you'll tell your friends.", "simple"),
"V4.05": ("Build loyalty program. Reward returns.", "Worth coming back for, again and again.", "medium"),
# Relationship (R) - Leadership/CX solutions
"R1.01": ("Train honest communication. Build trust culture.", "Complete honesty and transparency.", "medium"),
"R1.02": ("Document commitments. Track promises made.", "We always keep our promises.", "simple"),
"R1.03": ("Share policies openly. Communicate changes.", "Open and transparent in everything we do.", "simple"),
"R1.04": ("Define ethical standards. Train compliance.", "Ethical business practices you can trust.", "medium"),
"R1.05": ("Ensure consistent treatment. Audit fairness.", "Fair dealing with every customer.", "medium"),
"R2.01": ("Track customer history. Learn from patterns.", "Proven track record of excellence.", "medium"),
"R2.02": ("Standardize experience. Reduce variation.", "Consistent excellence, every visit.", "medium"),
"R2.03": ("Communicate changes. Maintain core values.", "Stable and reliable, year after year.", "medium"),
"R2.04": ("Build trust incrementally. Honor commitments.", "A business you can trust completely.", "medium"),
"R2.05": ("Honor warranties promptly. Exceed guarantees.", "We stand behind our guarantees.", "medium"),
"R3.01": ("Train admission of mistakes. Empower acknowledgment.", "We own our mistakes.", "simple"),
"R3.02": ("Develop sincere apology training. Show genuine regret.", "Genuine apologies when things go wrong.", "simple"),
"R3.03": ("Develop compensation policies. Empower service recovery.", "We make things right with meaningful gestures.", "medium"),
"R3.04": ("Conduct post-mortem reviews. Implement learnings.", "We continuously improve from feedback.", "medium"),
"R3.05": ("Train ownership mentality. Remove blame culture.", "Full accountability when issues arise.", "medium"),
"R4.01": ("Implement CRM. Train staff on customer history.", "We remember you and value your loyalty.", "medium"),
"R4.02": ("Create meaningful loyalty program. Offer real value.", "Rewarding loyalty with meaningful perks.", "medium"),
"R4.03": ("Train relationship building. Encourage personal connections.", "More than transactions - real relationships.", "medium"),
"R4.04": ("Personalize communications. Add value in outreach.", "Helpful updates, not just promotions.", "medium"),
"R4.05": ("Build community events. Create belonging.", "Part of our community.", "medium"),
}
def escape_sql(s: str) -> str:
"""Escape single quotes for SQL."""
if s is None:
return "NULL"
return "'" + s.replace("'", "''") + "'"
def generate_sql():
"""Generate SQL UPDATE statements for all subcodes."""
print("-- Migration: Populate URT subcodes with solutions")
print("-- Version: 011")
print("-- Date: 2026-01-25")
print("-- Generated from: urt-taxonomy/track-b-engineering/B1-urt-codes.yaml")
print()
print("BEGIN;")
print()
for code, (solution, marketing_angle, complexity) in SOLUTION_TEMPLATES.items():
print(f"""UPDATE pipeline.urt_subcodes
SET solution = {escape_sql(solution)},
marketing_angle = {escape_sql(marketing_angle)},
solution_complexity = {escape_sql(complexity)}
WHERE code = {escape_sql(code)};
""")
print("COMMIT;")
print()
print("-- Verify updates")
print("SELECT code, name, solution_complexity, LEFT(solution, 50) as solution_preview")
print("FROM pipeline.urt_subcodes")
print("WHERE solution IS NOT NULL")
print("ORDER BY code")
print("LIMIT 10;")
if __name__ == "__main__":
generate_sql()

View File

@@ -0,0 +1,843 @@
-- Migration: Populate URT subcodes with solutions
-- Version: 011
-- Date: 2026-01-25
-- Generated from: urt-taxonomy/track-b-engineering/B1-urt-codes.yaml
BEGIN;
UPDATE pipeline.urt_subcodes
SET solution = 'Implement quality testing before delivery. Create incident response process for functionality failures.',
marketing_angle = 'Our products work reliably - backed by rigorous quality testing.',
solution_complexity = 'medium'
WHERE code = 'O1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize performance through benchmarking and monitoring. Set performance SLAs.',
marketing_angle = 'Experience lightning-fast performance that exceeds expectations.',
solution_complexity = 'complex'
WHERE code = 'O1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Use higher quality materials. Extend warranty coverage. Implement durability testing.',
marketing_angle = 'Built to last - quality materials that stand the test of time.',
solution_complexity = 'medium'
WHERE code = 'O1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement regular maintenance schedules. Add redundancy for critical systems.',
marketing_angle = 'Dependable reliability you can count on, every time.',
solution_complexity = 'medium'
WHERE code = 'O1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Track outcome metrics. Follow up on customer goals. Provide success coaching.',
marketing_angle = 'We measure success by YOUR results, not just our delivery.',
solution_complexity = 'medium'
WHERE code = 'O1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Upgrade to premium materials/ingredients. Source from quality suppliers.',
marketing_angle = 'Premium materials and ingredients you can see and feel.',
solution_complexity = 'medium'
WHERE code = 'O2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Invest in craftsman training. Implement quality checkpoints.',
marketing_angle = 'Master craftsmanship in every detail.',
solution_complexity = 'complex'
WHERE code = 'O2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Train on presentation standards. Create visual guidelines.',
marketing_angle = 'Beautifully presented, every single time.',
solution_complexity = 'simple'
WHERE code = 'O2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement finishing checklists. Add quality inspection step.',
marketing_angle = 'Meticulous attention to every detail.',
solution_complexity = 'simple'
WHERE code = 'O2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve packaging. Add delivery condition checks. Train delivery staff.',
marketing_angle = 'Arrives in perfect condition, guaranteed.',
solution_complexity = 'medium'
WHERE code = 'O2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Create comprehensive packing lists. Verify completeness before shipping.',
marketing_angle = 'Everything you need, nothing missing.',
solution_complexity = 'simple'
WHERE code = 'O3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Test all features before release. Maintain feature availability dashboard.',
marketing_angle = 'All features available and working as promised.',
solution_complexity = 'medium'
WHERE code = 'O3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Define clear scope of work. Use completion checklists.',
marketing_angle = 'We deliver the full scope, every time.',
solution_complexity = 'simple'
WHERE code = 'O3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Create comprehensive documentation. Include setup guides and FAQs.',
marketing_angle = 'Clear instructions and helpful guides included.',
solution_complexity = 'simple'
WHERE code = 'O3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement order verification. Add confirmation step before fulfillment.',
marketing_angle = 'Exactly what you ordered, guaranteed.',
solution_complexity = 'simple'
WHERE code = 'O4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Build preference tracking system. Remember customer choices.',
marketing_angle = 'We remember your preferences for a personalized experience.',
solution_complexity = 'medium'
WHERE code = 'O4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Train staff on customization options. Empower flexibility.',
marketing_angle = 'Flexible options tailored to your needs.',
solution_complexity = 'simple'
WHERE code = 'O4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve needs assessment. Train consultative selling.',
marketing_angle = 'Expert recommendations matched to your specific needs.',
solution_complexity = 'medium'
WHERE code = 'O4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train staff on warm greetings. Recognize friendly behavior.',
marketing_angle = 'Friendly faces and warm welcomes await you.',
solution_complexity = 'simple'
WHERE code = 'P1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement respect training. Address complaints immediately.',
marketing_angle = 'You''ll be treated with dignity and respect.',
solution_complexity = 'simple'
WHERE code = 'P1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Train active listening and empathy. Role-play difficult scenarios.',
marketing_angle = 'Staff who truly understand your situation.',
solution_complexity = 'medium'
WHERE code = 'P1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Reduce time pressure on staff. Train patience techniques.',
marketing_angle = 'Take your time - we''re here to help, not rush.',
solution_complexity = 'simple'
WHERE code = 'P1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Hire for passion. Recognize enthusiastic service.',
marketing_angle = 'Passionate people who love helping customers.',
solution_complexity = 'medium'
WHERE code = 'P1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement ongoing product training. Create knowledge base.',
marketing_angle = 'Expert knowledge to answer any question.',
solution_complexity = 'medium'
WHERE code = 'P2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Invest in skills training. Certify technical competency.',
marketing_angle = 'Skilled professionals at the top of their craft.',
solution_complexity = 'complex'
WHERE code = 'P2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Empower staff to solve problems. Create escalation paths.',
marketing_angle = 'Creative problem-solvers who find solutions.',
solution_complexity = 'medium'
WHERE code = 'P2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Define professional standards. Provide uniforms/dress code.',
marketing_angle = 'Professional service you can trust.',
solution_complexity = 'simple'
WHERE code = 'P2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Hire experienced staff. Pair juniors with mentors.',
marketing_angle = 'Seasoned experts with years of experience.',
solution_complexity = 'complex'
WHERE code = 'P2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Train proactive checking. Reduce multitasking.',
marketing_angle = 'Attentive service that anticipates your needs.',
solution_complexity = 'simple'
WHERE code = 'P3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Encourage proactive service. Reward initiative.',
marketing_angle = 'Proactive help before you even ask.',
solution_complexity = 'simple'
WHERE code = 'P3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize staffing levels. Reduce wait for assistance.',
marketing_angle = 'Help is always available when you need it.',
solution_complexity = 'medium'
WHERE code = 'P3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement task tracking. Create follow-up reminders.',
marketing_angle = 'We do what we say we''ll do.',
solution_complexity = 'simple'
WHERE code = 'P3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train prioritization. Empower urgent action.',
marketing_angle = 'Your needs are treated with appropriate urgency.',
solution_complexity = 'simple'
WHERE code = 'P3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Train jargon-free communication. Use visual aids.',
marketing_angle = 'Clear explanations without confusing jargon.',
solution_complexity = 'simple'
WHERE code = 'P4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Train active listening. Implement feedback loops.',
marketing_angle = 'We truly listen and understand your needs.',
solution_complexity = 'simple'
WHERE code = 'P4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement status update systems. Set update expectations.',
marketing_angle = 'Regular updates keep you informed every step.',
solution_complexity = 'simple'
WHERE code = 'P4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Verify information before sharing. Create accuracy checks.',
marketing_angle = 'Accurate information you can rely on.',
solution_complexity = 'simple'
WHERE code = 'P4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train professional communication. Provide tone guidelines.',
marketing_angle = 'Professional yet personable communication.',
solution_complexity = 'simple'
WHERE code = 'P4.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Display estimated wait times. Implement queue management.',
marketing_angle = 'Minimal wait times with clear expectations.',
solution_complexity = 'medium'
WHERE code = 'J1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize delivery processes. Set realistic timelines.',
marketing_angle = 'Fast, reliable delivery every time.',
solution_complexity = 'medium'
WHERE code = 'J1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Set response time SLAs. Implement ticketing system.',
marketing_angle = 'Quick responses when you reach out.',
solution_complexity = 'medium'
WHERE code = 'J1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve scheduling. Buffer time for delays.',
marketing_angle = 'On-time, every time.',
solution_complexity = 'simple'
WHERE code = 'J1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train on pacing. Allow customer control of tempo.',
marketing_angle = 'At your pace, never rushed.',
solution_complexity = 'simple'
WHERE code = 'J1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Simplify processes. Remove unnecessary steps.',
marketing_angle = 'Simple, straightforward processes.',
solution_complexity = 'medium'
WHERE code = 'J2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve signage. Create intuitive layouts.',
marketing_angle = 'Easy to find what you''re looking for.',
solution_complexity = 'simple'
WHERE code = 'J2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Digitize forms. Pre-fill known information.',
marketing_angle = 'Minimal paperwork, maximum efficiency.',
solution_complexity = 'medium'
WHERE code = 'J2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve handoff protocols. Share context between teams.',
marketing_angle = 'Seamless transitions between team members.',
solution_complexity = 'medium'
WHERE code = 'J2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Build self-service portal. Add online options.',
marketing_angle = 'Self-service options for your convenience.',
solution_complexity = 'complex'
WHERE code = 'J2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Standardize processes. Document procedures.',
marketing_angle = 'Consistent quality every single time.',
solution_complexity = 'medium'
WHERE code = 'J3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement order verification. Add accuracy checks.',
marketing_angle = 'Accurate orders, no mistakes.',
solution_complexity = 'simple'
WHERE code = 'J3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve system reliability. Add monitoring and alerts.',
marketing_angle = 'Reliable systems that are always available.',
solution_complexity = 'complex'
WHERE code = 'J3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Set clear expectations. Document what to expect.',
marketing_angle = 'No surprises - exactly what you expect.',
solution_complexity = 'simple'
WHERE code = 'J3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement quality checks. Track and reduce errors.',
marketing_angle = 'Rare mistakes with quick corrections.',
solution_complexity = 'medium'
WHERE code = 'J3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Train problem acknowledgment. Create issue intake process.',
marketing_angle = 'We acknowledge issues immediately.',
solution_complexity = 'simple'
WHERE code = 'J4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Create clear escalation paths. Empower frontline resolution.',
marketing_angle = 'Efficient resolution process.',
solution_complexity = 'medium'
WHERE code = 'J4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Set resolution time targets. Prioritize open issues.',
marketing_angle = 'Fast resolution when things go wrong.',
solution_complexity = 'medium'
WHERE code = 'J4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Verify fixes before closing. Follow up on resolutions.',
marketing_angle = 'Complete solutions, not band-aids.',
solution_complexity = 'medium'
WHERE code = 'J4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Conduct root cause analysis. Implement systemic fixes.',
marketing_angle = 'We fix problems permanently.',
solution_complexity = 'complex'
WHERE code = 'J4.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Increase cleaning frequency. Create cleaning checklists.',
marketing_angle = 'Spotlessly clean facilities.',
solution_complexity = 'simple'
WHERE code = 'E1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement preventive maintenance. Fix issues promptly.',
marketing_angle = 'Well-maintained, everything works.',
solution_complexity = 'medium'
WHERE code = 'E1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Redesign layout for flow. Add wayfinding.',
marketing_angle = 'Intuitive layout, easy to navigate.',
solution_complexity = 'complex'
WHERE code = 'E1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Upgrade equipment. Implement replacement schedule.',
marketing_angle = 'Modern, state-of-the-art equipment.',
solution_complexity = 'complex'
WHERE code = 'E1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Add clear signage. Use consistent design.',
marketing_angle = 'Clear signs and easy navigation.',
solution_complexity = 'simple'
WHERE code = 'E1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Invest in UX design. Conduct usability testing.',
marketing_angle = 'Beautiful, intuitive digital experience.',
solution_complexity = 'complex'
WHERE code = 'E2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Test all features. Fix bugs promptly.',
marketing_angle = 'Everything works, no broken buttons.',
solution_complexity = 'medium'
WHERE code = 'E2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize page load. Improve server response.',
marketing_angle = 'Lightning-fast digital experience.',
solution_complexity = 'complex'
WHERE code = 'E2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Simplify navigation. Reduce menu depth.',
marketing_angle = 'Find what you need in seconds.',
solution_complexity = 'medium'
WHERE code = 'E2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize for mobile. Test on all devices.',
marketing_angle = 'Works beautifully on any device.',
solution_complexity = 'medium'
WHERE code = 'E2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Design for desired mood. Control sensory elements.',
marketing_angle = 'Perfect atmosphere and ambiance.',
solution_complexity = 'medium'
WHERE code = 'E3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Add sound absorption. Create quiet zones.',
marketing_angle = 'Pleasant sound levels.',
solution_complexity = 'medium'
WHERE code = 'E3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Optimize HVAC. Add zone controls.',
marketing_angle = 'Perfect temperature, always comfortable.',
solution_complexity = 'medium'
WHERE code = 'E3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Manage capacity. Control entry rates.',
marketing_angle = 'Comfortable, never overcrowded.',
solution_complexity = 'medium'
WHERE code = 'E3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Invest in design. Update decor regularly.',
marketing_angle = 'Beautiful, inviting space.',
solution_complexity = 'complex'
WHERE code = 'E3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Conduct safety audits. Address hazards immediately.',
marketing_angle = 'Safety is our top priority.',
solution_complexity = 'medium'
WHERE code = 'E4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement hygiene protocols. Train staff on standards.',
marketing_angle = 'Highest hygiene standards.',
solution_complexity = 'medium'
WHERE code = 'E4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Add security measures. Protect customer property.',
marketing_angle = 'Secure environment for you and your belongings.',
solution_complexity = 'medium'
WHERE code = 'E4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Upgrade furniture. Add comfort amenities.',
marketing_angle = 'Comfortable facilities for your visit.',
solution_complexity = 'medium'
WHERE code = 'E4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Conduct emergency drills. Mark exits clearly.',
marketing_angle = 'Prepared for any emergency.',
solution_complexity = 'medium'
WHERE code = 'E4.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Extend operating hours. Consider 24/7 options.',
marketing_angle = 'Open when you need us.',
solution_complexity = 'medium'
WHERE code = 'A1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Add online booking. Increase appointment slots.',
marketing_angle = 'Easy scheduling, plenty of availability.',
solution_complexity = 'medium'
WHERE code = 'A1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Improve inventory management. Add stock alerts.',
marketing_angle = 'Always in stock when you need it.',
solution_complexity = 'medium'
WHERE code = 'A1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Hire additional staff. Optimize scheduling.',
marketing_angle = 'Plenty of staff to help you.',
solution_complexity = 'complex'
WHERE code = 'A1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Expand service area. Add new locations.',
marketing_angle = 'Convenient locations near you.',
solution_complexity = 'complex'
WHERE code = 'A1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Add ramps and elevators. Ensure ADA compliance.',
marketing_angle = 'Fully accessible for all abilities.',
solution_complexity = 'complex'
WHERE code = 'A2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Add alt text. Ensure screen reader compatibility.',
marketing_angle = 'Accessible for visually impaired users.',
solution_complexity = 'medium'
WHERE code = 'A2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Add captions and transcripts. Support hearing devices.',
marketing_angle = 'Accessible for hearing impaired users.',
solution_complexity = 'medium'
WHERE code = 'A2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Use plain language. Simplify instructions.',
marketing_angle = 'Easy to understand for everyone.',
solution_complexity = 'simple'
WHERE code = 'A2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Test with assistive technologies. Follow WCAG guidelines.',
marketing_angle = 'Works with all assistive technologies.',
solution_complexity = 'complex'
WHERE code = 'A2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Hire multilingual staff. Add translation services.',
marketing_angle = 'Service in your language.',
solution_complexity = 'medium'
WHERE code = 'A3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Train cultural competency. Celebrate diversity.',
marketing_angle = 'Welcoming to all backgrounds.',
solution_complexity = 'medium'
WHERE code = 'A3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Offer dietary alternatives. Train allergy awareness.',
marketing_angle = 'Options for all dietary needs.',
solution_complexity = 'medium'
WHERE code = 'A3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Add family amenities. Create kid-friendly options.',
marketing_angle = 'Great for the whole family.',
solution_complexity = 'medium'
WHERE code = 'A3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train bias awareness. Audit for fair treatment.',
marketing_angle = 'Equal, respectful treatment for all.',
solution_complexity = 'medium'
WHERE code = 'A3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Choose high-traffic location. Improve visibility.',
marketing_angle = 'Convenient, easy-to-find location.',
solution_complexity = 'complex'
WHERE code = 'A4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Add parking spaces. Offer validation.',
marketing_angle = 'Easy, hassle-free parking.',
solution_complexity = 'complex'
WHERE code = 'A4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Locate near transit. Add shuttle service.',
marketing_angle = 'Easy access by public transit.',
solution_complexity = 'complex'
WHERE code = 'A4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Accept all payment types. Add mobile pay.',
marketing_angle = 'Pay however you prefer.',
solution_complexity = 'simple'
WHERE code = 'A4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Add contact channels. Reduce hold times.',
marketing_angle = 'Easy to reach through any channel.',
solution_complexity = 'medium'
WHERE code = 'A4.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Review pricing strategy. Offer value tiers.',
marketing_angle = 'Competitive, fair pricing.',
solution_complexity = 'complex'
WHERE code = 'V1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Benchmark against expectations. Communicate value.',
marketing_angle = 'Pricing that matches expectations.',
solution_complexity = 'medium'
WHERE code = 'V1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Conduct competitor analysis. Justify premium or match.',
marketing_angle = 'Competitive with the market.',
solution_complexity = 'medium'
WHERE code = 'V1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Display ALL fees upfront. Eliminate surprise charges.',
marketing_angle = 'Complete price transparency - no hidden fees.',
solution_complexity = 'simple'
WHERE code = 'V1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Offer payment plans. Add financing options.',
marketing_angle = 'Flexible payment options available.',
solution_complexity = 'medium'
WHERE code = 'V1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Create clear price lists. Explain pricing structure.',
marketing_angle = 'Clear, easy-to-understand pricing.',
solution_complexity = 'simple'
WHERE code = 'V2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'List all fees upfront. Include in quotes.',
marketing_angle = 'Full disclosure of all charges.',
solution_complexity = 'simple'
WHERE code = 'V2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Audit marketing claims. Ensure accuracy.',
marketing_angle = 'Honest, accurate advertising.',
solution_complexity = 'simple'
WHERE code = 'V2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Simplify contracts. Highlight key terms.',
marketing_angle = 'Fair, straightforward terms.',
solution_complexity = 'medium'
WHERE code = 'V2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Verify all claims. Provide evidence.',
marketing_angle = 'Honest representation of our services.',
solution_complexity = 'simple'
WHERE code = 'V2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Streamline processes. Reduce customer time.',
marketing_angle = 'Quick and easy, respecting your time.',
solution_complexity = 'medium'
WHERE code = 'V3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Simplify decisions. Provide guidance.',
marketing_angle = 'Easy decisions, minimal stress.',
solution_complexity = 'medium'
WHERE code = 'V3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Offer delivery/pickup. Reduce physical burden.',
marketing_angle = 'Convenient, minimal effort required.',
solution_complexity = 'medium'
WHERE code = 'V3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Reduce friction points. Improve processes.',
marketing_angle = 'Smooth, hassle-free experience.',
solution_complexity = 'medium'
WHERE code = 'V3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Demonstrate value clearly. Compare alternatives.',
marketing_angle = 'Worth every moment of your time.',
solution_complexity = 'simple'
WHERE code = 'V3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Communicate value proposition. Demonstrate ROI.',
marketing_angle = 'Exceptional value for your investment.',
solution_complexity = 'medium'
WHERE code = 'V4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Ensure quality matches price. Add value-adds.',
marketing_angle = 'Quality that justifies the price.',
solution_complexity = 'medium'
WHERE code = 'V4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Track satisfaction. Follow up post-purchase.',
marketing_angle = 'Complete satisfaction guaranteed.',
solution_complexity = 'medium'
WHERE code = 'V4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Encourage referrals. Make sharing easy.',
marketing_angle = 'So good, you''ll tell your friends.',
solution_complexity = 'simple'
WHERE code = 'V4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Build loyalty program. Reward returns.',
marketing_angle = 'Worth coming back for, again and again.',
solution_complexity = 'medium'
WHERE code = 'V4.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Train honest communication. Build trust culture.',
marketing_angle = 'Complete honesty and transparency.',
solution_complexity = 'medium'
WHERE code = 'R1.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Document commitments. Track promises made.',
marketing_angle = 'We always keep our promises.',
solution_complexity = 'simple'
WHERE code = 'R1.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Share policies openly. Communicate changes.',
marketing_angle = 'Open and transparent in everything we do.',
solution_complexity = 'simple'
WHERE code = 'R1.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Define ethical standards. Train compliance.',
marketing_angle = 'Ethical business practices you can trust.',
solution_complexity = 'medium'
WHERE code = 'R1.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Ensure consistent treatment. Audit fairness.',
marketing_angle = 'Fair dealing with every customer.',
solution_complexity = 'medium'
WHERE code = 'R1.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Track customer history. Learn from patterns.',
marketing_angle = 'Proven track record of excellence.',
solution_complexity = 'medium'
WHERE code = 'R2.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Standardize experience. Reduce variation.',
marketing_angle = 'Consistent excellence, every visit.',
solution_complexity = 'medium'
WHERE code = 'R2.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Communicate changes. Maintain core values.',
marketing_angle = 'Stable and reliable, year after year.',
solution_complexity = 'medium'
WHERE code = 'R2.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Build trust incrementally. Honor commitments.',
marketing_angle = 'A business you can trust completely.',
solution_complexity = 'medium'
WHERE code = 'R2.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Honor warranties promptly. Exceed guarantees.',
marketing_angle = 'We stand behind our guarantees.',
solution_complexity = 'medium'
WHERE code = 'R2.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Train admission of mistakes. Empower acknowledgment.',
marketing_angle = 'We own our mistakes.',
solution_complexity = 'simple'
WHERE code = 'R3.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Develop sincere apology training. Show genuine regret.',
marketing_angle = 'Genuine apologies when things go wrong.',
solution_complexity = 'simple'
WHERE code = 'R3.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Develop compensation policies. Empower service recovery.',
marketing_angle = 'We make things right with meaningful gestures.',
solution_complexity = 'medium'
WHERE code = 'R3.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Conduct post-mortem reviews. Implement learnings.',
marketing_angle = 'We continuously improve from feedback.',
solution_complexity = 'medium'
WHERE code = 'R3.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Train ownership mentality. Remove blame culture.',
marketing_angle = 'Full accountability when issues arise.',
solution_complexity = 'medium'
WHERE code = 'R3.05';
UPDATE pipeline.urt_subcodes
SET solution = 'Implement CRM. Train staff on customer history.',
marketing_angle = 'We remember you and value your loyalty.',
solution_complexity = 'medium'
WHERE code = 'R4.01';
UPDATE pipeline.urt_subcodes
SET solution = 'Create meaningful loyalty program. Offer real value.',
marketing_angle = 'Rewarding loyalty with meaningful perks.',
solution_complexity = 'medium'
WHERE code = 'R4.02';
UPDATE pipeline.urt_subcodes
SET solution = 'Train relationship building. Encourage personal connections.',
marketing_angle = 'More than transactions - real relationships.',
solution_complexity = 'medium'
WHERE code = 'R4.03';
UPDATE pipeline.urt_subcodes
SET solution = 'Personalize communications. Add value in outreach.',
marketing_angle = 'Helpful updates, not just promotions.',
solution_complexity = 'medium'
WHERE code = 'R4.04';
UPDATE pipeline.urt_subcodes
SET solution = 'Build community events. Create belonging.',
marketing_angle = 'Part of our community.',
solution_complexity = 'medium'
WHERE code = 'R4.05';
COMMIT;
-- Verify updates
SELECT code, name, solution_complexity, LEFT(solution, 50) as solution_preview
FROM pipeline.urt_subcodes
WHERE solution IS NOT NULL
ORDER BY code
LIMIT 10;

View File

@@ -0,0 +1,102 @@
-- =============================================================================
-- Migration: 012_sync_urt_subcodes_from_taxonomy.sql
-- Purpose: Sync missing URT subcodes from taxonomy v5.1 to database
-- =============================================================================
-- Insert missing subcodes (ON CONFLICT DO UPDATE to sync names/definitions)
INSERT INTO pipeline.urt_subcodes (code, category_code, domain_code, name, definition, positive_example, negative_example) VALUES
-- J1: Wait Times (missing J1.04, J1.05)
('J1.04', 'J1', 'J', 'Punctuality', 'Meeting scheduled times', 'Always on time', 'Two hours late'),
('J1.05', 'J1', 'J', 'Pacing', 'Appropriate speed (not rushed/dragged)', 'Perfect pace throughout', 'Felt rushed through everything'),
-- J2: Booking & Reservations (missing J2.04, J2.05)
('J2.04', 'J2', 'J', 'Booking Availability', 'Slots/capacity when needed', 'Always available slots', 'Fully booked for weeks'),
('J2.05', 'J2', 'J', 'Inventory', 'Stock availability', 'Always in stock', 'Out of stock constantly'),
-- J3: System Reliability (missing J3.04, J3.05)
('J3.04', 'J3', 'J', 'Data Accuracy', 'Correct info in systems', 'All details correct', 'Wrong info in my account'),
('J3.05', 'J3', 'J', 'Integration', 'Systems work together', 'Seamless between channels', 'Info doesn''t sync'),
-- J4: Problem Resolution (missing J4.04, J4.05)
('J4.04', 'J4', 'J', 'Escalation', 'Getting to right person', 'Quickly got to manager', 'Endless transfers'),
('J4.05', 'J4', 'J', 'Closure', 'Issue fully resolved', 'Problem completely solved', 'Issue still not fixed'),
-- A1: Physical Access (missing A1.04, A1.05)
('A1.04', 'A1', 'A', 'Wayfinding', 'Finding destination', 'Easy to find', 'Got lost trying to find it'),
('A1.05', 'A1', 'A', 'Physical Accessibility', 'Disability accommodations', 'Wheelchair accessible', 'No ramps or elevators'),
-- A2: Channel Access (missing A2.04, A2.05)
('A2.04', 'A2', 'A', 'Language Accessibility', 'Multilingual support', 'Available in my language', 'No translation available'),
('A2.05', 'A2', 'A', 'Hours of Operation', 'Service availability times', 'Open when needed', 'Terrible hours'),
-- A3: Information Access (missing A3.04, A3.05)
('A3.04', 'A3', 'A', 'Documentation Clarity', 'Clear instructions', 'Easy to understand docs', 'Confusing instructions'),
('A3.05', 'A3', 'A', 'Support Accessibility', 'Getting help when needed', 'Easy to reach support', 'Impossible to get help'),
-- A4: Financial Access (missing A4.04, A4.05)
('A4.04', 'A4', 'A', 'Payment Flexibility', 'Multiple payment options', 'Many payment options', 'Only accepts cash'),
('A4.05', 'A4', 'A', 'Refund Accessibility', 'Getting money back', 'Easy refund process', 'Impossible to get refund'),
-- E1: Physical Environment (missing E1.04, E1.05)
('E1.04', 'E1', 'E', 'Ambiance', 'Atmosphere and vibe', 'Great atmosphere', 'Depressing environment'),
('E1.05', 'E1', 'E', 'Comfort', 'Physical comfort', 'Very comfortable', 'Uncomfortable seating'),
-- E2: Digital Environment (missing E2.04, E2.05)
('E2.04', 'E2', 'E', 'Visual Design', 'Aesthetics of interface', 'Beautiful design', 'Ugly interface'),
('E2.05', 'E2', 'E', 'Mobile Experience', 'Mobile usability', 'Great mobile app', 'Terrible mobile site'),
-- E3: Safety & Security (missing E3.04, E3.05)
('E3.04', 'E3', 'E', 'Health Safety', 'Health precautions', 'Very clean and safe', 'Unsanitary conditions'),
('E3.05', 'E3', 'E', 'Cyber Security', 'Digital security', 'Secure platform', 'Got hacked'),
-- E4: Sustainability (missing E4.04, E4.05)
('E4.04', 'E4', 'E', 'Social Responsibility', 'Ethical practices', 'Ethical company', 'Exploitative practices'),
('E4.05', 'E4', 'E', 'Community Impact', 'Local community effect', 'Supports local community', 'Hurts local businesses'),
-- V1: Pricing (missing V1.04, V1.05)
('V1.04', 'V1', 'V', 'Price Transparency', 'Clear pricing', 'Clear pricing upfront', 'Hidden costs everywhere'),
('V1.05', 'V1', 'V', 'Price Stability', 'Consistent pricing', 'Same price always', 'Prices keep changing'),
-- V2: Value Perception (missing V2.04, V2.05)
('V2.04', 'V2', 'V', 'Quality-Price Ratio', 'Worth vs cost', 'Excellent quality for price', 'Overpriced for quality'),
('V2.05', 'V2', 'V', 'Competitive Value', 'Compared to alternatives', 'Best value around', 'Better deals elsewhere'),
-- V3: Promotions (missing V3.04, V3.05)
('V3.04', 'V3', 'V', 'Promotion Clarity', 'Clear offer terms', 'Clear promotion rules', 'Misleading promotions'),
('V3.05', 'V3', 'V', 'Reward Redemption', 'Using points/rewards', 'Easy to redeem rewards', 'Hard to use points'),
-- V4: Billing (missing V4.04, V4.05)
('V4.04', 'V4', 'V', 'Billing Accuracy', 'Correct charges', 'Always billed correctly', 'Overcharged constantly'),
('V4.05', 'V4', 'V', 'Billing Resolution', 'Fixing billing issues', 'Quick billing fix', 'Billing disputes ignored'),
-- R1: Trust (missing R1.04, R1.05)
('R1.04', 'R1', 'R', 'Ethics', 'Ethical behavior', 'Very ethical company', 'Unethical practices'),
('R1.05', 'R1', 'R', 'Accountability', 'Taking responsibility', 'Owned their mistakes', 'Never takes blame'),
-- R2: Reliability (missing R2.04, R2.05)
('R2.04', 'R2', 'R', 'Predictability', 'Consistent experience', 'Always know what to expect', 'Every visit is different'),
('R2.05', 'R2', 'R', 'Standards', 'Meeting quality standards', 'High standards maintained', 'Standards have dropped'),
-- R3: Care (missing R3.04, R3.05)
('R3.04', 'R3', 'R', 'Personal Connection', 'Human touch', 'Felt like family', 'Treated like a number'),
('R3.05', 'R3', 'R', 'Going Extra Mile', 'Beyond expectations', 'Went above and beyond', 'Minimum effort only'),
-- R4: Recovery (missing R4.04, R4.05)
('R4.04', 'R4', 'R', 'Service Recovery', 'Making things right', 'Fixed problem perfectly', 'Made it worse'),
('R4.05', 'R4', 'R', 'Feedback Response', 'Acting on feedback', 'Implemented my suggestion', 'Feedback ignored')
ON CONFLICT (code) DO UPDATE SET
name = EXCLUDED.name,
definition = EXCLUDED.definition,
positive_example = EXCLUDED.positive_example,
negative_example = EXCLUDED.negative_example;
-- Verify count
DO $$
DECLARE
subcode_count INTEGER;
BEGIN
SELECT COUNT(*) INTO subcode_count FROM pipeline.urt_subcodes;
RAISE NOTICE 'Total subcodes after sync: %', subcode_count;
END $$;

View File

@@ -0,0 +1,411 @@
-- Migration: Insert frozen primitive dictionary (36 primitives)
-- Description: Populates the primitives table with the complete URT taxonomy
-- Date: 2025-01-31
-- Quality dimension (8 primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'EFFECTIVENESS',
'QUALITY',
'Effectiveness',
'Did it achieve its intended purpose?',
FALSE,
'["worked perfectly", "exactly what I needed", "solved my problem"]',
'["didn''t work", "useless", "waste of time"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'TASTE',
'QUALITY',
'Taste',
'Sensory quality (flavor, texture, smell)',
FALSE,
'["delicious", "amazing taste", "flavorful"]',
'["bland", "tasteless", "disgusting"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'CRAFT',
'QUALITY',
'Craft',
'Skill of execution, workmanship',
FALSE,
'["well-made", "professional", "quality work"]',
'["sloppy", "poorly made", "amateur"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'ACCURACY',
'QUALITY',
'Accuracy',
'Correct as ordered/specified',
FALSE,
'["exactly what I ordered", "perfect", "got everything right"]',
'["wrong order", "missing items", "not what I asked for"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'FRESHNESS',
'QUALITY',
'Freshness',
'Fresh vs stale/expired',
FALSE,
'["fresh", "just made", "new"]',
'["stale", "old", "expired"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'TEMPERATURE',
'QUALITY',
'Temperature',
'Appropriate temperature for the item',
FALSE,
'["hot", "perfect temperature", "cold as it should be"]',
'["cold", "lukewarm", "too hot", "room temperature"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'CONDITION',
'QUALITY',
'Condition',
'Physical state, damage, defects',
FALSE,
'["perfect condition", "like new", "undamaged"]',
'["damaged", "broken", "defective"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'CONSISTENCY',
'QUALITY',
'Consistency',
'Same quality across visits/units',
FALSE,
'["always consistent", "reliable quality", "same every time"]',
'["inconsistent", "hit or miss", "varies"]'
);
-- Service dimension (4 primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'MANNER',
'SERVICE',
'Manner',
'Warmth, respect, patience in interactions',
FALSE,
'["friendly", "nice", "welcoming", "patient"]',
'["rude", "dismissive", "impatient", "attitude"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'COMPETENCE',
'SERVICE',
'Competence',
'Knowledge and skill of staff',
FALSE,
'["knowledgeable", "professional", "knew what they were doing"]',
'["clueless", "incompetent", "didn''t know"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'ATTENTIVENESS',
'SERVICE',
'Attentiveness',
'Present, notices needs, proactive',
FALSE,
'["attentive", "checked on us", "anticipated needs"]',
'["ignored", "had to flag down", "neglected"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'COMMUNICATION',
'SERVICE',
'Communication',
'Clear, listens, keeps informed',
FALSE,
'["clear", "good communication", "kept us updated"]',
'["confusing", "didn''t listen", "no updates"]'
);
-- Process dimension (4 primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'SPEED',
'PROCESS',
'Speed',
'How fast/slow things happen',
FALSE,
'["fast", "quick", "no wait"]',
'["slow", "took forever", "long wait"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'FRICTION',
'PROCESS',
'Friction',
'Ease vs obstacles in the process',
FALSE,
'["easy", "smooth", "hassle-free"]',
'["complicated", "difficult", "hassle"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RELIABILITY',
'PROCESS',
'Reliability',
'Process works consistently, no errors',
FALSE,
'["reliable", "dependable", "always works"]',
'["unreliable", "errors", "problems"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'AVAILABILITY',
'PROCESS',
'Availability',
'Hours, capacity, stock availability',
FALSE,
'["always available", "open when needed", "in stock"]',
'["closed", "sold out", "no appointments"]'
);
-- Environment dimension (6 primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'CLEANLINESS',
'ENVIRONMENT',
'Cleanliness',
'Clean, sanitary conditions',
FALSE,
'["clean", "spotless", "hygienic"]',
'["dirty", "filthy", "unsanitary"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'COMFORT',
'ENVIRONMENT',
'Comfort',
'Physical comfort of the space',
FALSE,
'["comfortable", "cozy", "spacious"]',
'["uncomfortable", "cramped", "hard seats"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'AMBIANCE',
'ENVIRONMENT',
'Ambiance',
'Vibe, atmosphere, noise level',
FALSE,
'["nice atmosphere", "great vibe", "quiet"]',
'["loud", "noisy", "bad atmosphere"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'SAFETY',
'ENVIRONMENT',
'Safety',
'Physical and health safety',
FALSE,
'["safe", "secure", "clean protocols"]',
'["unsafe", "dangerous", "health hazard"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'ACCESSIBILITY',
'ENVIRONMENT',
'Accessibility',
'Disability access, location convenience',
FALSE,
'["accessible", "easy to get to", "good parking"]',
'["hard to access", "no parking", "not wheelchair accessible"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'DIGITAL_UX',
'ENVIRONMENT',
'Digital UX',
'App/website usability and performance',
FALSE,
'["easy to use", "great app", "fast website"]',
'["app crashed", "hard to navigate", "slow website"]'
);
-- Value dimension (4 primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'PRICE_LEVEL',
'VALUE',
'Price Level',
'Absolute cost perception',
FALSE,
'["affordable", "cheap", "good prices"]',
'["expensive", "overpriced", "pricey"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'PRICE_FAIRNESS',
'VALUE',
'Price Fairness',
'Fair value for what was received',
FALSE,
'["fair price", "worth it", "good value"]',
'["rip off", "not worth it", "overcharged"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'PRICE_TRANSPARENCY',
'VALUE',
'Price Transparency',
'Clear pricing, no surprises',
FALSE,
'["clear pricing", "no hidden fees", "upfront"]',
'["hidden fees", "surprise charges", "bait and switch"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'VALUE_FOR_MONEY',
'VALUE',
'Value for Money',
'Overall worth judgment',
FALSE,
'["great value", "worth every penny", "good deal"]',
'["bad value", "waste of money", "not worth it"]'
);
-- Trust dimension (3 meta primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'HONESTY',
'TRUST',
'Honesty',
'Truthful, no deception',
TRUE,
'["honest", "transparent", "truthful"]',
'["lied", "deceived", "dishonest", "scam"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'ETHICS',
'TRUST',
'Ethics',
'Ethical, fair dealing',
TRUE,
'["ethical", "fair", "integrity"]',
'["unethical", "shady", "crooked"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'PROMISES',
'TRUST',
'Promises',
'Kept or broken commitments',
TRUE,
'["kept their word", "delivered as promised", "reliable"]',
'["broke promise", "didn''t deliver", "false advertising"]'
);
-- Resolution dimension (3 meta primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'ACKNOWLEDGMENT',
'RESOLUTION',
'Acknowledgment',
'Recognized the problem',
TRUE,
'["acknowledged", "apologized", "admitted mistake"]',
'["denied", "dismissed", "blamed me"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RESPONSE_QUALITY',
'RESOLUTION',
'Response Quality',
'How well they handled the issue',
TRUE,
'["handled well", "resolved quickly", "took care of it"]',
'["ignored complaint", "unhelpful", "made it worse"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RECOVERY',
'RESOLUTION',
'Recovery',
'Made it right, compensation',
TRUE,
'["made it right", "refunded", "compensated"]',
'["refused refund", "no compensation", "wouldn''t fix"]'
);
-- Loyalty dimension (3 meta primitives)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RETURN_INTENT',
'LOYALTY',
'Return Intent',
'Will/won''t come back',
TRUE,
'["will be back", "returning customer", "coming again"]',
'["never again", "won''t return", "last time"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RECOMMEND',
'LOYALTY',
'Recommend',
'Would/wouldn''t recommend',
TRUE,
'["highly recommend", "tell everyone", "must try"]',
'["avoid", "don''t go", "stay away", "wouldn''t recommend"]'
);
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'RECOGNITION',
'LOYALTY',
'Recognition',
'Felt valued, remembered',
TRUE,
'["remembered me", "felt valued", "personal touch"]',
'["treated like a number", "didn''t care", "no loyalty"]'
);
-- Escape dimension (1 meta primitive)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES (
'UNMAPPED',
'ESCAPE',
'Unmapped',
'Does not fit taxonomy; preserve evidence',
TRUE,
'[]',
'[]'
);
-- Verify count
-- SELECT COUNT(*) FROM pipeline.primitives; -- Should return 36

View File

@@ -0,0 +1,561 @@
-- =============================================================================
-- Migration: 014_primitive_classification_system.sql
-- Purpose: Create primitive classification system for context-aware review analysis
-- =============================================================================
--
-- This migration introduces a "primitive" classification system that allows
-- industry-specific and category-specific configuration of what aspects to
-- look for when classifying reviews.
--
-- Components:
-- 1. pipeline.primitives - Frozen dictionary of primitives (quality dimensions)
-- 2. ALTER public.gbp_categories - Add primitive_configs and business_context
-- 3. pipeline.jsonb_deep_merge() - Recursive JSONB merge function
-- 4. pipeline.resolve_primitive_config() - Resolve configs through category tree
-- 5. pipeline.get_classification_context() - Get full classification context
--
-- Date: 2026-01-31
-- =============================================================================
-- =============================================================================
-- SECTION 1: PRIMITIVES TABLE (Frozen Dictionary)
-- =============================================================================
CREATE TABLE IF NOT EXISTS pipeline.primitives (
code VARCHAR(30) PRIMARY KEY,
dimension VARCHAR(20) NOT NULL, -- quality, service, process, environment, value, trust, resolution, loyalty, escape
name VARCHAR(100) NOT NULL,
definition TEXT NOT NULL,
is_meta BOOLEAN DEFAULT FALSE, -- true for always-active primitives (HONESTY, ETHICS, etc.)
base_positive_signals TEXT[],
base_negative_signals TEXT[],
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index on dimension for filtering
CREATE INDEX IF NOT EXISTS idx_primitives_dimension ON pipeline.primitives(dimension);
-- Index on is_meta for quick access to always-active primitives
CREATE INDEX IF NOT EXISTS idx_primitives_is_meta ON pipeline.primitives(is_meta) WHERE is_meta = TRUE;
COMMENT ON TABLE pipeline.primitives IS 'Frozen dictionary of classification primitives (quality dimensions)';
COMMENT ON COLUMN pipeline.primitives.code IS 'Unique identifier for the primitive (e.g., FOOD_TASTE, SERVICE_SPEED)';
COMMENT ON COLUMN pipeline.primitives.dimension IS 'Category of the primitive (quality, service, process, etc.)';
COMMENT ON COLUMN pipeline.primitives.is_meta IS 'If true, this primitive is always active regardless of category config';
COMMENT ON COLUMN pipeline.primitives.base_positive_signals IS 'Default positive signal keywords for this primitive';
COMMENT ON COLUMN pipeline.primitives.base_negative_signals IS 'Default negative signal keywords for this primitive';
-- =============================================================================
-- SECTION 2: ALTER gbp_categories TABLE
-- =============================================================================
-- Add primitive_configs column (JSONB for flexible config)
ALTER TABLE public.gbp_categories
ADD COLUMN IF NOT EXISTS primitive_configs JSONB DEFAULT '{}';
-- Add business_context column (JSONB for industry-specific context)
ALTER TABLE public.gbp_categories
ADD COLUMN IF NOT EXISTS business_context JSONB DEFAULT '{}';
-- Add config versioning columns
ALTER TABLE public.gbp_categories
ADD COLUMN IF NOT EXISTS config_version VARCHAR(20);
ALTER TABLE public.gbp_categories
ADD COLUMN IF NOT EXISTS config_generated_by VARCHAR(100);
ALTER TABLE public.gbp_categories
ADD COLUMN IF NOT EXISTS config_updated_at TIMESTAMP WITH TIME ZONE;
-- GIN indexes for JSONB containment queries
CREATE INDEX IF NOT EXISTS idx_gbp_categories_primitive_configs
ON public.gbp_categories USING GIN (primitive_configs);
CREATE INDEX IF NOT EXISTS idx_gbp_categories_business_context
ON public.gbp_categories USING GIN (business_context);
-- Index for config version lookups
CREATE INDEX IF NOT EXISTS idx_gbp_categories_config_version
ON public.gbp_categories(config_version) WHERE config_version IS NOT NULL;
COMMENT ON COLUMN public.gbp_categories.primitive_configs IS 'JSONB config for primitives at this category level (inherits from ancestors)';
COMMENT ON COLUMN public.gbp_categories.business_context IS 'JSONB business context for this category (industry-specific terminology, etc.)';
COMMENT ON COLUMN public.gbp_categories.config_version IS 'Version of the primitive config (for cache invalidation)';
COMMENT ON COLUMN public.gbp_categories.config_generated_by IS 'Tool/model that generated this config';
COMMENT ON COLUMN public.gbp_categories.config_updated_at IS 'When the config was last updated';
-- =============================================================================
-- SECTION 3: JSONB DEEP MERGE FUNCTION
-- =============================================================================
-- Recursive JSONB merge function
-- - Objects: recursively merge (override wins on conflicts)
-- - Arrays: union with dedup by default
-- - If object has "__replace__": true, replace entirely instead of merge
CREATE OR REPLACE FUNCTION pipeline.jsonb_deep_merge(
base JSONB,
override JSONB
) RETURNS JSONB AS $$
DECLARE
result JSONB;
key TEXT;
base_value JSONB;
override_value JSONB;
merged_array JSONB;
BEGIN
-- Handle NULL cases
IF base IS NULL THEN
RETURN override;
END IF;
IF override IS NULL THEN
RETURN base;
END IF;
-- If override has __replace__ flag, return override without the flag
IF jsonb_typeof(override) = 'object' AND override ? '__replace__' AND (override->>'__replace__')::boolean = true THEN
RETURN override - '__replace__';
END IF;
-- If both are not objects, override wins
IF jsonb_typeof(base) != 'object' OR jsonb_typeof(override) != 'object' THEN
RETURN override;
END IF;
-- Both are objects, merge recursively
result := base;
FOR key IN SELECT jsonb_object_keys(override)
LOOP
override_value := override->key;
IF NOT (base ? key) THEN
-- Key doesn't exist in base, just add it
result := result || jsonb_build_object(key, override_value);
ELSE
base_value := base->key;
-- Check for __replace__ flag in the override value
IF jsonb_typeof(override_value) = 'object'
AND override_value ? '__replace__'
AND (override_value->>'__replace__')::boolean = true THEN
-- Replace entirely (without the __replace__ flag)
result := result || jsonb_build_object(key, override_value - '__replace__');
-- If both are objects, recurse
ELSIF jsonb_typeof(base_value) = 'object' AND jsonb_typeof(override_value) = 'object' THEN
result := result || jsonb_build_object(
key,
pipeline.jsonb_deep_merge(base_value, override_value)
);
-- If both are arrays, union with dedup
ELSIF jsonb_typeof(base_value) = 'array' AND jsonb_typeof(override_value) = 'array' THEN
-- Union arrays, remove duplicates
-- Using a subquery to deduplicate
SELECT jsonb_agg(DISTINCT elem)
INTO merged_array
FROM (
SELECT jsonb_array_elements(base_value) AS elem
UNION
SELECT jsonb_array_elements(override_value) AS elem
) AS combined;
result := result || jsonb_build_object(key, COALESCE(merged_array, '[]'::jsonb));
-- Otherwise, override wins
ELSE
result := result || jsonb_build_object(key, override_value);
END IF;
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
COMMENT ON FUNCTION pipeline.jsonb_deep_merge(JSONB, JSONB) IS
'Recursively merges two JSONB objects. Objects are merged recursively (override wins on conflicts).
Arrays are unioned with dedup. Use {"__replace__": true, ...} to replace instead of merge.';
-- =============================================================================
-- SECTION 4: RESOLVE PRIMITIVE CONFIG FUNCTION
-- =============================================================================
-- Resolves primitive config by merging ancestor configs (general -> specific)
CREATE OR REPLACE FUNCTION pipeline.resolve_primitive_config(
p_path ltree
) RETURNS JSONB AS $$
DECLARE
result JSONB := '{}';
row_config JSONB;
BEGIN
-- Fetch all ancestor nodes (including self), ordered by level ASC (general -> specific)
-- Uses @> operator: p_path is a descendant of (or equal to) the node's path
FOR row_config IN
SELECT primitive_configs
FROM public.gbp_categories
WHERE p_path <@ path -- p_path is descendant of or equal to path
ORDER BY level ASC
LOOP
-- Skip NULL or empty configs
IF row_config IS NOT NULL AND row_config != '{}' THEN
result := pipeline.jsonb_deep_merge(result, row_config);
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE;
COMMENT ON FUNCTION pipeline.resolve_primitive_config(ltree) IS
'Resolves the full primitive config for a category path by merging all ancestor configs from general to specific.';
-- =============================================================================
-- SECTION 5: RESOLVE BUSINESS CONTEXT FUNCTION
-- =============================================================================
-- Resolves business context by merging ancestor contexts (general -> specific)
CREATE OR REPLACE FUNCTION pipeline.resolve_business_context(
p_path ltree
) RETURNS JSONB AS $$
DECLARE
result JSONB := '{}';
row_context JSONB;
BEGIN
-- Fetch all ancestor nodes (including self), ordered by level ASC (general -> specific)
FOR row_context IN
SELECT business_context
FROM public.gbp_categories
WHERE p_path <@ path
ORDER BY level ASC
LOOP
-- Skip NULL or empty contexts
IF row_context IS NOT NULL AND row_context != '{}' THEN
result := pipeline.jsonb_deep_merge(result, row_context);
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE;
COMMENT ON FUNCTION pipeline.resolve_business_context(ltree) IS
'Resolves the full business context for a category path by merging all ancestor contexts from general to specific.';
-- =============================================================================
-- SECTION 6: GET CLASSIFICATION CONTEXT FUNCTION
-- =============================================================================
-- Returns complete classification context for a category path
CREATE OR REPLACE FUNCTION pipeline.get_classification_context(
p_path ltree
) RETURNS JSONB AS $$
DECLARE
resolved_primitives JSONB;
resolved_context JSONB;
primitives_dict JSONB;
BEGIN
-- Resolve the primitive config for this path
resolved_primitives := pipeline.resolve_primitive_config(p_path);
-- Resolve the business context for this path
resolved_context := pipeline.resolve_business_context(p_path);
-- Build the primitives dictionary from the primitives table
SELECT jsonb_object_agg(
code,
jsonb_build_object(
'code', code,
'dimension', dimension,
'name', name,
'definition', definition,
'is_meta', is_meta,
'base_positive_signals', COALESCE(to_jsonb(base_positive_signals), '[]'::jsonb),
'base_negative_signals', COALESCE(to_jsonb(base_negative_signals), '[]'::jsonb)
)
)
INTO primitives_dict
FROM pipeline.primitives;
-- Handle case where primitives table is empty
IF primitives_dict IS NULL THEN
primitives_dict := '{}'::jsonb;
END IF;
-- Return combined context object
RETURN jsonb_build_object(
'primitive_configs', resolved_primitives,
'business_context', resolved_context,
'primitives_dictionary', primitives_dict,
'category_path', p_path::text,
'resolved_at', NOW()
);
END;
$$ LANGUAGE plpgsql STABLE;
COMMENT ON FUNCTION pipeline.get_classification_context(ltree) IS
'Returns complete classification context for a category path, including resolved primitive configs,
business context, and the full primitives dictionary.';
-- =============================================================================
-- SECTION 7: HELPER FUNCTION - GET ACTIVE PRIMITIVES
-- =============================================================================
-- Returns the list of active primitive codes for a category path
-- (includes meta primitives + enabled primitives from config)
CREATE OR REPLACE FUNCTION pipeline.get_active_primitives(
p_path ltree
) RETURNS TEXT[] AS $$
DECLARE
resolved_config JSONB;
active_codes TEXT[];
meta_codes TEXT[];
config_enabled TEXT[];
config_disabled TEXT[];
BEGIN
-- Get resolved config
resolved_config := pipeline.resolve_primitive_config(p_path);
-- Get all meta primitives (always active)
SELECT array_agg(code)
INTO meta_codes
FROM pipeline.primitives
WHERE is_meta = TRUE;
-- Get enabled primitives from config
IF resolved_config ? 'enabled' THEN
SELECT array_agg(elem::text)
INTO config_enabled
FROM jsonb_array_elements_text(resolved_config->'enabled') AS elem;
END IF;
-- Get disabled primitives from config
IF resolved_config ? 'disabled' THEN
SELECT array_agg(elem::text)
INTO config_disabled
FROM jsonb_array_elements_text(resolved_config->'disabled') AS elem;
END IF;
-- Combine: meta + enabled, minus disabled
active_codes := COALESCE(meta_codes, ARRAY[]::TEXT[]) || COALESCE(config_enabled, ARRAY[]::TEXT[]);
-- Remove disabled primitives
IF config_disabled IS NOT NULL THEN
active_codes := array(
SELECT unnest(active_codes)
EXCEPT
SELECT unnest(config_disabled)
);
END IF;
-- Remove duplicates
active_codes := array(SELECT DISTINCT unnest(active_codes));
RETURN active_codes;
END;
$$ LANGUAGE plpgsql STABLE;
COMMENT ON FUNCTION pipeline.get_active_primitives(ltree) IS
'Returns array of active primitive codes for a category path (meta primitives + enabled - disabled).';
-- =============================================================================
-- SECTION 8: SEED INITIAL PRIMITIVES (Examples)
-- =============================================================================
-- Insert some example primitives (can be extended later)
INSERT INTO pipeline.primitives (code, dimension, name, definition, is_meta, base_positive_signals, base_negative_signals)
VALUES
-- Meta primitives (always active)
('HONESTY', 'trust', 'Honesty & Truthfulness', 'Whether the business is perceived as honest and truthful in their dealings', TRUE,
ARRAY['honest', 'truthful', 'transparent', 'upfront', 'no hidden'],
ARRAY['lied', 'dishonest', 'deceptive', 'misleading', 'hidden fees', 'bait and switch']),
('ETHICS', 'trust', 'Ethical Behavior', 'Whether the business behaves ethically and with integrity', TRUE,
ARRAY['ethical', 'integrity', 'fair', 'principled', 'moral'],
ARRAY['unethical', 'scam', 'fraud', 'cheat', 'ripoff', 'shady']),
('SAFETY', 'trust', 'Safety & Security', 'Whether customers feel safe and secure', TRUE,
ARRAY['safe', 'secure', 'protected', 'trust'],
ARRAY['unsafe', 'dangerous', 'security concern', 'risk', 'hazard']),
-- Quality dimension primitives
('FOOD_TASTE', 'quality', 'Food Taste & Flavor', 'Quality and taste of food items', FALSE,
ARRAY['delicious', 'tasty', 'flavorful', 'yummy', 'amazing taste', 'perfectly seasoned'],
ARRAY['bland', 'tasteless', 'bad taste', 'over-seasoned', 'under-seasoned', 'disgusting']),
('FOOD_FRESHNESS', 'quality', 'Food Freshness', 'Freshness of ingredients and food items', FALSE,
ARRAY['fresh', 'crisp', 'just made', 'homemade', 'organic'],
ARRAY['stale', 'old', 'not fresh', 'frozen', 'reheated', 'expired']),
('FOOD_PORTION', 'quality', 'Portion Size', 'Size and quantity of food servings', FALSE,
ARRAY['generous portions', 'large serving', 'filling', 'plenty of food'],
ARRAY['small portions', 'tiny', 'not enough', 'skimpy', 'overpriced for size']),
('PRODUCT_QUALITY', 'quality', 'Product Quality', 'Overall quality of products', FALSE,
ARRAY['high quality', 'well made', 'premium', 'durable', 'excellent quality'],
ARRAY['poor quality', 'cheap', 'flimsy', 'broke easily', 'defective']),
-- Service dimension primitives
('SERVICE_SPEED', 'service', 'Service Speed', 'Speed and timeliness of service', FALSE,
ARRAY['fast', 'quick', 'prompt', 'efficient', 'no wait'],
ARRAY['slow', 'long wait', 'took forever', 'delayed', 'waited too long']),
('SERVICE_FRIENDLINESS', 'service', 'Staff Friendliness', 'Friendliness and warmth of staff', FALSE,
ARRAY['friendly', 'welcoming', 'warm', 'nice', 'pleasant', 'smiled'],
ARRAY['rude', 'unfriendly', 'cold', 'dismissive', 'attitude', 'ignored']),
('SERVICE_KNOWLEDGE', 'service', 'Staff Knowledge', 'Knowledge and expertise of staff', FALSE,
ARRAY['knowledgeable', 'expert', 'helpful advice', 'knew their stuff', 'professional'],
ARRAY['clueless', 'didnt know', 'unhelpful', 'inexperienced', 'untrained']),
('SERVICE_ATTENTIVENESS', 'service', 'Staff Attentiveness', 'How attentive staff are to customer needs', FALSE,
ARRAY['attentive', 'checked on us', 'responsive', 'available', 'proactive'],
ARRAY['inattentive', 'ignored', 'couldnt find anyone', 'had to flag down', 'neglected']),
-- Environment dimension primitives
('ENV_CLEANLINESS', 'environment', 'Cleanliness', 'Cleanliness of the establishment', FALSE,
ARRAY['clean', 'spotless', 'tidy', 'well-maintained', 'hygienic'],
ARRAY['dirty', 'filthy', 'messy', 'gross', 'sticky', 'unhygienic']),
('ENV_AMBIANCE', 'environment', 'Ambiance & Atmosphere', 'Overall atmosphere and vibe', FALSE,
ARRAY['great atmosphere', 'nice ambiance', 'cozy', 'relaxing', 'beautiful decor'],
ARRAY['bad atmosphere', 'uncomfortable', 'loud', 'cramped', 'depressing']),
('ENV_PARKING', 'environment', 'Parking Availability', 'Availability and convenience of parking', FALSE,
ARRAY['easy parking', 'plenty of parking', 'free parking', 'valet available'],
ARRAY['no parking', 'hard to park', 'paid parking', 'had to park far']),
-- Value dimension primitives
('VALUE_PRICE', 'value', 'Price Level', 'Perception of price levels', FALSE,
ARRAY['affordable', 'reasonable prices', 'cheap', 'good deal', 'budget-friendly'],
ARRAY['expensive', 'overpriced', 'pricey', 'not worth the price', 'too costly']),
('VALUE_WORTH', 'value', 'Value for Money', 'Whether the experience is worth the cost', FALSE,
ARRAY['worth it', 'great value', 'bang for buck', 'money well spent'],
ARRAY['not worth it', 'waste of money', 'rip off', 'should be cheaper']),
-- Process dimension primitives
('PROCESS_BOOKING', 'process', 'Booking & Reservations', 'Ease of making reservations or appointments', FALSE,
ARRAY['easy to book', 'simple reservation', 'available appointments', 'online booking'],
ARRAY['hard to book', 'no availability', 'complicated booking', 'had to call multiple times']),
('PROCESS_WAIT', 'process', 'Wait Times', 'Time spent waiting for service', FALSE,
ARRAY['no wait', 'seated immediately', 'quick turnaround'],
ARRAY['long wait', 'waited forever', 'always busy', 'need to wait in line']),
-- Resolution dimension primitives
('RESOLUTION_RESPONSE', 'resolution', 'Problem Response', 'How problems and complaints are handled', FALSE,
ARRAY['fixed the issue', 'made it right', 'apologized', 'took responsibility'],
ARRAY['ignored complaint', 'didnt care', 'blamed me', 'no resolution', 'refused to help']),
-- Loyalty dimension primitives
('LOYALTY_RETURN', 'loyalty', 'Return Intent', 'Whether customers intend to return', FALSE,
ARRAY['will be back', 'coming back', 'regular customer', 'my go-to place'],
ARRAY['never again', 'wont return', 'last time', 'not coming back']),
('LOYALTY_RECOMMEND', 'loyalty', 'Recommendation Intent', 'Whether customers would recommend to others', FALSE,
ARRAY['highly recommend', 'tell everyone', 'bring friends', 'must try'],
ARRAY['dont recommend', 'avoid', 'stay away', 'warned friends']),
-- Escape dimension primitives (when customers leave early or avoid)
('ESCAPE_LEFT', 'escape', 'Early Departure', 'Whether customers left early or walked out', FALSE,
ARRAY[]::TEXT[], -- No positive signals for escape
ARRAY['walked out', 'left early', 'didnt finish', 'had to leave', 'couldnt stay'])
ON CONFLICT (code) DO UPDATE SET
dimension = EXCLUDED.dimension,
name = EXCLUDED.name,
definition = EXCLUDED.definition,
is_meta = EXCLUDED.is_meta,
base_positive_signals = EXCLUDED.base_positive_signals,
base_negative_signals = EXCLUDED.base_negative_signals;
-- =============================================================================
-- SECTION 9: EXAMPLE CATEGORY CONFIGS
-- =============================================================================
-- Example: Set primitive config for Food & Dining sector (level 1)
-- This would enable food-related primitives for all food businesses
UPDATE public.gbp_categories
SET
primitive_configs = '{
"enabled": ["FOOD_TASTE", "FOOD_FRESHNESS", "FOOD_PORTION", "SERVICE_SPEED", "SERVICE_FRIENDLINESS", "ENV_CLEANLINESS", "ENV_AMBIANCE", "VALUE_PRICE", "VALUE_WORTH", "PROCESS_WAIT"],
"weights": {
"FOOD_TASTE": 1.5,
"FOOD_FRESHNESS": 1.3,
"SERVICE_SPEED": 1.2
}
}'::jsonb,
business_context = '{
"terminology": {
"staff": ["server", "waiter", "waitress", "host", "hostess", "bartender"],
"product": ["food", "dish", "meal", "appetizer", "entree", "dessert", "drink"]
},
"industry": "food_service"
}'::jsonb,
config_version = 'v1.0.0',
config_generated_by = 'migration_014',
config_updated_at = NOW()
WHERE slug = 'food_dining' AND level = 1;
-- Example: Override config for Restaurants (level 2) - adds more specific settings
UPDATE public.gbp_categories
SET
primitive_configs = '{
"enabled": ["PROCESS_BOOKING", "ENV_PARKING"],
"weights": {
"PROCESS_WAIT": 1.3
},
"signals": {
"FOOD_TASTE": {
"positive": ["perfectly cooked", "chef special", "signature dish"],
"negative": ["undercooked", "overcooked", "cold food"]
}
}
}'::jsonb,
business_context = '{
"terminology": {
"staff": ["chef", "cook", "sous chef", "kitchen staff"]
},
"typical_visit_duration": "1-2 hours",
"reservation_common": true
}'::jsonb,
config_version = 'v1.0.0',
config_generated_by = 'migration_014',
config_updated_at = NOW()
WHERE slug = 'restaurants' AND level = 2;
-- =============================================================================
-- VERIFICATION QUERIES (can be removed in production)
-- =============================================================================
-- Verify primitives table
DO $$
BEGIN
RAISE NOTICE 'Primitives table created with % rows', (SELECT COUNT(*) FROM pipeline.primitives);
END $$;
-- Verify functions exist
DO $$
BEGIN
-- Test jsonb_deep_merge
ASSERT pipeline.jsonb_deep_merge('{"a": 1}'::jsonb, '{"b": 2}'::jsonb) = '{"a": 1, "b": 2}'::jsonb,
'jsonb_deep_merge basic test failed';
-- Test __replace__ flag
ASSERT pipeline.jsonb_deep_merge('{"a": {"x": 1, "y": 2}}'::jsonb, '{"a": {"__replace__": true, "z": 3}}'::jsonb) = '{"a": {"z": 3}}'::jsonb,
'jsonb_deep_merge __replace__ test failed';
RAISE NOTICE 'All function tests passed';
END $$;

View File

@@ -0,0 +1,29 @@
-- Migration: Add dedicated columns for business info
-- Purpose: Move business data from metadata JSONB to queryable/indexable columns
-- Date: 2026-01-31
-- Add business info columns
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS business_name VARCHAR(500);
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS business_category VARCHAR(255);
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS business_address TEXT;
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS business_rating NUMERIC(3,2);
-- Add indexes for common queries
CREATE INDEX IF NOT EXISTS idx_jobs_business_name ON jobs(business_name);
CREATE INDEX IF NOT EXISTS idx_jobs_business_category ON jobs(business_category);
CREATE INDEX IF NOT EXISTS idx_jobs_business_rating ON jobs(business_rating);
-- Migrate existing data from metadata JSONB to new columns
UPDATE jobs SET
business_name = metadata->>'business_name',
business_address = metadata->>'business_address',
business_rating = CASE
WHEN metadata->>'rating_snapshot' IS NOT NULL
THEN (metadata->>'rating_snapshot')::NUMERIC(3,2)
ELSE NULL
END
WHERE metadata IS NOT NULL
AND (business_name IS NULL OR business_address IS NULL OR business_rating IS NULL);
-- Clean up metadata: remove migrated fields (optional - keeps metadata for performance metrics only)
-- Note: We keep the data in metadata for backward compatibility, but new code should use columns

View File

@@ -0,0 +1,22 @@
-- Migration: Add resolved GBP category columns to jobs table
-- Purpose: Store the matched taxonomy path for classification context
-- Date: 2026-01-31
-- Add ltree extension if not exists
CREATE EXTENSION IF NOT EXISTS ltree;
-- Add resolved category columns
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS gbp_category_id INTEGER REFERENCES gbp_categories(id);
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS gbp_category_path ltree;
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS category_resolution_method VARCHAR(20); -- 'exact', 'fuzzy', 'llm', 'hierarchical'
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS business_category_source VARCHAR(20); -- 'google' or 'inferred'
-- Index for fast lookups by category path
CREATE INDEX IF NOT EXISTS idx_jobs_gbp_category_path ON jobs USING GIST (gbp_category_path);
CREATE INDEX IF NOT EXISTS idx_jobs_gbp_category_id ON jobs(gbp_category_id);
-- Comment on columns
COMMENT ON COLUMN jobs.gbp_category_id IS 'FK to gbp_categories - the resolved deepest taxonomy node';
COMMENT ON COLUMN jobs.gbp_category_path IS 'ltree path for the resolved category (e.g., Retail.Stores.Toy_store)';
COMMENT ON COLUMN jobs.category_resolution_method IS 'How category was resolved: exact (from Google), fuzzy (trigram match), llm (LLM matched), hierarchical (LLM walked tree)';
COMMENT ON COLUMN jobs.business_category_source IS 'Where business category originated: google (scraped from Maps) or inferred (LLM inferred from name)';