Protocol Raw Operations Portal Documentation¶
Version: 3.8
Last Updated: February 17, 2026
Status: Production Ready
Portal URL: https://ops.protocolraw.co.uk
What's New in v3.8¶
Terminology & Schema Corrections:
- ✅ Batch status terminology aligned — CLEARED → RELEASED, QA_FAIL → QUARANTINE (matches live database, SOP-01 v4.3, config.js, and Systems Overview v2.0)
- ✅ Database schema updated — Removed stale CHECK constraint from documentation (live database has no status enum constraint); updated column names to match actual schema
- ✅ Batch lifecycle diagram corrected — All status references now use canonical values
- ✅ Version aligned to live portal — Documentation now matches portal v3.8 (Refund Actions)
From v3.7 (February 2026): - ✅ Refund action buttons in Support Workstation - ✅ Config version bumped to v3.8
From v3.6 (January 20, 2026):
- ✅ Conversation Thread Panel - Full message history displayed in ticket detail view
- ✅ Email Threading - In-Reply-To and References headers for proper inbox threading
- ✅ [Support] Subject Prefix - All outbound emails prefixed to distinguish from marketing
- ✅ Editable Subject Line - Agent can customize subject before sending
- ✅ Message History Tracking - ticket_messages table records full back-and-forth
- ✅ Unified Email Sending - send-support-email Edge Function handles all outbound
Database Updates:
- ✅ email_message_id and email_references columns on support_tickets
- ✅ ticket_messages table with direction, sender, delivery_id fields
- ✅ Updated v_support_queue view with message count
From v3.5 (January 19, 2026): - ✅ Agent Review tab - Human-in-the-loop validation interface for AI agent decisions - ✅ Shadow Mode workflow - All AI decisions queued for human review before autonomous mode - ✅ Confidence badges - Color-coded display (green >85%, yellow 70-85%, red <70%) - ✅ cs_agent_decisions table - New database table for AI decision tracking
From v3.4 (January 13, 2026): - ✅ Documentation consolidation - merged v2.0 and v3.3 into single comprehensive document - ✅ Pack Day, Fulfillment, and Batch Creation workflows restored - ✅ Full troubleshooting guide restored (20+ scenarios)
From v3.3 (December 10, 2025): - ✅ Customer Search - Real-time search by name, email, or phone with debounced queries - ✅ Customer Profile Panel - Full customer view with subscription management, order history, address - ✅ Ticket Assignment - Assign tickets to agents with visible queue badges - ✅ Outbound Tickets - Proactively contact customers from Customer Profile - ✅ Awaiting Reply Filter - Dedicated queue filter for outbound tickets awaiting customer response
Table of Contents¶
- Overview
- Access & Authentication
- Portal Structure
- Architecture Overview
- Pack Day (SOP PACK)
- Fulfillment (SOP 0Y)
- Batch Creation (SOP 01)
- Support Workstation
- Agent Review (Shadow Mode)
- Live Chat
- Analytics
- Database Views & Tables
- Edge Functions
- Make.com Webhooks
- System Architecture
- Security & Best Practices
- Troubleshooting
- Maintenance & Updates
- Keyboard Shortcuts
- Deployment
- Appendix
- For LLM Assistants
Overview¶
Purpose¶
The Protocol Raw Operations Portal is a unified interface for managing core business operations. Built as a tech-first, AI-native platform, it demonstrates operational sophistication and provides a single hub for packing, fulfillment, batch tracking, customer support, AI agent validation, and business intelligence.
Key Features¶
- Pack Day Automation (SOP PACK) - Weather-based PCM calculation for Tuesday/Thursday packs
- Fulfillment Management (SOP 0Y) - Batch dispatch recording with CSV upload
- Batch Creation (SOP 01) - Production batch registration with QA_HOLD workflow
- Support Workstation - Full customer operations with ticket management, search, conversation threading, and proactive outreach
- Agent Review - Shadow mode validation for AI customer service decisions
- Live Chat - Real-time customer communication
- Analytics Integration - Metabase dashboard access
- Protocol Raw Branding - Consistent visual identity throughout
- Responsive Design - Works on desktop, tablet, and mobile
- Real-time Updates - Direct Supabase database connectivity
Design Principles¶
- Scale First - Built for 100,000+ customers from day one
- Zero Dependencies - No npm packages, no build step, no dependency rot
- Modular by Default - Each feature is a self-contained ES6 module
- State-Driven UI - Centralized state with pub/sub for reactive updates
- Brand Consistent - CSS tokens derived from Visual Identity Guide v2.1
- Systematic, not emotional - Evidence-based operations
- Proof, not promises - Verifiable safety at every step
Access & Authentication¶
Portal URL¶
Primary: https://ops.protocolraw.co.uk
Backup: https://protocol-raw-ops.pages.dev
Authentication Method¶
The portal uses Cloudflare Access with Google OAuth for authentication. Only authorized email addresses can access the portal.
Login Process¶
- Navigate to https://ops.protocolraw.co.uk
- Click "Sign in with Google"
- Authenticate with your authorized Google account
- Session lasts 24 hours before re-authentication required
Managing Access¶
Add/Remove Users: 1. Cloudflare Dashboard → Zero Trust → Access → Applications 2. Find "Protocol Raw Operations Portal" application 3. Edit policy → Add or remove email addresses 4. Save changes
⚠ï¸Â Security Note
The portal contains your Supabase service role key with full database access. It is protected by Cloudflare Access authentication. Never share login credentials or disable authentication.
Portal Structure¶
Navigation¶
The portal uses a tab-based navigation system with seven main sections:
- 🎯 Pack Day (SOP PACK) - Automated packing workflow
- 📦 Fulfillment (SOP 0Y) - Dispatch recording
- 🧪 Batches (SOP 01) - Production batch registration
- 📊 Inventory - Stock levels and allocation
- 🎧 Support Workstation - Customer operations hub
- 🤖 Agent Review - AI decision validation (shadow mode)
- 💬 Live Chat - Real-time customer communication
Visual Design¶
Typography: - Headlines: Montserrat Bold 700 - Body text: Inter Regular 400 - UI elements: Inter Medium 500
Colors: - Background: Old Lace (#FEFDF7) - Surface: Spring Wood (#F2EEE3) - Text: Heavy Metal (#323531) - Muted text: Friar Gray (#7C7C78) - Primary CTA: Terracotta (#D48762) - Secondary: Nandor (#4B685B)
Layout: - Max width: 1200px (centered) - Generous padding: 40px desktop, 20px mobile - Border radius: 12px - Responsive breakpoint: 768px
Architecture Overview¶
Technology Stack¶
| Layer | Technology | Purpose |
|---|---|---|
| Hosting | Cloudflare Pages | Static file serving, edge caching |
| Auth | Cloudflare Access | Zero-trust authentication |
| Database | Supabase PostgreSQL | Data storage, views, RPC functions |
| API | Supabase REST + Edge Functions | Data operations |
| Automation | Make.com | Webhook-triggered workflows |
| Subscriptions | Seal Subscriptions | Shopify subscription management |
| Customer.io | Transactional email delivery | |
| Frontend | Vanilla JS (ES6 modules) | No framework overhead |
| Fonts | Google Fonts | Montserrat + Inter |
Request Flow¶
User Action
↓
Module Function (e.g., support.subscriptionAction)
↓
API Layer (api.js) → Supabase REST/RPC/Edge Function
↓ or
Make.com Webhook → Seal API / Customer.io
↓
State Update (state.js)
↓
UI Re-render (subscribers notified)
File Structure¶
/
â“â â  index.html
â“â â  css/
â  ââ€â€â â  agent-review.css # Agent Review tab styles
ââ€â€â â  js/
â“â â  app.js # Main application, module orchestration
â“â â  api.js # Supabase client, webhooks
â“â â  config.js # Configuration (v3.8)
â“â â  state.js # Centralized state management
ââ€â€â â  modules/
â“â â  packday.js # Pack Day tab
â“â â  fulfillment.js # Fulfillment tab
â“â â  batches.js # Batches tab
â“â â  inventory.js # Inventory tab
â“â â  support.js # Support Workstation
â“â â  agent-review.js # Agent Review tab (v3.5)
ââ€â€â â  chat.js # Live Chat
Pack Day (SOP PACK)¶
Purpose¶
Automate the intelligent packing workflow for Tuesday and Thursday dispatch days. Calculate PCM (Phase Change Material) requirements based on real weather forecasts to ensure frozen delivery.
Pack Schedule¶
Tuesday Dispatch: - Calculate PCM: 9:00 AM Tuesday - Pack orders: 10:00 AM - 4:00 PM - Courier collection: 4:00-6:00 PM - Customer delivery: Wednesday/Thursday (48h)
Thursday Dispatch: - Calculate PCM: 9:00 AM Thursday - Pack orders: 10:00 AM - 4:00 PM - Courier collection: 4:00-6:00 PM - Customer delivery: Friday/Saturday (48h)
Workflow¶
Step 1: Calculate PCM Requirements¶
When: Pack morning (9:00 AM on Tuesday or Thursday)
How:
1. Navigate to "Pack Day (SOP PACK)" tab
2. Click "🧊 Calculate PCM for Today's Packs" button
3. System executes:
- Fetches all orders with export_state = 'sent'
- Filters orders without existing packing instructions
- Calls OpenWeatherMap API for each delivery postcode
- Determines max temperature over next 48 hours
- Calculates PCM requirements per packaging specification
- Creates packing instructions in database
- Returns results with risk levels
Expected Results:
✅ Success!
Processed 23 orders
23 successful, 0 failed
Results:
#1234 - 6 packs - STANDARD
#1235 - 9 packs - MEDIUM
#1236 - 11 packs - HIGH
Risk Levels: - STANDARD (<20°C) - Base PCM requirement, no logger - MEDIUM (20-29°C) - Increased PCM, logger required - HIGH (≥30°C) - Maximum PCM, logger required
Troubleshooting:
Button doesn't respond:
- Check browser console (F12) for errors
- Verify Edge Function is deployed: calculate-pack-day-instructions
- Check Supabase Edge Functions logs
Error: "No orders found":
- Verify orders exist with export_state = 'sent'
- Check SOP 0X (Export to Fulfillment) ran successfully
- Query database: SELECT * FROM raw_ops.orders WHERE export_state = 'sent'
API error: - Check OpenWeatherMap API status - Verify API key in Edge Function is valid - Check Edge Function logs for detailed error
Step 2: View Pack Queue¶
When: After PCM calculation completes
How: 1. Click "📋 Open Pack Queue" button 2. System opens Metabase dashboard (when configured) 3. Dashboard shows: - Orders sorted by risk level (HIGH → MEDIUM → STANDARD) - PCM pack count per order - Delivery postcode - Customer name - Special notes
Alternative (Pre-Metabase):
Query the database directly:
SELECT
order_number_label,
customer_name,
delivery_postcode,
box_size,
pcm_packs_count,
risk_level,
ambient_forecast_max,
logger_required,
special_notes
FROM raw_ops.v_pack_queue_with_batch
ORDER BY
CASE risk_level
WHEN 'HIGH' THEN 1
WHEN 'MEDIUM' THEN 2
WHEN 'STANDARD' THEN 3
END,
exported_at ASC;
Step 3: Pack & Dispatch¶
Process: 1. Follow pack queue instructions for each order 2. Record quality checks per SOP PACK-01 3. Use correct number of PCM packs 4. Insert temperature logger if required 5. Record dispatch via Fulfillment tab (SOP 0Y)
Quality Metrics: - Pack time: <10 mins (8kg/12kg), <12 mins (16kg) - Weight variance: ±5% tolerance - Temperature: Product at ≤-25°C at pack time
Technical Details¶
Edge Function: calculate-pack-day-instructions
Database Tables:
- raw_ops.packing_instructions - Stores PCM requirements per order
- raw_ops.orders - Source for orders ready to pack
- raw_ops.v_pack_queue_with_batch - View combining instructions with batch data
API Integration: - OpenWeatherMap API (via Edge Function) - 1000 free calls/day - 48-hour forecast window - Postcode-based temperature lookup
Authentication: - Uses Supabase Anon Key (public, safe for browser) - Edge Function handles secure API calls
Fulfillment (SOP 0Y)¶
Purpose¶
Record dispatch confirmations for orders. Supports batch processing of dispatches with CSV upload to trigger automated courier integration and customer notifications.
Workflow¶
Step 1: Add Dispatches to Batch¶
When: After packing each order
How: 1. Navigate to "Fulfillment (SOP 0Y)" tab 2. Enter dispatch details: - Order ID: Shopify order ID (e.g., 12294292865399) - Tracking Number: Courier tracking number - Courier: Select from DPD, Royal Mail, Evri, UPS - SKU: Defaults to STARTER-8KG (or specify) - Qty: Number of units (usually 1) 3. Click "➕ Add to Batch" 4. Order appears in Current Batch table 5. Repeat for all orders packed today
Features: - LocalStorage Persistence: Batch survives page refresh - Duplicate Prevention: Can't add same Order ID twice - Remove Individual Orders: Remove button per row - Clear Batch: Clear all at once with confirmation
Example Batch:
| Order ID | Tracking Number | Courier | SKU | Qty |
|---|---|---|---|---|
| 12294292865399 | DPD123456789 | DPD | STARTER-8KG | 1 |
| 12294292865400 | DPD123456790 | DPD | STARTER-12KG | 1 |
| 12294292865401 | DPD123456791 | DPD | STARTER-8KG | 1 |
Step 2: Submit Batch¶
When: End of pack day (4:00-6:00 PM)
How:
1. Review Current Batch table (check for errors)
2. Click "🚀 Submit Batch to SOP 0Y"
3. Confirm submission in popup dialog
4. System executes:
- Generates CSV file with all dispatches
- Filename: dispatch_batch_YYYY-MM-DD_timestamp.csv
- Uploads to Supabase Storage: dispatch-files/inbox/
- Clears batch from localStorage
- Shows success message with filename
CSV Format:
external_order_id,dispatch_time_utc,courier,service,tracking_number,sku,qty,parcel_count,notes,status
12294292865399,2025-11-13T16:23:45.123Z,DPD,Standard,DPD123456789,STARTER-8KG,1,1,,DISPATCHED
12294292865400,2025-11-13T16:24:12.456Z,DPD,Standard,DPD123456790,STARTER-12KG,1,1,,DISPATCHED
Downstream Automation:
Once CSV is uploaded, Make.com scenario (SOP 0Y) automatically:
1. Detects new file in dispatch-files/inbox/
2. Parses CSV and validates data
3. Updates raw_ops.shipments table
4. Creates courier tracking records
5. Triggers customer notification emails
6. Moves file to dispatch-files/processed/
Step 3: Check Recent Activity¶
Purpose: Verify orders are ready for dispatch
How:
1. Click "Check Recent Orders" button
2. System queries last 20 orders with status queued or sent
3. Table displays:
- Order ID
- Export state (queued/sent)
- Order date
Use Cases: - Verify SOP 0X exported orders successfully - Check order count matches expected pack day volume - Identify any orders stuck in queue
Technical Details¶
Storage Location:
- Bucket: dispatch-files
- Folder: inbox/ (for new files)
- Folder: processed/ (after Make.com processes)
Database Tables:
- raw_ops.orders - Source for recent activity
- raw_ops.shipments - Updated by Make.com after CSV processing
Authentication: - Uses Supabase Service Role Key (full access, portal protected by Cloudflare Access)
File Naming Convention:
- Format: dispatch_batch_YYYY-MM-DD_UnixTimestamp.csv
- Example: dispatch_batch_2025-11-13_1731513825123.csv
Troubleshooting¶
"Order ID already in batch" error: - Order was already added to current batch - Check Current Batch table - Remove duplicate if needed
Submit fails with "Upload failed: 403":
- Service Role Key may be invalid
- Check Supabase Storage bucket permissions
- Verify bucket dispatch-files exists with inbox/ folder
Submit succeeds but Make.com doesn't process: - Check Make.com scenario is active - Verify webhook URL is correct - Check scenario execution history for errors
Batch Creation (SOP 01)¶
Purpose¶
Register new production batches with automatic dual ID generation, QA_HOLD status, and proof portal integration.
Workflow¶
Create New Batch¶
When: Production batch arrives from co-packer
How:
1. Navigate to "Batches (SOP 01)" tab
2. Enter batch details:
- Production Date: When batch was produced
- Quantity (kg): Weight of batch
3. Click "Create Batch"
4. System executes:
- Auto-generates internal batch code
- Sets status: QA_HOLD
- Sets partner: COPACKER-A
- Sets COGS: £3.50/kg
- Generates dual IDs (internal batch code + public batch ID)
- Creates QR code for proof portal
- Inserts record into raw_ops.batches
- Shows success message
Example:
Input:
- Batch Code: BATCH-20251113-001
- Production Date: 2025-11-13
- Quantity: 500 kg
Creates:
{
"batch_code": "BATCH-20251113-001",
"public_batch_id": "PR-A711BCF6",
"production_date": "2025-11-13",
"expiry_date": "2026-11-13",
"kg_produced": 500.00,
"status": "QA_HOLD",
"partner": "COPACKER-A",
"cogs_per_kg": 3.50
}
View Recent Batches¶
Purpose: Monitor batch status and inventory levels
How: 1. Click "View Recent Batches" button 2. System queries last 10 batches, sorted by production date 3. Table displays: - Batch Code - Public Batch ID - Production Date - Status (QA_HOLD, RELEASED, QUARANTINE, DEPLETED) - Quantity (kg)
Status Meanings: - QA_HOLD: Awaiting lab results (cannot be sold or allocated) - RELEASED: Lab tests passed, available for dispatch - QUARANTINE: Failed testing — do not use - DEPLETED: No stock remaining, archived
Batch Lifecycle¶
1. BATCH CREATED
ââ€â€â > Status: QA_HOLD
2. LAB SAMPLE SENT
ââ€â€â > Co-packer sends sample to UKAS lab
3. LAB RESULTS RECEIVED
ââ€â€â > Email with PDF arrives
4. SOP 01 AUTOMATION
ââ€â€â > Make.com parses PDF
ââ€â€â > Checks: Salmonella ABSENT, Listeria ABSENT
ââ€â€â > If PASS: Status → RELEASED
ââ€â€â > If FAIL: Status → QUARANTINE (batch quarantined)
5. BATCH AVAILABLE FOR SALE
ââ€â€â > Inventory system can allocate (SOP-INV-01)
ââ€â€â > Orders can be fulfilled
6. BATCH DEPLETED
ââ€â€â > All kg allocated to orders
ââ€â€â > Status → DEPLETED
Technical Details¶
Database Table: raw_ops.batches
Schema (simplified — see Supabase for full current schema):
CREATE TABLE raw_ops.batches (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
batch_code TEXT UNIQUE NOT NULL,
public_batch_id TEXT UNIQUE NOT NULL,
production_date DATE NOT NULL,
expiry_date DATE,
kg_produced NUMERIC NOT NULL CHECK (kg_produced > 0),
qty_on_hand NUMERIC CHECK (qty_on_hand >= 0),
qty_reserved NUMERIC CHECK (qty_reserved >= 0),
status TEXT NOT NULL, -- QA_HOLD, RELEASED, QUARANTINE, DEPLETED (no CHECK constraint)
partner TEXT NOT NULL,
cogs_per_kg_gbp NUMERIC CHECK (cogs_per_kg_gbp >= 0),
total_cost_gbp NUMERIC CHECK (total_cost_gbp >= 0),
formulation_id UUID REFERENCES raw_ops.formulations(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
released_at TIMESTAMPTZ,
lab_cert_url TEXT
);
Note: The status column has no database-level CHECK constraint. Status transitions are enforced by application logic (SOP-01 triggers). The canonical status values are defined in config.js under BATCH_STATUSES: QA_HOLD, RELEASED, DEPLETED, QUARANTINE.
Authentication: - Uses Supabase Service Role Key (INSERT permission required)
Validation Rules: - Batch code must be unique - Production date cannot be in future - Quantity must be positive - COGS must be positive
Troubleshooting¶
"Batch code already exists" error: - Batch with this code already in database - Check Recent Batches to confirm - Use different batch code or verify co-packer confirmation
Create fails with "Permission denied":
- Service Role Key may be invalid
- Check Supabase console for key
- Verify raw_ops.batches table exists
Expiry date incorrect: - System auto-calculates as production date + 12 months - Check production date was entered correctly - To manually adjust: Update in Supabase dashboard
Batch stuck in QA_HOLD: - Lab results not yet received - Check co-packer sent sample to lab - Check email for lab results PDF - Verify Make.com SOP 01 scenario is active - Check scenario execution history for parsing errors
Support Workstation Module¶
File: js/modules/support.js
Purpose: Full-featured customer operations workstation with ticket management, customer search, conversation threading, and proactive outreach
Layout (v3.6)¶
â‌â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â ââ€Â
â  Support Workstation [Refresh Queue] â 
â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․
â  [ðŸâ€Â Search customers by name, email, or phone...] [Clear] â 
â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․
â  Customer Profile Panel (when customer selected from search) â 
â  â‌â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â ââ€Â â 
â  â  Customer Name [📤 Contact Customer] [✕] â  â 
â  â  email@example.com â  â 
â  â  Customer since: Jan 2025 · 5 orders · LTV: £450.00 â  â 
â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  Subscription: Active â  â 
â  â  Next: Mon 16 Dec · Every 2 weeks · 8kg â  â 
â  â  [Skip] [Pause] [Change Box ▾] [Change Frequency ▾] â  â 
â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  Address: 123 Example St, London, E1 1AA â  â 
â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  Order History â  â 
â  â  #1234 · 10 Dec · PAID · £89.00 â  â 
â  â  #1198 · 26 Nov · PAID · £89.00 â  â 
â  ââ€â€â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â‘ â 
â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․
â  [Open: 5] [High: 2] [Resolved Today: 12] [Avg: 15m] â 
â“â â â â â â â â â â â â â â â â â â â‬â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․
â  Queue List â  Response Panel â 
â  â‌â â â â â â â â â â â â ââ€Â â  â‌â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â ââ€Â â 
â  â [All][📧][💬]â  â  â  Customer Context Assigned To [▾] â  â 
â  â [📤 Awaiting]â  â  â  Name · Email · Dog · Sub Waiting: 5m â  â 
â  â“â â â â â â â â â â â â â․ â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  Customer 1 â  â  â  CONVERSATION THREAD (v3.6) â  â 
â  â  5m · High â  â  â  â‌â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â ââ€Â â  â 
â  â  👤 Anton â  â  â  â  â†Â john@example.com (10:15) â  â  â 
â  â“â â â â â â â â â â â â â․ â  â  â  "Hi, I have a question about my order..." â  â  â 
â  â  Customer 2 â  â  â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â  â 
â  â  15m · Med â  â  â  â  → Sophie (10:45) â  â  â 
â  â  📤 outboundâ  â  â  â  "Thanks for reaching out! I can help..." â  â  â 
â  â  Awaiting â  â  â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â  â 
â  â“â â â â â â â â â â â â â․ â  â  â  â†Â john@example.com (11:02) â  â  â 
â  â  Customer 3 â  â  â  â  "Thanks, but I still have questions..." â  â  â 
â  â  45m · Norm â  â  â  ââ€â€â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â‘ â  â 
â  ââ€â€â â â â â â â â â â â â â‘ â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  â  AI Triage: Category · Confidence · Action â  â 
â  â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  â  Subject: [Support] Re: My order question â  â 
â  â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  â  Draft Response â  â 
â  â  â  [textarea] â  â 
â  â  â“â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â․ â 
â  â  â  [Send Response] [Close Without Sending] â  â 
â  â  ââ€â€â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â‘ â 
ââ€â€â â â â â â â â â â â â â â â â â â â‴â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â‘
Conversation Thread Panel (v3.6)¶
The Support Workstation now displays the full conversation history for each ticket:
| Feature | Status | Notes |
|---|---|---|
| Inbound messages | ✅ Built | Customer emails with left alignment |
| Outbound messages | ✅ Built | Our replies with right alignment |
| Chronological order | ✅ Built | Oldest first |
| Sender display | ✅ Built | Customer email or persona name |
| Timestamp | ✅ Built | Relative time (e.g., "2h ago") |
| Message count badge | ✅ Built | Shows thread depth in queue |
Data Source: raw_ops.ticket_messages
Visual Styling: - Inbound (customer): Left-aligned, gray background - Outbound (us): Right-aligned, green background
Email Response Features (v3.6)¶
| Feature | Status | Notes |
|---|---|---|
| Editable subject line | ✅ Built | Pre-filled with [Support] prefix |
[Support] prefix auto-added |
✅ Built | Distinguishes from marketing |
| Email threading | ✅ Built | In-Reply-To + References headers |
| Persona sign-off | ✅ Built | Sophie/Tom/Lucy auto-appended |
| Response logged to thread | ✅ Built | Stored in ticket_messages |
| Panel clears after send | ✅ Built | Ready for next ticket |
Queue Filters¶
| Filter | Description |
|---|---|
| All | All open tickets (inbound + outbound) |
| Inbound email tickets only | |
| 💬 Chat | Chat escalations only |
| 📤 Awaiting | Outbound tickets awaiting customer reply |
Customer Search¶
Real-time search with 300ms debounce:
// Search triggers after 300ms of no typing
// Returns: customer_id, first_name, last_name, email, phone,
// subscription_status, total_orders, lifetime_value
Search fields: first_name, last_name, email, phone (case-insensitive ILIKE)
Customer Profile Panel¶
Displays when customer selected from search:
- Header: Name, email, customer since, order count, LTV
- Subscription: Status, next delivery, box size, frequency, action buttons
- Address: Shipping address
- Order History: Last 10 orders with status and total
- Contact Button: Opens outbound ticket modal
Ticket Assignment¶
- Agents Table:
raw_ops.agentswith id, name, email, role, is_active - Dropdown: Shows active agents, updates ticket on selection
- Queue Badge: Blue "👤 Anton" badge on assigned tickets
- Persistence: Stored in
support_tickets.assigned_to
Outbound Tickets¶
Proactive customer contact flow:
- Search for customer → Click "📤 Contact Customer"
- Modal opens with customer info pre-filled
- Select reason: Delivery Issue, Order Issue, Payment/Billing, Account Update, General Inquiry
- Enter subject and message
- Click "Send Email & Create Ticket"
- Ticket created with
is_outbound=true,status='awaiting_reply' - Email sent via Make.com → Customer.io
- Ticket appears in "Awaiting" filter with purple styling
Outbound Ticket Flow:
Customer Profile
↓
[📤 Contact Customer]
↓
Modal: Reason + Subject + Message
↓
create_outbound_ticket() RPC
↓
Make.com Webhook → Customer.io Email
↓
Ticket in queue (status: awaiting_reply)
↓
Customer replies → Inbound flow (status: open)
Email Send Flow (v3.6)¶
Agent clicks "Send Response"
↓
Portal calls send-support-email Edge Function
↓
Edge Function:
1. Fetches ticket email_message_id
2. Builds headers: In-Reply-To + References
3. Prepends [Support] to subject if missing
4. Sends via Customer.io Transactional API
5. Inserts message into ticket_messages
6. Updates ticket status
↓
Customer receives threaded email
Database Dependencies¶
Views:
- public.v_support_queue - Open tickets with subscription context, assignment, outbound fields, message count
Tables:
- raw_ops.support_tickets - Ticket records (includes is_outbound, outbound_reason, assigned_to, email_message_id)
- raw_ops.ticket_messages - Conversation thread (v3.6)
- raw_ops.agents - Agent roster
- raw_ops.subscriptions - Subscription records
- raw_ops.subscription_actions - Action log
- raw_ops.orders - Order history
- raw_ops.customers - Customer records
RPC Functions:
- public.search_customers(search_term, result_limit) - Customer search
- public.get_customer_profile(p_customer_id) - Full customer profile
- public.get_customer_orders(p_customer_id, p_limit) - Order history
- public.get_active_agents() - Active agents list
- public.assign_ticket(p_ticket_id, p_assigned_to) - Assign ticket
- public.create_outbound_ticket(...) - Create outbound ticket
- public.log_subscription_action(...) - Log and sync subscription changes
- public.get_ticket_messages(p_ticket_id) - Get conversation thread (v3.6)
Edge Functions:
- send-support-email - Send response with threading (v3.6)
Agent Review Module¶
File: js/modules/agent-review.js
Styles: css/agent-review.css
Purpose: Human-in-the-loop validation interface for AI agent decisions during shadow mode
Purpose¶
The Agent Review tab provides a validation interface for AI customer service decisions before enabling autonomous responses. All AI decisions are queued for human review, allowing operators to approve correct decisions or reject incorrect ones with feedback for training.
Accessing¶
- Navigate to Ops Portal → 🤖 Agent Review tab
- Badge shows count of pending reviews
- Click Refresh to load latest queue
Review Workflow¶
1. AI processes inbound email → generates decision
↓
2. Decision written to `cs_agent_decisions` with `review_status: 'pending'`
↓
3. Decision appears in Agent Review queue
↓
4. Human reviews:
- Category assignment
- Confidence score
- AI reasoning
- Draft response
- Proposed actions
↓
5. Human clicks **Approve** or **Reject**
↓
6. Approved: Decision marked as validated
Rejected: Feedback captured for training
UI Elements¶
| Element | Description |
|---|---|
| Review Card | Shows AI decision details |
| Confidence Badge | Color-coded (green >85%, yellow 70-85%, red <70%) |
| Queue Age | Time since AI processed |
| Approve Button | Mark decision as correct |
| Reject Button | Mark incorrect with feedback prompt |
Database Table¶
CREATE TABLE raw_ops.cs_agent_decisions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticket_id UUID REFERENCES raw_ops.support_tickets(id),
-- AI Processing
category TEXT,
confidence_score NUMERIC(3,2),
reasoning TEXT,
draft_response TEXT,
proposed_actions JSONB DEFAULT '[]',
escalation_reason TEXT,
-- Processing timestamps
processed_at TIMESTAMPTZ DEFAULT NOW(),
-- Review status
review_status TEXT DEFAULT 'pending'
CHECK (review_status IN ('pending', 'approved', 'rejected')),
reviewed_at TIMESTAMPTZ,
reviewed_by TEXT,
rejection_reason TEXT,
rejection_feedback TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_cs_agent_decisions_review_status
ON raw_ops.cs_agent_decisions(review_status)
WHERE review_status = 'pending';
CREATE INDEX idx_cs_agent_decisions_ticket
ON raw_ops.cs_agent_decisions(ticket_id);
JavaScript Module¶
File: js/modules/agent-review.js
Key Functions:
| Function | Description |
|---|---|
loadQueue() |
Fetch pending decisions from database |
renderQueue() |
Display decisions as review cards |
approveDecision(id) |
Mark decision as approved |
rejectDecision(id) |
Mark rejected with feedback |
refresh() |
Reload queue and update badge |
updateBadge() |
Update pending count in tab |
App.js Integration¶
// Import
import agentReview from './modules/agent-review.js';
// Add to modules registry
const modules = {
// ... other modules
agentReview,
};
// Add to tab map
const tabModuleMap = {
// ... other tabs
agentReview: 'agentReview',
};
// Expose globally
window.AgentReview = agentReview;
Shadow Mode → Autonomous Mode Transition¶
Shadow Mode (Current): - All AI decisions queued for review - No automatic responses sent - Human approves/rejects each decision - Builds confidence in AI accuracy
Transition Criteria: - 95%+ approval rate over 100+ decisions - No critical errors in last 50 decisions - All edge cases documented
Autonomous Mode (Future): - High-confidence decisions auto-execute - Low-confidence still escalated - Human reviews exceptions only
Next Steps for Agent Review¶
- Wire up Make.com AI triage to insert into
cs_agent_decisions - Build confidence through shadow mode validation
- Define autonomous mode criteria
- Implement auto-execute for high-confidence decisions
Live Chat Module¶
File: js/modules/chat.js
Purpose: Real-time customer communication with seamless escalation to ticketed support
Features¶
- Real-time messaging via Supabase Realtime
- Customer identification and context loading
- Chat transcript history
- Escalation to Support Workstation tickets
- Typing indicators
- Read receipts
Technical Details¶
See SOP CS-02: Live Chat System v1.4 for complete documentation.
Analytics¶
Purpose¶
Access Metabase business intelligence dashboards for operational insights and performance tracking.
Available Dashboards¶
Pack Queue with PCM Requirements - Orders ready to pack, sorted by risk level - PCM pack count per order - Delivery postcode and forecast temperature - Logger requirement indicator
Batch Status & Inventory - Current inventory levels (kg available) - Batches in QA_HOLD awaiting clearance - Expiry dates and batch rotation - FEFO (First Expired, First Out) compliance
Fulfillment Performance - Dispatch volume by day/week - Pack time metrics and quality checks - Courier performance and tracking - On-time delivery rates
CAC & LTV Metrics - Customer acquisition cost - Lifetime value projections - Box-2 retention rates - Cohort analysis
Access¶
How: 1. Navigate to "Analytics" tab 2. Click "Open Metabase Dashboard" 3. Opens in new browser tab 4. Authenticate with Metabase credentials (if required)
Metabase URL: (Configured in index.html)
Configuration¶
To add Metabase URL:
1. Open index.html in text editor
2. Find line: onclick="window.open('YOUR_METABASE_URL', '_blank')"
3. Replace YOUR_METABASE_URL with actual Metabase dashboard URL
4. Save and re-upload to Cloudflare Pages
Example:
Database Views & Tables¶
Core Tables¶
| Table | Purpose |
|---|---|
raw_ops.batches |
Production batch tracking |
raw_ops.orders |
Customer order records |
raw_ops.shipments |
Dispatch and tracking data |
raw_ops.packing_instructions |
Pack Day PCM requirements |
raw_ops.pack_quality_checks |
Quality control metrics |
raw_ops.temperature_logger_data |
Post-delivery temperature audits |
raw_ops.formulations |
Recipe management |
raw_ops.customers |
Customer records |
raw_ops.subscriptions |
Subscription records |
raw_ops.support_tickets |
Support ticket records |
raw_ops.ticket_messages |
Ticket conversation thread (v3.6) |
raw_ops.ticket_notes |
Internal agent notes |
raw_ops.agents |
Agent roster |
raw_ops.cs_agent_decisions |
AI agent decisions (v3.5) |
raw_ops.config |
System configuration |
Tables (v3.3+)¶
raw_ops.agents¶
CREATE TABLE raw_ops.agents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
email TEXT,
role TEXT DEFAULT 'agent', -- agent, admin, supervisor
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_agents_active ON raw_ops.agents(is_active) WHERE is_active = true;
raw_ops.support_tickets (columns added v3.3, v3.6)¶
-- v3.3 additions
ALTER TABLE raw_ops.support_tickets
ADD COLUMN IF NOT EXISTS is_outbound BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS outbound_reason TEXT,
ADD COLUMN IF NOT EXISTS assigned_to TEXT;
-- v3.6 additions
ALTER TABLE raw_ops.support_tickets
ADD COLUMN IF NOT EXISTS email_message_id TEXT,
ADD COLUMN IF NOT EXISTS email_references TEXT;
CREATE INDEX idx_support_tickets_outbound
ON raw_ops.support_tickets(is_outbound, status)
WHERE is_outbound = true;
CREATE INDEX idx_support_tickets_assigned
ON raw_ops.support_tickets(assigned_to)
WHERE assigned_to IS NOT NULL;
Tables (v3.5)¶
raw_ops.cs_agent_decisions¶
CREATE TABLE raw_ops.cs_agent_decisions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticket_id UUID REFERENCES raw_ops.support_tickets(id),
-- AI Processing
category TEXT,
confidence_score NUMERIC(3,2),
reasoning TEXT,
draft_response TEXT,
proposed_actions JSONB DEFAULT '[]',
escalation_reason TEXT,
-- Processing timestamps
processed_at TIMESTAMPTZ DEFAULT NOW(),
-- Review status
review_status TEXT DEFAULT 'pending'
CHECK (review_status IN ('pending', 'approved', 'rejected')),
reviewed_at TIMESTAMPTZ,
reviewed_by TEXT,
rejection_reason TEXT,
rejection_feedback TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_cs_agent_decisions_review_status
ON raw_ops.cs_agent_decisions(review_status)
WHERE review_status = 'pending';
CREATE INDEX idx_cs_agent_decisions_ticket
ON raw_ops.cs_agent_decisions(ticket_id);
Tables (v3.6)¶
raw_ops.ticket_messages¶
CREATE TABLE raw_ops.ticket_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticket_id UUID NOT NULL REFERENCES raw_ops.support_tickets(id) ON DELETE CASCADE,
direction TEXT NOT NULL CHECK (direction IN ('inbound', 'outbound')),
sender TEXT NOT NULL, -- customer email or agent persona
subject TEXT,
body TEXT NOT NULL,
email_message_id TEXT, -- For threading reference
delivery_id TEXT, -- Customer.io delivery ID for outbound
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_ticket_messages_ticket_id ON raw_ops.ticket_messages(ticket_id);
Ticket Statuses¶
| Status | Description |
|---|---|
| pending | New ticket, not yet viewed |
| in_progress | Ticket viewed, being worked on |
| awaiting_reply | Outbound ticket waiting for customer response |
| resolved | Issue resolved, response sent |
| closed | Ticket closed without response |
Key Views¶
v_pack_queue_with_batch- Pack Day queue with batch traceabilityv_inventory_summary- Current inventory levelsv_order_fulfillment_status- Order status trackingv_support_queue- Open tickets with customer context, message count (v3.6)
Edge Functions¶
calculate-pack-day-instructions¶
Purpose: Calculate PCM requirements based on weather forecasts
Trigger: Portal Pack Day button
Process:
1. Fetch orders with export_state = 'sent'
2. Get 48-hour weather forecast per postcode
3. Calculate PCM pack count based on temperature
4. Create packing instruction records
send-support-email (v3.6)¶
Purpose: Send support responses via Customer.io with email threading
Trigger: Support Workstation "Send Response" button or CS-03 Agent
Process:
1. Receive ticket ID, customer email, subject, message
2. Fetch email_message_id from ticket for threading
3. Build headers: In-Reply-To + References if reply
4. Prepend [Support] to subject if not present
5. Select random persona (Sophie/Tom/Lucy)
6. Send via Customer.io Transactional API
7. Insert message into ticket_messages (direction: outbound)
8. Update ticket status to resolved
9. Return success with delivery_id and persona
Payload:
{
"ticket_id": "uuid",
"customer_id": "uuid",
"customer_email": "customer@example.com",
"subject": "Re: Original subject",
"message": "Response body text",
"source": "ops_portal | cs_agent",
"delay_send": false
}
Response:
{
"success": true,
"delivery_id": "abc123",
"persona": "Sophie",
"threading_enabled": true,
"sent_immediately": true
}
support-send-response (deprecated)¶
Purpose: Legacy email send function - replaced by send-support-email in v3.6
Make.com Webhooks¶
Portal Subscription Actions¶
Webhook URL: https://hook.eu2.make.com/25vurnbyc8bhvqi5zqvgf9mjf809z0m8
Scenario: "Portal Subscription Actions"
Routes:
| Route | Filter | Action |
|---|---|---|
| Outbound Email | action=outbound_email | Customer.io transactional email |
| Ops Portal Frequency | source=ops_portal, action=frequency_change | Seal API edit intervalCount |
| Ops Portal Box Change | source=ops_portal, action=box_change | Seal API edit variantId |
| Ops Portal Skip | source=ops_portal, action=skip | Seal API skip billing attempt |
| Ops Portal Bypass | source=ops_portal, action=pause/resume | Seal API pause/resume |
Outbound Email Route¶
Filter: {{1.action}} equals outbound_email
Payload:
{
"action": "outbound_email",
"ticket_id": "uuid",
"customer_email": "customer@example.com",
"customer_name": "John Smith",
"subject": "Quick update about your delivery",
"message": "Hi John, just wanted to let you know...",
"reason": "Delivery Issue"
}
Customer.io API Call:
{
"transactional_message_id": "support_response",
"to": "{{1.customer_email}}",
"identifiers": { "email": "{{1.customer_email}}" },
"message_data": {
"customer_name": "{{1.customer_name}}",
"response_body": "{{1.message}}",
"subject": "{{1.subject}}"
},
"from": "support@protocolraw.co.uk",
"reply_to": "support@protocolraw.co.uk",
"subject": "{{1.subject}}"
}
System Architecture¶
Database Architecture¶
Schema: raw_ops
Key Tables:
- batches - Production batch tracking
- orders - Customer order records
- shipments - Dispatch and tracking data
- packing_instructions - Pack Day PCM requirements
- pack_quality_checks - Quality control metrics
- temperature_logger_data - Post-delivery temperature audits
- formulations - Recipe management
- config - System configuration
- cs_agent_decisions - AI agent decisions (v3.5)
- ticket_messages - Conversation threads (v3.6)
Key Views:
- v_pack_queue_with_batch - Pack Day queue with batch traceability
- v_inventory_summary - Current inventory levels
- v_order_fulfillment_status - Order status tracking
- v_support_queue - Open tickets with message count (v3.6)
Access Levels: - Anon Key: Public read access + specific Edge Functions - Service Role Key: Full CRUD access (portal only, protected by Cloudflare Access)
API Integrations¶
Supabase REST API:
- Base URL: https://znfjpllsiuyezqlneqzr.supabase.co/rest/v1/
- Authentication: Service Role Key in Authorization header
- Schema: Accept-Profile: raw_ops
Supabase Edge Functions:
- Base URL: https://znfjpllsiuyezqlneqzr.supabase.co/functions/v1/
- Authentication: Anon Key in Authorization header
- Functions: calculate-pack-day-instructions, send-support-email
Supabase Storage:
- Base URL: https://znfjpllsiuyezqlneqzr.supabase.co/storage/v1/
- Authentication: Service Role Key in Authorization header
- Bucket: dispatch-files
External Dependencies¶
Google Fonts API:
- Montserrat: fonts.googleapis.com/css2?family=Montserrat:wght@700
- Inter: fonts.googleapis.com/css2?family=Inter:wght@400;500;600
OpenWeatherMap API (via Edge Function): - Used for Pack Day weather forecasts - 1000 free calls/day - API key stored in Edge Function (not in portal)
Performance¶
Load Times: - Initial page load: <1 second - Tab switching: <50ms (instant) - Database queries: <100ms (indexed) - File uploads: ~1-2 seconds (depends on batch size) - Conversation thread load: <100ms (v3.6)
Scalability: - Built for 100,000+ customers - No hardcoded limits - Database indexed for performance - CDN-cached static assets
Security & Best Practices¶
Authentication & Authorization¶
Cloudflare Access Protection: - Portal protected by Google OAuth - Only authorized emails can access - 24-hour session expiry - Force re-authentication on sensitive operations
API Keys in Portal:
⚠ï¸Â Service Role Key is embedded in the HTML file
This key has full database access. Security measures:
- Protected by Cloudflare Access - Key only accessible to authenticated users
- HTTPS Only - All traffic encrypted in transit
- No public exposure - Portal URL not publicly listed
- Audit trail - All database operations logged
- Key rotation - Rotate key quarterly
Never: - Disable Cloudflare Access - Share portal URL publicly - Share login credentials - Access portal from untrusted devices - Take screenshots with sensitive data
Data Security¶
In Transit: - All connections use HTTPS/TLS 1.3 - API calls encrypted end-to-end - No unencrypted data transmission
At Rest: - Supabase database encrypted at rest - Storage files encrypted at rest - Automatic backups encrypted
Access Control: - Row-level security on sensitive tables - Service role key isolated to portal only - Edge Functions use limited anon key
Best Practices¶
Daily Operations: 1. Always log out after pack day (or let session expire) 2. Clear browser cache on shared devices 3. Never save passwords in browser on shared devices 4. Use private/incognito mode on shared devices 5. Report suspicious activity immediately
Batch Processing: 1. Double-check Order IDs before adding to batch 2. Review complete batch before submitting 3. Verify success message after submission 4. Keep paper backup of tracking numbers (Phase A) 5. Check Make.com processed successfully
Quality Control: 1. Verify PCM calculations match expected values 2. Cross-check pack queue against orders received 3. Monitor batch status transitions (QA_HOLD → RELEASED) 4. Review Recent Activity regularly for anomalies 5. Investigate any failed operations immediately
Incident Response: 1. Note exact error message and time 2. Check browser console for detailed errors (F12) 3. Check Supabase logs (Edge Functions, Storage, Database) 4. Document steps to reproduce 5. Check Make.com scenario execution history 6. Contact technical lead with details
Compliance¶
Data Protection: - Customer data (names, addresses) visible in portal - Covered by Protocol Raw privacy policy - GDPR compliance maintained - Data retention per policy
Food Safety: - Batch traceability maintained - Lab certificate links stored - Recall capability via batch_code - Quality check records preserved
Audit Trail: - All database operations timestamped - Created_at, updated_at on all records - ops_events log for critical operations - CSV files archived in Supabase Storage - Email conversation threads preserved (v3.6)
Troubleshooting¶
Common Issues¶
Portal Shows 404¶
Symptoms: Page not found error at ops.protocolraw.co.uk
Causes:
1. File not named index.html
2. File in wrong directory/folder
3. Deployment failed
4. DNS not propagated
Resolution:
1. Check Cloudflare Pages deployment status
2. Verify file is named exactly index.html
3. Check file is at root level (not in subfolder)
4. Try backup URL: protocol-raw-ops.pages.dev
5. Clear browser cache and retry
Can't Log In¶
Symptoms: Cloudflare Access blocks login
Causes: 1. Email not in authorized list 2. Session expired 3. Cookies blocked 4. Access policy changed
Resolution: 1. Verify email is in Cloudflare Access policy 2. Clear browser cookies for ops.protocolraw.co.uk 3. Try different browser 4. Check Cloudflare Access application is active 5. Contact admin to verify email whitelist
Pack Day Button Doesn't Work¶
Symptoms: Calculate PCM button shows error or nothing happens
Causes:
1. Edge Function not deployed
2. Edge Function error
3. No orders in sent state
4. Network connectivity issue
5. API quota exceeded
Resolution:
1. Open browser console (F12) and check for errors
2. Verify Edge Function exists: Supabase Dashboard → Edge Functions
3. Check Edge Function logs for errors
4. Query database: SELECT * FROM raw_ops.orders WHERE export_state = 'sent'
5. Check OpenWeatherMap API quota
6. Test Edge Function directly via Supabase dashboard
Fulfillment Upload Fails¶
Symptoms: Submit Batch shows error, CSV not uploaded
Causes: 1. Storage bucket doesn't exist 2. Service Role Key invalid 3. Network error 4. Bucket permissions incorrect
Resolution:
1. Check browser console for detailed error
2. Verify bucket exists: Supabase Dashboard → Storage → dispatch-files
3. Verify inbox/ folder exists in bucket
4. Check Service Role Key is correct
5. Test upload manually via Supabase Storage UI
6. Check bucket policies allow service role write access
Batch Creation Fails¶
Symptoms: Create Batch shows error, batch not in database
Causes: 1. Duplicate batch code 2. Service Role Key invalid 3. Table doesn't exist 4. Validation error 5. Database permissions
Resolution:
1. Check browser console for detailed error
2. Query database: SELECT * FROM raw_ops.batches WHERE batch_code = 'YOUR-CODE'
3. Verify table exists: Supabase Dashboard → Table Editor
4. Check all required fields are filled
5. Verify Service Role Key has INSERT permission
6. Try different batch code
LocalStorage Batch Lost¶
Symptoms: Current Batch empty after page refresh
Causes: 1. Browser cache cleared 2. Incognito/private browsing mode 3. Different browser/device 4. LocalStorage quota exceeded
Resolution: 1. Check you're using same browser as when batch was created 2. Don't use incognito/private mode during pack day 3. Re-add orders to batch (check Recent Activity for order IDs) 4. Submit batches more frequently to avoid loss 5. Keep paper backup of Order IDs during pack day (Phase A)
Customer Search Not Working¶
Symptoms: Search returns no results or errors
Causes: 1. RPC function missing 2. Database permissions 3. Network error
Resolution:
1. Check public.search_customers function exists
2. Verify function has EXECUTE granted to anon and service_role
3. Check browser console for RPC errors
Ticket Assignment Not Showing¶
Symptoms: Assignment dropdown empty or not visible
Causes: 1. No active agents in database 2. RPC function missing 3. Column missing on tickets table
Resolution:
1. Verify raw_ops.agents table has active agents
2. Check public.get_active_agents function exists
3. Verify assigned_to column exists on support_tickets
Outbound Tickets Not Sending Email¶
Symptoms: Ticket created but no email sent
Causes: 1. Make.com route missing 2. Customer.io template issue 3. Webhook error
Resolution:
1. Check Make.com scenario has outbound_email route
2. Verify Customer.io support_response template has {{subject}} in subject line
3. Check Make.com execution history for errors
4. Verify Customer.io API key is correct
Outbound Tickets Not Appearing in Queue¶
Symptoms: Created outbound ticket not visible
Causes: 1. Missing columns on tickets table 2. View not updated 3. Wrong status
Resolution:
1. Verify is_outbound and outbound_reason columns exist on support_tickets
2. Check public.v_support_queue view includes outbound fields
3. Verify ticket was created with status='awaiting_reply'
Agent Review Queue Not Loading¶
Symptoms: Agent Review tab shows no decisions or errors
Causes:
1. Table cs_agent_decisions doesn't exist
2. No pending decisions
3. RPC function missing
Resolution:
1. Verify raw_ops.cs_agent_decisions table exists
2. Check for pending decisions: SELECT * FROM raw_ops.cs_agent_decisions WHERE review_status = 'pending'
3. Verify module is correctly imported in app.js
Conversation Thread Not Loading (v3.6)¶
Symptoms: Thread panel shows "No messages" or errors
Causes:
1. Table ticket_messages doesn't exist
2. No messages for ticket
3. RPC function missing
Resolution:
1. Verify raw_ops.ticket_messages table exists
2. Check for messages: SELECT * FROM raw_ops.ticket_messages WHERE ticket_id = 'uuid'
3. Verify public.get_ticket_messages function exists
4. Check browser console for RPC errors
Email Not Threading (v3.6)¶
Symptoms: Customer sees separate emails instead of thread
Causes:
1. email_message_id not captured on ticket
2. Headers not sent
3. Customer.io template issue
Resolution:
1. Check ticket has email_message_id populated
2. Verify send-support-email Edge Function is deployed
3. Check Edge Function logs for header construction
4. Verify Customer.io template accepts headers parameter
Error Messages¶
"Failed to fetch" - Network connectivity issue - API endpoint unreachable - CORS error - Check internet connection - Try different network - Check Supabase status: status.supabase.com
"Authorization header required" - API key missing or invalid - Check configuration section of HTML - Verify Anon Key or Service Role Key is correct - Check key hasn't been rotated
"Permission denied" - Database RLS (Row Level Security) blocking operation - Service Role Key should bypass RLS - Check key is correct service role key (not anon key) - Verify key has correct permissions in Supabase
"Unique constraint violation" - Trying to create duplicate record - Common with batch codes - Check existing records - Use different identifier
"Network request failed" - DNS resolution issue - SSL certificate issue - Cloudflare error - Check Cloudflare status: cloudflarestatus.com - Try backup URL: protocol-raw-ops.pages.dev
Getting Help¶
Self-Service: 1. Check this troubleshooting section 2. Open browser console (F12) for detailed errors 3. Check Supabase logs (Edge Functions, Database, Storage) 4. Check Make.com scenario execution history 5. Query database directly via Supabase SQL Editor
Escalation: 1. Document exact error message 2. Note time of occurrence 3. Describe steps to reproduce 4. Check if issue is persistent or intermittent 5. Gather relevant screenshots (redact sensitive data) 6. Contact technical lead with details
Maintenance & Updates¶
Regular Maintenance¶
Daily (Pack Days): - [ ] Verify portal loads correctly - [ ] Test Pack Day calculation - [ ] Monitor fulfillment batch submissions - [ ] Check Make.com processed dispatches
Weekly: - [ ] Review Recent Batches for status changes - [ ] Check Recent Orders matches expected volume - [ ] Monitor browser console for JavaScript errors - [ ] Verify Cloudflare Access policy is current - [ ] Review Agent Review queue (clear any backlog)
Monthly: - [ ] Review Supabase API usage and quotas - [ ] Check OpenWeatherMap API call count - [ ] Audit user access list (add/remove as needed) - [ ] Review error logs for patterns - [ ] Test disaster recovery procedures - [ ] Review AI agent approval rates
Quarterly: - [ ] Rotate Supabase Service Role Key - [ ] Update portal with new key - [ ] Review and update user access policies - [ ] Performance audit and optimization - [ ] Documentation review and updates
Updating the Portal¶
To update portal files: 1. Make changes to local files 2. Push to GitHub repository 3. Cloudflare Pages auto-deploys from main branch 4. Verify changes at ops.protocolraw.co.uk 5. Test all functionality 6. Document changes in version history
Cache Busting¶
When updating JavaScript modules, bump the version parameter:
- In
app.js:import support from './modules/support.js?v=N'; - In
index.html:<script type="module" src="js/app.js?v=N"></script>
Current version: v18 (bumped for v3.8)
Deployment Checklist¶
- Update module files
- Bump version in
app.jsimports - Bump version in
index.htmlscript tag - Push to GitHub
- Cloudflare Pages auto-deploys
- Hard refresh browser (Ctrl+Shift+R)
Keyboard Shortcuts¶
Global¶
| Shortcut | Action |
|---|---|
| Tab | Navigate between form fields |
| Enter | Submit focused form |
| Escape | Close modals |
| Ctrl/Cmd + F | Find on page |
| Ctrl/Cmd + 1 | Switch to Pack Day |
| Ctrl/Cmd + 2 | Switch to Fulfillment |
| Ctrl/Cmd + 3 | Switch to Batches |
| Ctrl/Cmd + 4 | Switch to Inventory |
| Ctrl/Cmd + 5 | Switch to Support |
| Ctrl/Cmd + 6 | Switch to Agent Review |
| Ctrl/Cmd + 7 | Switch to Live Chat |
Support Workstation¶
| Shortcut | Action |
|---|---|
| Ctrl/Cmd + Enter | Send response |
| Escape | Deselect ticket / Close modal |
Agent Review¶
| Shortcut | Action |
|---|---|
| A | Approve selected decision |
| R | Reject selected decision (opens feedback) |
| N | Next decision in queue |
Deployment¶
Cloudflare Pages¶
Project: protocol-raw-ops
Domain: ops.protocolraw.co.uk
Backup: protocol-raw-ops.pages.dev
Auto-Deploy: - Connects to GitHub repository - Deploys on push to main branch - Build command: (none - static files) - Output directory: /
Manual Deployment (if needed)¶
- Download current files from repository
- Make necessary changes
- Test locally (open in browser)
- Cloudflare Pages → Create deployment → Upload assets
- Verify at ops.protocolraw.co.uk
Appendix¶
Browser Compatibility¶
Fully Supported: - Chrome 90+ - Firefox 88+ - Safari 14+ - Edge 90+
Mobile: - iOS Safari 14+ - Chrome Android 90+
Not Supported: - Internet Explorer (any version) - Opera Mini
File Size & Performance¶
- HTML file size: ~35 KB
- JavaScript modules: ~65 KB total (including agent-review.js, thread updates)
- CSS files: ~15 KB total (including agent-review.css)
- No external JavaScript dependencies
- Google Fonts: ~50 KB (cached)
- Total page weight: <165 KB
- Load time: <1 second on 3G
Data Retention¶
LocalStorage: - Fulfillment batch: Until submitted or manually cleared - Browser-specific: Not synced across devices
Database: - Orders: Indefinite (business records) - Batches: Indefinite (traceability requirement) - Shipments: Indefinite (delivery records) - Packing instructions: 24 months (archived after) - Quality checks: 24 months (regulatory requirement) - Support tickets: Indefinite (customer service records) - Ticket messages: Indefinite (conversation history, v3.6) - AI agent decisions: 12 months (training data, then anonymized)
Backup & Recovery¶
Cloudflare Pages: - All deployments preserved - Can rollback to previous version instantly - Deployment history maintained indefinitely
Supabase Database: - Automatic daily backups - Point-in-time recovery (7 days) - Manual backup via Supabase dashboard
Critical Data: - Export batches table monthly (CSV) - Export orders table monthly (CSV) - Store batch lab certificates in cloud storage - Maintain paper backup of critical batch codes
Support Contacts¶
Portal Issues: - Cloudflare Support: https://support.cloudflare.com - Supabase Support: https://supabase.com/support
System Status: - Cloudflare: https://cloudflarestatus.com - Supabase: https://status.supabase.com - OpenWeatherMap: https://status.openweathermap.org
Internal: - Operations Lead: [contact info] - Technical Lead: [contact info] - QA Lead: [contact info]
For LLM Assistants¶
Adding New Features to Support Workstation¶
- Add RPC function in Supabase (public schema)
- Grant EXECUTE to service_role and anon
- Add JavaScript function in
support.js - Export function in default export
- Expose in
app.jsunderwindow.opsPortal.support - Add UI elements in
index.htmlwith onclick handlers - Bump version numbers and deploy
Key File Locations¶
- HTML:
index.html(all tab sections) - JavaScript:
js/modules/*.js(tab-specific logic) - CSS:
css/*.css(component styles) - Global API:
js/app.js(window.opsPortal.*) - Database: Supabase raw_ops schema + public RPC functions
Common Patterns¶
Adding a new tab module:
1. Create js/modules/newfeature.js
2. Create css/newfeature.css (if needed)
3. Import in app.js
4. Add to window.opsPortal namespace
5. Add tab HTML in index.html
6. Add navigation button
Adding database functionality:
1. Create table/view in Supabase
2. Create RPC function if complex logic needed
3. Add API call in api.js
4. Expose via module function
5. Wire up to UI
v3.6 File Changes Summary¶
| File | Change |
|---|---|
index.html |
Added conversation thread panel, editable subject field |
js/app.js |
Updated support module integration for threading |
js/config.js |
Bumped to v3.6 |
js/modules/support.js |
Added thread display, subject editing, send-support-email call |
Edge Function send-support-email |
New unified email sending with threading |
v3.5 File Changes Summary¶
| File | Change |
|---|---|
index.html |
Added Agent Review tab + content section |
js/app.js |
Added agentReview module import and registration |
js/config.js |
Fixed syntax error, bumped to v3.5 |
js/modules/agent-review.js |
New file |
js/modules/support.js |
Fixed order_number_label reference |
css/agent-review.css |
New file |
Version History¶
| Version | Date | Changes |
|---|---|---|
| 3.8 | 2026-02-17 | Batch status terminology corrected (CLEARED→RELEASED, QA_FAIL→QUARANTINE), database schema updated to match live system, documentation aligned to portal v3.8 |
| 3.7 | 2026-02 | Refund action buttons in Support Workstation |
| 3.6 | 2026-01-20 | Conversation thread panel, email threading (In-Reply-To/References), [Support] subject prefix, editable subject, ticket_messages table, send-support-email Edge Function |
| 3.5 | 2026-01-19 | Agent Review tab for shadow mode validation, bug fixes |
| 3.4 | 2026-01-13 | Documentation consolidation - merged v2.0 and v3.3 into comprehensive document |
| 3.3 | 2025-12-10 | Customer Search, Customer Profile, Ticket Assignment, Outbound Tickets |
| 3.2 | 2025-12-10 | Subscription actions, order history, internal notes, bidirectional Seal sync |
| 3.1 | 2025-12-09 | Support Workstation UI refinements |
| 3.0 | 2025-12-04 | Modular ES6 architecture, Support Workstation |
| 2.1 | 2025-11-28 | Auto-generated batch codes, dual ID system |
| 2.0 | 2025-11-15 | Pack Day, Fulfillment, Batch Creation, tab navigation, Protocol Raw branding |
| 1.0 | 2025-11-04 | Initial basic fulfillment interface |
Document Owner: Protocol Raw Operations Team
Last Reviewed: February 17, 2026
Next Review: May 17, 2026
Version: 3.8
Status: Production Ready ✅
End of Protocol Raw Operations Portal Documentation v3.8