Why Code-Based Scoring Over Gemini

The initial architecture considered using a Gemini agent to score churn risk from free-text customer data. This was rejected for one reason: the scoring logic is entirely deterministic. It is multiplication and comparison. Sending a math problem to an LLM adds 2–4 seconds of latency, API cost, and a failure surface for zero additional intelligence. The code node calculates the same result in under 10 milliseconds every time.

Gemini was deliberately reserved for the one task where it genuinely adds value — generating personalised email copy. That decision is in the Phase 2 roadmap.


Why Per-Customer Repurchase Interval Instead of Fixed Thresholds

The first version used fixed thresholds: 30 days for AT_RISK, 60 days for LAPSED, 90 days for CHURNED. This failed immediately on the seed data. A customer who buys every 20 days was flagged as AT_RISK after 30 days even when they had just ordered. A customer who buys every 90 days was flagged as CHURNED at 91 days when they were perfectly on schedule.

The multiplier model makes the threshold relative to each customer's personal rhythm. This is the architecture decision that makes RetainIQ genuinely useful rather than just another fixed-rule system.


Why Two Separate Workflows Instead of One

A single combined workflow would require logic to differentiate between individual events and bulk scans — adding conditional branching that made the workflow harder to debug. Two clean workflows with single responsibilities are easier to test, extend, and produce cleaner execution logs.

The manual scan webhook on Workflow 2 was added specifically so the dashboard button could trigger a real scan during a demo without waiting for the midnight cron.


Why Supabase Over Firebase

SQL structure enables the filtered, grouped, and sorted queries that power the dashboard — most purchased product, revenue by stage, interventions by type. These require GROUP BY and SUM operations that NoSQL makes unnecessarily complex.


Why n8n Over a Custom Backend

n8n provides observable execution logs that make debugging a live production system significantly faster. When the SplitInBatches loop silently processed only one customer instead of 26, the execution view showed exactly which node received zero items. A custom backend would have required log parsing.


Biggest Technical Failure and What It Taught

The SplitInBatches node in Workflow 2 processed all 26 customers silently but updated zero Supabase records. The workflow showed success. The execution logs showed green nodes. Supabase showed no changes.