Fionn
AI-Powered Renewal Management System — Architecture Document
1. System Overview
Fionn is an AI-based software renewal management system that automates the end-to-end renewal lifecycle — from initial customer outreach through final contract closure. It operates across multiple integrated platforms to identify upcoming renewals, engage customers via intelligent email conversations, track renewal stages, and provide real-time operational visibility through a management dashboard.
Fionn replaces manual renewal management with an autonomous AI agent that handles outreach, follow-ups, sentiment analysis, pricing, quoting, and stage progression — all while maintaining strict communication discipline and contract rules.
Core Principles
- Fully autonomous — Fionn handles outreach, replies, reminders, and escalations without human intervention in standard cases
- Asynchronous communication only — all customer engagement happens via email; no calls, no meetings
- Contract discipline — pricing, terms, and contract structures are enforced programmatically
- Stage-driven progression — every opportunity follows a defined renewal pipeline with clear transition rules
- Real-time visibility — a dedicated dashboard surfaces pipeline health, AI assessments, and email activity
2. High-Level Architecture
graph TB
subgraph FionnSystem [Fionn System]
SF["Salesforce<br/>(Trilogy Sales + No Software Speed)"]
CC["CuChulainn<br/>AI Engine<br/>4 Packages · 14 Skills · 1 Agent"]
DASH["Fionn Dashboard<br/>S3 + CloudFront + Cognito SSO"]
MCP["MCP Server<br/>Function URL"]
SBX["Sandbox Stack<br/>Parallel test environment"]
COMP["Compliance<br/>Indexer + Docs API"]
end
subgraph ExternalSystems [External Systems]
KLAIR["Klair<br/>NetSuite Data"]
NETSUITE["NetSuite REST<br/>Subsidiary + Subscription"]
KAYAKO["Kayako<br/>Support Tickets"]
OPENAI["OpenAI<br/>GPT-5.3-instant + Cost API"]
GAS["Gmail + Apps Script<br/>gmailwatch · senders"]
GDRIVE["Google Drive + Sheets<br/>Compliance documents"]
ADOBE["Adobe Sign<br/>Agreements"]
ADOPT["Klairvoyant<br/>Adoption API"]
COGNITO["AWS Cognito<br/>Google SSO"]
end
SF <--> CC
CC <--> DASH
SF <--> DASH
CC --> KLAIR
CC --> KAYAKO
CC --> OPENAI
GAS <--> CC
OPENAI --> DASH
DASH <--> COGNITO
DASH <--> MCP
DASH <--> ADOBE
DASH --> ADOPT
COMP --> GDRIVE
COMP --> NETSUITE
DASH <--> COMP
DASH <--> SBX
SBX --> CC
CUSTOMER["Customer<br/>Email Inbox"] <--> GAS
CC --> CUSTOMER
3. Component Architecture
3.1 CuChulainn — AI Execution Engine
CuChulainn is the core AI platform that powers Fionn's autonomous operations. It provides the runtime for AI packages, each containing workflows, skills, and agents.
graph LR
subgraph CuChulainn Platform
GO["GeneralOutbound<br/>First contact with customer"]
GI["GeneralInbound<br/>Reply to every inbound email"]
RP["ReminderPackage<br/>Follow-up + find more users"]
EI["EmailInvestigator<br/>Find alternate emails"]
SA["SalesforceAgent<br/>6 Salesforce skills"]
SK["14 Shared Skills<br/>API endpoints"]
end
GO --> SK
GI --> SK
RP --> SK
EI --> SK
GO --> SA
GI --> SA
RP --> SA
EI --> SA
3.2 Fionn Dashboard — Operational Visibility Layer
The dashboard provides real-time pipeline visibility, AI health assessments, and operational controls.
| Component | Technology | Purpose |
|---|---|---|
| Frontend | S3 + CloudFront | Static HTML/JS/CSS dashboard with Cognito SSO |
| CDN | CloudFront (E22HOIROU34E4P) | Global content delivery + API routing |
| API Gateway | HTTP API (o61t89e1x1) | REST endpoint routing |
| Authentication | AWS Cognito (Google SSO) | User pool + role lookup via FionnUsers |
3.3 Lambda Inventory
All deployed Lambdas in account 582049328161 / us-east-1. Source-of-truth deploy mappings live in .cursor/rules/lambda-deploy.mdc.
| Lambda | Source | Purpose |
|---|---|---|
fionn-dashboard-api | lambda_handler.handler | Main HTTP API monolith — opps, emails, AI, notes, flags, agreements, financials, sentiment, RCA, users |
fionn-dashboard-sync | lambda_handler.sync_handler | Daily Salesforce → DynamoDB sync + safe upsert |
fionn-auto-trigger | lambda_handler.auto_trigger_handler | Auto-trigger Fionn at ≤180 days; smart-defer reminders |
fionn-ai-scan-daily | lambda_handler.ai_scan_handler | Daily AI status refresh + deferral signal scan |
fionn-openai-cost-updater | lambda_handler.openai_cost_refresh_handler | Hourly pull of OpenAI org cost into FionnFinancials |
fionn-mcp-server | lambda_mcp_server.py | MCP Streamable HTTP server (Function URL with token) |
fionn-compliance-indexer | lambda_compliance_indexer.py | Daily Drive + Sheet walker → FionnComplianceIndex |
fionn-compliance-docs | lambda_compliance_docs.py | Function URL: opp/NS ID → subsidiary cache → compliance docs (with Drive bytes) |
fionn-email-logger | lambda_email_logger.py | Ingest email events into FionnEmailLogs (+ sandbox table) |
fionn-netsuite-api | lambda_netsuite_api.py | NetSuite ID lookup; synthetic sandbox payloads |
fionn-sandbox-testing | lambda_sandbox_testing.py | Trigger sandbox CuChulainn package; scan logs/tests |
fionn-sandbox-query | lambda_sandbox_query.py | Sandbox FionnEmailLogs-Sandbox thread / product lookup |
fionn-adoption-api | lambda_adoption_api.py | Proxy for Klairvoyant adoption API per account/opp |
fionn-pricing-calculator | lambda_pricing_calculator.py | Renewal pricing (1/3/5y × tiers) with FX + per-product floors |
fionn-quote-cloner | lambda_quote_cloner.py | CPQ clone / tier swap / approvals in NoSoftware Speed SF |
fionn-address-validated | lambda_address_validated.py | Sets Addresses_Validated__c on Opportunity (NSS SF) |
fionn-chat-websocket | lambda_chat_ws.py | WebSocket chat: dashboard context + CuChulainn + OpenAI |
fionn-task-complete | lambda_task_complete.py | Trivial TASK_COMPLETE handler for integrations |
3.4 DynamoDB Tables
| Table | Purpose |
|---|---|
FionnDashboard (a.k.a. FionnDashboard-prod) | Opportunity data, AI status, flags, notes, defer state |
FionnEmailLogs | Email conversation history |
FionnProductConfig | Product-to-project mappings and aliases |
FionnFinancials | Vendor spend + OpenAI cost rollups |
FionnUsers | Cognito user → role mapping (admin / standard) |
CustomerSentimentHistory | Sentiment alert history (/sentiment-alerts) |
FionnComplianceIndex | Indexed Drive + Sheet compliance documents |
FionnSubsidiaryCache | NetSuite subsidiary resolution cache |
FionnDashboard-Sandbox | Sandbox opportunity data |
FionnEmailLogs-Sandbox | Sandbox email log mirror |
3.5 Scheduled Processes
Five scheduled jobs run via AWS EventBridge:
| Schedule | Lambda | Cron | Purpose |
|---|---|---|---|
| Daily Sync | fionn-dashboard-sync | cron(0 6 * * ? *) — 6 AM UTC | Salesforce data sync + safe upsert |
| AI Scan | fionn-ai-scan-daily | Daily ~7 AM GMT | AI status refresh + deferral signal scan across all open opps |
| Auto-Trigger | fionn-auto-trigger | cron(0 14 * * ? *) — 2 PM GMT | Auto-trigger at ≤180 days; reminders for stale Pending opps |
| Compliance Index | fionn-compliance-indexer | Daily | Walk Drive folder + Sheet → upsert FionnComplianceIndex |
| OpenAI Cost | fionn-openai-cost-updater | Hourly | Pull OpenAI org cost into FionnFinancials |
3.6 Function URL Lambdas
Two Lambdas are exposed via dedicated AWS Function URLs (no API Gateway):
| Lambda | URL Pattern | Auth |
|---|---|---|
fionn-mcp-server | https://eu4zkntsvzzv66gwmir2lragi40kxcpe.lambda-url.us-east-1.on.aws/?token=<MCP_ACCESS_TOKEN> | Bearer token in query string |
fionn-compliance-docs | https://no7calsf7skczvbrkulue7jdbq0fieav.lambda-url.us-east-1.on.aws/ | IAM / open (read-only lookup) |
4. CuChulainn Packages — Detailed Flows
4.1 GeneralOutbound
Purpose: First contact with the customer when a renewal is approaching.
Trigger: Dashboard trigger (manual or auto-trigger at ≤180 days to renewal).
Package ID: PACKAGE-d3a9354c-3d3e-4edd-9494-c55898403852 (common for all products)
flowchart LR
T["Trigger<br/>(Manual or Auto)"] --> FETCH["Fetch Opportunity<br/>from Salesforce"]
FETCH --> KLAIR["Get NetSuite<br/>Contract Data"]
KLAIR --> COMPOSE["AI Composes<br/>Outreach Email"]
COMPOSE --> SEND["Send Email<br/>to Customer"]
SEND --> LOG["Log to<br/>FionnEmailLogs"]
LOG --> UPDATE["Update Opp Stage<br/>→ Outreach"]
Key behaviors
- Retrieves full contract context from NetSuite via Klair before composing
- Email is AI-generated, warm, professional, and product-aware
- Never mentions pricing, internal IDs, or meeting requests in first outreach
- Marks opportunity as
FionnTriggered = Yesin DynamoDB
4.2 GeneralInbound
Purpose: Process and respond to every inbound customer email related to a renewal.
Trigger: Google Apps Script routes inbound email to CuChulainn.
flowchart LR
IN["Inbound Email<br/>via Apps Script"] --> PARSE["Parse Email<br/>+ Thread Context"]
PARSE --> ANALYZE["AI Sentiment<br/>Analysis"]
ANALYZE --> DECIDE["Determine<br/>Response Strategy"]
DECIDE --> REPLY["AI Composes<br/>Reply"]
REPLY --> SEND["Send Reply<br/>to Customer"]
SEND --> STAGE["Update Stage<br/>if Needed"]
Key behaviors
- Maintains full thread context for coherent conversations
- Detects customer sentiment and adjusts tone accordingly
- Escalates to human when customer explicitly requests it
- Progresses stage automatically when conversation milestones are reached
4.3 ReminderPackage
Purpose: Follow up when no customer response has been received. Discovers and adds additional contacts to widen the outreach net.
Trigger: Auto-trigger (daily at 2 PM GMT for Pending opps with no reply in 5+ days) or manual dashboard trigger.
Package ID: PACKAGE-9dc9897a-3d92-4dc1-b7c6-ddd3591a74e8
flowchart LR
CHECK["Check Last<br/>Mail Date"] --> DEFER{"Defer Signal<br/>Detected?"}
DEFER -->|Yes| PAUSE["Pause Until<br/>Follow-up Date"]
DEFER -->|No| CONTACTS["Find Additional<br/>Contacts"]
CONTACTS --> COMPOSE["AI Composes<br/>Follow-up"]
COMPOSE --> SEND["Send Reminder<br/>Email"]
SEND --> LOG["Log + Update<br/>Reminder Count"]
Key Differentiator: Actively searches for additional contacts beyond Salesforce, broadening reach when the original contact is unresponsive.
4.4 EmailInvestigator
Purpose: Find alternate email addresses when delivery fails or the primary contact is unreachable.
Trigger: Called by other packages when email bounces or no response after multiple reminders.
flowchart LR
BOUNCE["Delivery Failure<br/>or No Response"] --> SEARCH["Search Kayako<br/>+ Other Systems"]
SEARCH --> VALIDATE["Validate Found<br/>Addresses"]
VALIDATE --> UPDATE["Update Contact<br/>in Salesforce"]
UPDATE --> RETRY["Retry Outreach<br/>with New Address"]
5. Automated Trigger & Reminder System
The system runs autonomously at 2:00 PM GMT daily via the fionn-auto-trigger Lambda.
5.1 Auto-Trigger Rules
| Rule | Condition | Action |
|---|---|---|
| Auto-Trigger Outbound | ≤180 days to renewal AND not yet triggered AND not closed/finalizing | Calls Fionn outbound API, marks FionnTriggered = Yes, AutoTriggered = true |
| Auto-Send Reminder | Stage is "Pending" AND already triggered AND last mail direction is outbound AND 5+ days since last mail | Analyzes emails for defer → if no defer, sends reminder |
5.2 Smart Defer Detection
Before sending any auto-reminder, the system analyzes the last 5 emails using GPT-5.3-instant to detect defer signals from the customer.
Detected signals include
- "It's too early, let's discuss later"
- "We will follow up in June"
- "Let's reconnect after Q2"
- "Can we discuss this on March 25?"
- "We're not ready yet, please reach out in 3 months"
When a defer is detected
- GPT extracts the follow-up date (converts relative dates like "in 2 weeks" to actual dates)
ReminderPausedUntilis stored in DynamoDB with the extracted dateDeferReasoncaptures the customer's statement- Reminders are suppressed until the follow-up date
- When the date arrives, reminders automatically resume
flowchart TB
AUTO["Auto-Trigger<br/>2 PM GMT Daily"] --> SCAN["Scan All<br/>Open Opportunities"]
SCAN --> TRIGGER{"≤180 Days<br/>& Not Triggered?"}
TRIGGER -->|Yes| OUTBOUND["Call Fionn<br/>Outbound API"]
TRIGGER -->|No| PENDING{"Pending Stage<br/>& 5+ Days Stale?"}
PENDING -->|Yes| PAUSED{"Reminder<br/>Paused?"}
PAUSED -->|Yes, Future| SKIP["Skip — Wait for<br/>Follow-up Date"]
PAUSED -->|No or Expired| ANALYZE["AI Analyzes<br/>Recent Emails"]
ANALYZE --> DEFER{"Defer Signal<br/>Found?"}
DEFER -->|Yes| STORE["Store Pause Date<br/>+ Reason"]
DEFER -->|No| REMIND["Send Reminder<br/>via ReminderPackage"]
PENDING -->|No| NEXT["Next Opportunity"]
5.3 Manual Pause/Resume
The dashboard provides manual controls to pause or resume reminders:
- Pause — Set a specific follow-up date and reason from the dashboard
- Resume — Clear any existing pause immediately
- API endpoint:
POST /reminder-pausewith{action: 'pause'|'resume', opportunityId, pauseUntil?, reason?}
6. Skills Reference
All skills are shared across packages. Each skill is an API endpoint performing one atomic task.
| # | Skill Name | Description |
|---|---|---|
| 1 | send_email_fionn | Send email from Fionn mailbox to customer |
| 2 | get_sf_details | Get full opportunity details from Salesforce |
| 3 | update_sf_stage | Update opportunity stage in Salesforce |
| 4 | get_klair_contract | Fetch NetSuite contract data via Klair |
| 5 | get_klair_pricing | Fetch pricing and subscription details |
| 6 | search_kayako_tickets | Search Kayako for support history |
| 7 | get_kayako_contacts | Find alternate contacts from Kayako |
| 8 | pull_andon_cord_fionn | Emergency stop — halts all processing |
| 9 | get_sf_contact_roles | Get contact roles for an opportunity |
| 10 | update_sf_contact | Update contact information in Salesforce |
| 11 | search_sf_accounts | Search Salesforce accounts by criteria |
| 12 | get_email_thread | Retrieve full email thread history |
| 13 | validate_email | Validate email address deliverability |
| 14 | log_activity | Log activity to FionnEmailLogs DynamoDB table |
7. Agents Reference
| Agent | Skills Used | Purpose |
|---|---|---|
| SalesforceAgent | get_sf_details, update_sf_stage, get_sf_contact_roles, update_sf_contact, search_sf_accounts, log_activity | Manages all Salesforce interactions with AI intelligence to decide which data to fetch/update |
8. Renewal Pipeline — Stage Progression
The renewal lifecycle follows a strict sequential pipeline. Fionn manages transitions automatically based on conversation state.
flowchart LR
P["Pending"] --> O["Outreach"]
O --> E["Engaged"]
E --> PR["Proposal"]
PR --> QF["Quote Follow Up"]
QF --> F["Finalizing"]
F --> CW["Closed Won"]
F --> CL["Closed Lost"]
Stage Definitions
| Stage | Meaning | Typical Timeline |
|---|---|---|
| Pending | Renewal identified, no outreach yet | >180 days |
| Outreach | Initial email sent, awaiting response | 180–145 days |
| Engaged | Customer is actively responding | 145–90 days |
| Proposal | Quote or proposal shared | 90–60 days |
| Quote Follow Up | Awaiting customer decision on quote | 60–30 days |
| Finalizing | Contract in final closing stage (treated as closed) | 30–0 days |
| Closed Won | Renewal completed successfully | — |
| Closed Lost | Customer chose not to renew | — |
Stage Treatment
- Finalizing is treated as a closed stage — it is excluded from "open" counts, does not trigger reminders, and receives a deterministic GREEN AI signal
- Finalizing can result in either Closed Won or Closed Lost
9. Data Flow — End to End
graph TB
subgraph ExternalDataSources [External Data Sources]
SF_TS["Salesforce: Trilogy Sales<br/>Fionn AI owned opportunities"]
SF_NS["Salesforce: No Software Speed<br/>Renewal data · ARR · Stages"]
GDRIVE["Google Drive + Sheets<br/>Compliance documents"]
ADOBE["Adobe Sign<br/>Agreement status"]
end
subgraph AIandCost [AI & Cost Services]
OAI["OpenAI GPT-5.3-instant<br/>AI status · Summaries · Defer analysis"]
OAI_COST["OpenAI Org Cost API<br/>Hourly billing pull"]
AWS_COST["AWS Cost Explorer<br/>Vendor spend"]
end
subgraph FionnCore [Fionn Core]
CC["CuChulainn<br/>4 Packages"]
LAMBDA_SYNC["Lambda: Sync<br/>Daily 6 AM UTC"]
LAMBDA_AI["Lambda: AI Scan<br/>Daily ~7 AM GMT"]
LAMBDA_API["Lambda: API<br/>Dashboard backend"]
LAMBDA_AUTO["Lambda: Auto-Trigger<br/>Daily 2 PM GMT"]
LAMBDA_OAI_COST["Lambda: Cost Updater<br/>Hourly"]
LAMBDA_COMP["Lambda: Compliance<br/>Indexer + Docs"]
LAMBDA_MCP["Lambda: MCP Server<br/>Function URL"]
LAMBDA_SBX["Lambda: Sandbox<br/>Testing + Query"]
DDB["DynamoDB<br/>10 tables (prod + sandbox)"]
DASH["Dashboard UI<br/>S3 + CloudFront + Cognito"]
end
SF_TS --> LAMBDA_SYNC
SF_NS --> LAMBDA_SYNC
LAMBDA_SYNC --> DDB
LAMBDA_AI --> OAI
LAMBDA_AI --> DDB
DDB --> DASH
DASH --> LAMBDA_API
LAMBDA_API --> CC
LAMBDA_API --> ADOBE
LAMBDA_AUTO --> CC
LAMBDA_AUTO --> OAI
LAMBDA_AUTO --> DDB
LAMBDA_OAI_COST --> OAI_COST
LAMBDA_OAI_COST --> AWS_COST
LAMBDA_OAI_COST --> DDB
LAMBDA_COMP --> GDRIVE
LAMBDA_COMP --> DDB
DASH --> LAMBDA_MCP
LAMBDA_MCP --> LAMBDA_API
DASH --> LAMBDA_SBX
LAMBDA_SBX --> CC
LAMBDA_SBX --> DDB
Data Sync Process (Daily + On-Demand)
- Trilogy Sales query — Fetch all Fionn AI-owned opportunity IDs via SOAP API
- No Software Speed query — Fetch renewal data (ARR, stage, dates) for those IDs via REST API
- Email log merge — Fetch from FionnEmailLogs DynamoDB + legacy mail tracking API
- Safe upsert — Write to DynamoDB preserving protected fields (triggers, reminders, flags, notes, AI status, defer state)
- Stale cleanup — Remove records no longer in Salesforce
- AI refresh — Generate/update AI health status for all open opportunities
- DaysSinceLastMail — Recalculated in real-time on every API response (not stored stale)
10. Dashboard Features
10.1 Hierarchical Table View
Opportunities are organized in a collapsible hierarchy:
All groups are collapsed by default. Expand All / Collapse All toggle is available. A second "Flat View" tab shows all opportunities without grouping.
10.2 Per-Opportunity AI Status
Each opportunity has an AI-generated health assessment powered by GPT-5.3-instant:
| Signal | Meaning | Criteria |
|---|---|---|
| 🟢 GREEN | On Track | Stage matches or ahead of timeline, active communication, no overdue AR |
| 🟡 YELLOW | Attention | Stage slightly behind, or communication stalled >14 days |
| 🔴 RED | At Risk | Stage significantly behind, customer expressed intent to cancel, OR any overdue AR balance > $0 on the customer or the reseller (deterministic override — see 10.2.1) |
AI status is refreshed:
- Daily — automatically after sync (overdue refresh runs first so the AI prompt sees fresh AR data)
- On demand (single) — click refresh icon next to any opportunity
- On demand (bulk) — click "Refresh All AI" in toolbar (with progress polling)
10.2.1 AR / Overdue Risk Override
The AI prompt is given the customer's NetSuite overdue balance plus, for indirect deals, the reseller's overdue balance. If either is > $0 the signal is forced to RED (deterministic post-process, independent of what the model returns) and the summary is prefixed with the overdue amounts. This guarantees that an account who is 30+ days behind on invoices never shows GREEN regardless of stage or email engagement.
- Customer overdue — fetched from NetSuite via
NETSUITE_OVERDUE_URLusingAccount.NetSuite_ID__c; stored asOverdueBalance+OverdueBalanceUpdatedAt. - Reseller overdue — only captured when the SF
OpportunityPartnerrelationship has a Reseller/Distributor/VAR record (the SOQL pullsAccountFrom.NetSuite_ID__c). Stored asResellerOverdueBalance+ResellerOverdueBalanceUpdatedAt+ResellerNetSuiteID. Opps where reseller is only inferred from the opp-name pattern get aResellerNamelabel but no NS lookup.
10.3 AI Status Click-to-Expand
Clicking an AI signal expands an inline detail panel below that opportunity showing:
- Color-coded signal badge (On Track / Attention / At Risk)
- Full AI-generated summary text
- Last updated timestamp
10.4 Smart Reminder Controls
Each opportunity's reminder column shows contextual controls:
- Active — "Remind" button + pause (⏸) button to manually set a follow-up date
- Deferred (AI-detected) — Green badge with follow-up date + resume (▶) button
- Deferred (Manual) — Blue badge with follow-up date + resume (▶) button
- Expired pause — "Remind" button reappears + clear (✕) button
10.5 KPI Cards & Running Totals
| Metric | Description |
|---|---|
| Urgent (<30d) | Open opportunities within 30 days of renewal |
| Upcoming (30-90d) | Open opportunities 30-90 days from renewal |
| Fionn Triggered | Total opportunities with outbound initiated |
| Emails Sent | Total email count across all opportunities |
| Deferred | Opportunities with paused reminders (AI or manual) |
| Running ARR | Dynamic ARR total in toolbar, updates with filters |
10.6 Additional Features
- Sync Health — Trilogy Sales count vs Dashboard count, missing opportunity tracking
- Email History — Full conversation thread per opportunity with HTML rendering, quoted replies, signatures; external images stripped for tracking pixel protection
- Notes — Internal notes per opportunity with timeline view and delete
- Flags — Flag at-risk opportunities for visibility
- PDF Reports — Filtered renewal reports with AI executive summary, cover page with stage breakdown, timeline, legend; loading indicator prevents double-clicks
- CSV Export — Configurable column selection, grouping by BU/Product
- Product Configuration — Manage product settings with Ephor Project IDs; product alias mapping for Salesforce name variations
- Searchable Multi-Select Filters — Product, Stage, Fionn Status, Open/Closed (with separate Finalizing option), Renewal Window
- Support Link — Direct link to fionn-renewals.kayako.com
- Architecture Page — This document, accessible from the sidebar
10.7 Dashboard Sections (Sidebar Views)
The dashboard exposes multiple views via the sidebar in dashboard/index.html + dashboard/app.js. Some are admin-only (gated by FionnUsers role). The sidebar order matches the in-product order; Performance is the default landing route after sign-in (Viewer accounts fall back to Renewals).
Performance, Renewals, and Conversation Quality share a single Unified Filter Bar (Date Range · BU · Products · Stages · Fionn Status · Renewal Window · ARR Tier · Status · Search). Filter state persists in URL params with a localStorage fallback (fionn.filters.v1) and follows the operator across these three views — an active-filter pill row appears above the KPIs with per-pill clear buttons and a "Clear all" link. The BU control is a preset that auto-populates Products with the selected Business Unit's product list (mirrors BUSINESS_UNIT_MAP in backend/lambdas/lambda_handler.py); manually editing products auto-resets BU to "All". Window-scope KPIs and charts respect the Date Range; portfolio-scope sections are tagged with a Portfolio badge and ignore the Date Range.
The Performance header is organised into three semantic strips: Portfolio (Total ARR Managed — portfolio-scope, ignores Date Range), Retention (Gross Retention, Net Retention, DM%, Renewal Event Retention — all window-scope, Playbook conventions; Net Retention carries a ✓/⚠ indicator vs the 90% floor), and ARR Flow (Closed ARR, Active ARR, New ARR out-for-signature, Churn $, Downsell $, Overdue ARR). Gross and Net Retention share the same denominator (Total Revenue = Old ARR = Curr ARR on Won + Lost); Gross clamps each renewal to min(New, Curr), Net includes upsells. DM% (Double Maintenance) = (Total Revenue + Upgrades − Downgrades − Churn + New Business) / Total Revenue, with New Business = 0 for this dataset. Every $ tile in the flow strip is a drill-through: clicking mutates the unified FILTERS state (status/stages/win, preserving dr) and navigates to the Renewals or Agreements view. Prior-window deltas (same-length window immediately preceding) appear as ▲/▼ arrows; colours invert for churn and downsell so rising = red. Overdue ARR ignores the Date Range end (always as-of-now) and renders a red accent when > 0.
Below the three primary strips, the Performance tab renders a secondary Agent metrics row containing five demoted KPIs (Win Rate, Automated Resolution, Response Rate, Avg Reminders / Deal, Avg Emails to Close) plus a Conversation Quality link tile that navigates to the Conversation Quality view. Each tile exposes its formula as small muted text at rest (readable without hovering). Win Rate, Automated Resolution, and Response Rate render a 90-day weekly SVG sparkline (_perfSparkline) with a dashed target line — 80%, 50%, 60% respectively — and the line/last-point colours green when at/above target, amber when below.
The Performance tab also carries three window-scoped diagnostic charts/queues, all respecting the unified filter bar: (1) HVO Cadence Funnel — opportunities with ARR_USD (or ARR) ≥ $100K distributed across cadence buckets (Pre-cadence >210d / Upcoming / Mid / Urgent / Overdue) using DaysToRenewal; bars are clickable drill-throughs into Renewals with win+tier=hvo pre-applied, and an "N off-cadence" pill surfaces when any HVO falls into the Overdue bucket. (2) AR Step Funnel — Sub-HVO accounts (<$100K) on auto-renewal, counted at each of the six live notice milestones projected on Opportunity: D-104 → D-89 → D-60 → D-40 → D-14 → D-0 (confirm). (3) Escalation Queue — a table of AI-flagged escalations (AISignal=RED) sorted by urgency (lowest DaysToRenewal) then ARR desc, with a "N flagged" pill in the header. The Stage Funnel bars now carry inline numeric labels via the shared _perfValueLabelsPlugin (Chart.js afterDatasetsDraw). Earlier iterations included three placeholder sections (D-82/D-21/D-7 greyed AR bars, a Pricing Strategy Mix card awaiting Opportunity.PricingStrategy__c, and a "Linked Fix Ticket" column awaiting FixTicketURL) — all removed to keep the Performance tab live-data-only.
The Adobe Sign Quote & Term Breakdown (3 summary tiles: Agreements Sent · Signed · Waiting to be Signed, plus 4 term cards: 12mo, 36mo, 60mo, No Term Data) lives on the Agreements tab rather than Performance. The "No Term Data" card absorbs agreements with no matched opp/term and non-standard terms (18/24/48/…). renderQuoteTermBreakdown(_agreementsData) is called from refreshAgreements() and from _refreshAgreementsAfterOverride() so that manual signed overrides propagate into the breakdown tiles.
Settings access. Settings is no longer a sidebar nav entry — it now opens from a gear icon at the bottom of the sidebar (Admin-only). The redesigned modal uses a card-based product list with inline search, two-column forms, and in-modal toast feedback instead of blocking alert() dialogs. Esc closes the modal; overlay click still dismisses.
Agreements carry an optional manual status override (e.g. "customer signed outside Adobe Sign"). Overrides are stored per-browser in localStorage["fionn.agreementStatusOverrides"] keyed by Adobe Sign agreement ID; the override rewrites the effective status at match-cache build time, so Performance Strip 3 ("New ARR out-for-signature"), the Agreements table, the Quote & Term Breakdown, and the status chip counters all stay coherent without branching. The raw Adobe Sign status is preserved on _rawStatus and exposed in the agreement detail panel alongside an Undo control.
| # | View | Access | Purpose |
|---|---|---|---|
| 1 | Performance (default landing) | Manager+ | Three KPI strips (Portfolio · Retention · ARR Flow), Agent metrics secondary row with sparklines, AI health / funnel charts, product performance |
| 2 | Renewals | All | Hierarchical + Flat opportunity views (described in §10.1). Column triage: 10 essential columns always visible (Customer, Product, Renewal Date, Days, Auto-Renew, Curr ARR, New ARR, Overdue, Stage, Fionn status) + 6 icon columns (Flag, Notes, Analysis, Reseller, Excl., AI). 17 contextual columns (NetSuite, NS Sub, Quote, Opp ID, etc.) behind inline row-expand chevron. Frozen default: Through Customer. Column preferences persisted per user via localStorage. |
| 3 | Conversation Quality | Manager+ | Summary tiles (Avg Score, Scored, Good/Fair/Poor), 30-day rubric trend chart (7 dimensions + 7/10 target line), per-prompt-version comparison table (auto-hidden unless ≥2 versions), scored-conversation table with per-row "View conversation" action (/email-detail), bulk + single re-scoring (/conversation-quality). Uses shared filter bar. |
| 4 | Agreements | Manager+ | Adobe Sign agreement status + linked opportunities; Quote & Term Breakdown (12/36/60mo + No Term Data); manual signed-outside-Adobe override |
| 5 | Reports | Manager+ | Filtered renewal PDF reports with AI executive summary (described in §10.6) |
| 6 | Customer Asks | All | Standalone request tracker (requests.html, see §19) |
| 7 | Architecture | Admin | This document |
| 8 | Financials | Admin | OpenAI cost rollups + AWS Cost Explorer vendor spend (FionnFinancials) |
| 9 | Users | Admin | Manage Cognito users + roles in FionnUsers |
| 10 | Sandbox Testing | Admin | Trigger sandbox CuChulainn package; list test results + sandbox logs |
| 11 | RCA | Manager+ (no FinanceAdmin) | Root Cause Analysis: create/list incidents with PDF export |
| 12 | Developer | Admin (no FinanceAdmin) | Embedded Swagger + /app-config MCP key/URL + internal Function URL table |
| 13 | Sentiment | Manager+ | Customer sentiment timeline (/sentiment-alerts, CustomerSentimentHistory) |
| 14 | Contract Review | Manager+ | Toxic-contract analysis via external Lambda URL + /contract-review-ai |
| 15 | Support | All | External link to Kayako (fionn-renewals.kayako.com) |
Standalone pages
live.html— Live Activity feed (polls/live-activity) + Fionn AI WebSocket chat tabswagger.html— Public OpenAPI 3 documentation page (auth banner)
11. Integration Map
graph TB
subgraph ExternalDataSources [External Data Sources]
SF_TS["Salesforce: Trilogy Sales<br/>Fionn AI owned opportunities"]
SF_NS["Salesforce: No Software Speed<br/>Renewal data · ARR · Stages"]
KLAIR["Klair<br/>NetSuite contract · Pricing"]
NETSUITE["NetSuite REST<br/>Subsidiary · Subscription"]
KAYAKO["Kayako<br/>Support tickets · Contacts"]
GDRIVE["Google Drive + Sheets<br/>Compliance documents"]
ADOBE["Adobe Sign<br/>Agreements"]
ADOPT["Klairvoyant Adoption API"]
end
subgraph AIServices [AI Services]
OAI_CC["OpenAI<br/>CuChulainn email gen + sentiment"]
OAI_DASH["OpenAI GPT-5.3-instant<br/>AI status · Defer · Summaries"]
OAI_COST["OpenAI Org Cost API"]
AWS_COST["AWS Cost Explorer"]
end
subgraph FionnCore [Fionn Core]
CC["CuChulainn<br/>4 Packages"]
LAMBDA["AWS Lambda<br/>18 functions"]
MCP["MCP Server<br/>Function URL"]
WS["WebSocket Chat<br/>fionn-chat-websocket"]
DDB["DynamoDB<br/>10 tables"]
DASH["Dashboard UI<br/>S3 + CloudFront"]
end
subgraph AuthAndComms [Auth & Communication]
COGNITO["AWS Cognito<br/>Google SSO"]
GAS["gmailwatch + senders<br/>Apps Script"]
CUST["Customer<br/>Email inbox"]
end
SF_TS --> LAMBDA
SF_NS --> LAMBDA
LAMBDA --> DDB
DDB --> DASH
LAMBDA --> OAI_DASH
LAMBDA --> OAI_COST
LAMBDA --> AWS_COST
LAMBDA --> ADOBE
LAMBDA --> ADOPT
LAMBDA --> NETSUITE
LAMBDA --> GDRIVE
CC --> KLAIR
CC --> KAYAKO
CC --> OAI_CC
CC --> SF_NS
DASH --> COGNITO
DASH --> LAMBDA
DASH --> MCP
DASH --> WS
WS --> CC
MCP --> LAMBDA
LAMBDA --> CC
GAS --> CC
CC --> CUST
CUST --> GAS
12. Security & Authentication
| Layer | Measure |
|---|---|
| Authentication | AWS Cognito user pool with Google SSO; configured in dashboard/config.js |
| Authorization | Role-based access via FionnUsers DynamoDB table; admin-only views (Users, RCA create, sensitive admin actions) |
| MCP Token | Bearer token in URL query string (?token=<MCP_ACCESS_TOKEN>) for fionn-mcp-server Function URL; stored as Lambda env var, surfaced to admins via /app-config |
| Sandbox Isolation | Separate -Sandbox DynamoDB tables (FionnDashboard-Sandbox, FionnEmailLogs-Sandbox); separate sender (emailsendersandbox); synthetic NetSuite payloads via fionn-netsuite-api |
| API Keys | Stored in Lambda environment variables / AWS Secrets Manager via secrets_helper.py; never in frontend code or git |
| CORS | Origin whitelist (CloudFront domain + localhost dev) — no wildcard |
| Input Validation | Salesforce ID regex validation (^[a-zA-Z0-9]{15,18}$) on all ID parameters |
| XSS Protection | All user-supplied content escaped via escapeHtml() before DOM insertion |
| Email Sanitization | HTML emails sanitized via DOMParser — scripts, iframes, forms stripped; event handlers removed; external images blocked (tracking pixel protection) |
| CDN Integrity | SRI attributes on external script tags (jsPDF, AutoTable) |
| Sensitive Logging | Request logging excludes full event payload — only method + path logged |
| DynamoDB | Protected fields preserved during sync (triggers, flags, notes, AI, defer state never overwritten) |
| Write-Path Approvals | Anything that writes to NoSoftware Speed SF org requires explicit user approval per workspace rule |
13. Communication Guardrails
Fionn operates under strict communication rules enforced at the package level:
Forbidden in All Outbound Communication
- Pricing, contract terms, or deadlines (first outreach only)
- Meeting or call invitations
- Phone numbers, Calendly links, scheduling URLs
- Internal identifiers (NetSuite ID, Opportunity ID, ARR)
- Urgency or pressure language
- Assumptions about customer knowledge of renewal processes
Required in All Communication
- HTML formatted emails
- Professional, warm, non-aggressive tone
- Product name referenced (not internal codes)
- Signed as "Fionn" (no placeholders)
- Single email per workflow execution
- Thread history preserved in replies
Contract Rules
- Allowed terms: 1 year, 3 year, 5 year only
- No monthly contracts, no 2-year contracts
- No custom pricing outside approved structure
- Platinum Success Tier positioned first in upgrade discussions
14. Deployment Architecture
flowchart LR
DEV["Developer<br/>Machine"] --> FE["S3 Upload<br/>index.html · app.js<br/>styles.css · logo.png<br/>architecture.html"]
DEV --> BE["Lambda Deploy<br/>lambda_handler.py<br/>→ API + Sync + Auto-Trigger"]
DEV --> RT["API Gateway<br/>Route creation"]
DEV --> EB["EventBridge<br/>Schedule rules"]
FE --> CF["CloudFront<br/>Cache Invalidation"]
CF --> LIVE["Live Dashboard"]
style LIVE fill:#EDFAF3,stroke:#1A7F4B,color:#1A1A18
| Item | Value |
|---|---|
| AWS Account | 582049328161 |
| Region | us-east-1 |
| S3 Bucket | fionn-dashboard-frontend-582049328161 |
| CloudFront Distribution | E22HOIROU34E4P |
| API Gateway | o61t89e1x1 (HTTP API) |
| Cognito User Pool | Google SSO for dashboard authentication (config in dashboard/config.js) |
| Lambdas (18) | See §3.3 for the full inventory |
| MCP Function URL | https://eu4zkntsvzzv66gwmir2lragi40kxcpe.lambda-url.us-east-1.on.aws/?token=<MCP_ACCESS_TOKEN> |
| Compliance Docs Function URL | https://no7calsf7skczvbrkulue7jdbq0fieav.lambda-url.us-east-1.on.aws/ |
| DynamoDB Tables (11) | FionnDashboard, FionnEmailLogs, FionnProductConfig, FionnFinancials, FionnUsers, CustomerSentimentHistory, FionnComplianceIndex, FionnSubsidiaryCache, FionnRequests, FionnDashboard-Sandbox, FionnEmailLogs-Sandbox |
| Scheduled Jobs (5) | See §3.5 — daily sync, AI scan, auto-trigger, compliance index; hourly OpenAI cost |
| AI Model | GPT-5.3-instant (via OpenAI API) |
15. Email Pipeline
All customer email flows through a layered pipeline: a Gmail Apps Script poller (gmailwatch) routes inbound mail to CuChulainn, dedicated sender scripts handle outbound, and an event logger persists every send/receive into DynamoDB.
graph LR
INBOX["Customer<br/>Inbox"] --> GAS["gmailwatch<br/>Apps Script poller"]
GAS --> CC["CuChulainn"]
GAS --> BOUNCE["/handle-bounce/"]
GAS --> LOGIN["/log-inbound/"]
GAS --> PRODQ["fionn-product-query<br/>sandbox-query"]
CC --> SENDER["emailsenderprod<br/>or emailsendersandbox"]
SENDER --> LOGGER["fionn-email-logger"]
LOGGER --> DDB[("FionnEmailLogs<br/>+ Sandbox mirror")]
SENDER --> INBOX
CC --> GMAIL_API["lambda_gmail_thread<br/>Gmail API skill"]
Components
| Component | Path | Purpose |
|---|---|---|
| gmailwatch | gmailwatch + appsscript.json | Apps Script poller: unread inbox → CuChulainn external adapter; bounce handling; sandbox routing; calls handle-bounce / log-inbound / product-query |
| emailsenderprod | emailsenderprod | Outbound sender (production): CuChulainn → SMTP → fionn-email-logger → FionnEmailLogs |
| emailsendersandbox | emailsendersandbox | Sandbox sender: same pipeline, sandbox tables + sandbox NetSuite lookup |
| fionn-email-logger | backend/lambdas/lambda_email_logger.py | Ingest email events; updates FionnEmailLogs + dashboard rows |
| lambda_gmail_thread | backend/lambdas/lambda_gmail_thread.py | Gmail API full-thread fetch (CuChulainn skill, not standalone deploy) |
16. MCP Server
fionn-mcp-server (backend/lambdas/lambda_mcp_server.py) exposes 56 Fionn operations as Model Context Protocol tools over Streamable HTTP. This lets external MCP clients (Claude Code, Claude Desktop, Cursor) drive Fionn programmatically — querying opportunities, sending emails, triggering AI analysis, and more.
Endpoint
https://eu4zkntsvzzv66gwmir2lragi40kxcpe.lambda-url.us-east-1.on.aws/?token=<MCP_ACCESS_TOKEN>
Authentication
- Bearer token in URL query string (
?token=...) orAuthorization: Bearerheader - Token stored as Lambda environment variable (
MCP_ACCESS_TOKEN) and infionn/app-keysSecrets Manager - Surfaced to admins through the Developer view (
/app-config)
Deployment note
Deploy with python3 deploy_lambda.py fionn-mcp-server. The ZIP must include both lambda_mcp_server.py and secrets_helper.py — the handler is lambda_mcp_server.lambda_handler (not the AWS default lambda_function.lambda_handler).
56 tools by category
| Category | Tools |
|---|---|
| Dashboard | fionn_get_dashboard, fionn_get_stats, fionn_get_sync_health, fionn_get_live_activity, fionn_get_overdue_balance |
fionn_get_email_history, fionn_get_gmail_thread, fionn_send_email | |
| Triggers | fionn_trigger_ai_outreach, fionn_reset_trigger, fionn_send_reminder, fionn_send_followup, fionn_send_quote_followup, fionn_pause_reminder |
| AI | fionn_refresh_ai_status, fionn_refresh_all_ai, fionn_scan_deferrals, fionn_score_conversation, fionn_executive_summary |
| Sentiment | fionn_get_sentiment_alerts |
| Agreements | fionn_get_agreements, fionn_get_agreement_detail, fionn_get_current_quote_pdf |
| Annotations | fionn_get_prior_contacts, fionn_get_feedback_summary, fionn_toggle_flag, fionn_get_notes, fionn_add_note, fionn_delete_note, fionn_set_analysis, fionn_override_reseller, fionn_exclude_automation |
| Config | fionn_get_product_config, fionn_add_product, fionn_update_product, fionn_delete_product, fionn_update_reminder_config |
| Financials | fionn_get_financial_data, fionn_update_financial_contract, fionn_delete_financial_contract |
| Users | fionn_get_users, fionn_update_user_role, fionn_delete_user |
| Lambda-backed | fionn_get_ar_info, fionn_get_reseller_contacts, fionn_reseller_check, fionn_get_compliance_docs |
| Contact Discovery | fionn_discover_contacts, fionn_detect_stale_opportunities, fionn_advance_discovery, fionn_get_discovery_status, fionn_get_escalation_report |
| System | fionn_get_me, fionn_health_check, fionn_trigger_sync, fionn_debug_opportunity |
Used from
- Claude Code / Claude Desktop — primary usage; full tool access via MCP connection
- Dashboard Developer view — copy-paste connection string + key
- Cursor and other MCP-compatible IDEs
17. Compliance System
A two-Lambda pair maintains an indexed cache of compliance documents (NDAs, MSAs, addenda) and resolves them by opportunity or NetSuite ID.
graph LR
DRIVE["Google Drive<br/>Compliance folder"] --> INDEXER["fionn-compliance-indexer<br/>Daily EventBridge"]
SHEET["Google Sheet<br/>Manifest"] --> INDEXER
INDEXER --> CIDX[("FionnComplianceIndex")]
CLIENT["Dashboard / Caller"] --> DOCS["fionn-compliance-docs<br/>Function URL"]
DOCS --> SUB[("FionnSubsidiaryCache")]
DOCS --> NS["NetSuite REST"]
DOCS --> CIDX
DOCS --> DRIVE
DOCS --> CLIENT
Components
| Component | Source | Purpose |
|---|---|---|
fionn-compliance-indexer | backend/lambdas/lambda_compliance_indexer.py | Daily walks Drive folder + Sheet manifest → upserts FionnComplianceIndex |
fionn-compliance-docs | backend/lambdas/lambda_compliance_docs.py | Function URL: opp/NS ID → subsidiary cache → compliance index → optional Drive file bytes |
Key dependencies
google_client.py+ vendoredrsa==4.9for Drive/Sheets authnetsuite_client.pyfor subsidiary resolutionsecrets_helper.pyfor credential lookup
18. Sandbox Environment
A parallel sandbox stack mirrors the production pipeline so test emails, synthetic NetSuite data, and CuChulainn dry-runs never touch real customer data or production Salesforce.
Components
| Layer | Component | Purpose |
|---|---|---|
| Orchestration Lambda | fionn-sandbox-testing (lambda_sandbox_testing.py) | Trigger sandbox CuChulainn package; scan logs/tests against sandbox tables |
| Query Lambda | fionn-sandbox-query (lambda_sandbox_query.py) | Sandbox FionnEmailLogs-Sandbox thread / product resolution |
| Synthetic NetSuite | fionn-netsuite-api (lambda_netsuite_api.py) | Returns synthetic NetSuite payloads when invoked in sandbox mode |
| Outbound sender | emailsendersandbox (Apps Script) | Sandbox-scoped sender; logs to sandbox table |
| Primary store | FionnDashboard-Sandbox | Sandbox opportunity data |
| Email logs | FionnEmailLogs-Sandbox | Sandbox email mirror |
| Dashboard view | Sandbox Testing | Trigger packages, list test results + sandbox logs |
| Sandbox Lambda URLs | Bundled in dashboard/config.js | Frontend wiring for the sandbox Lambdas |
Related skill
email-lookup-sandbox— Cursor skill at.cursor/skills/email-lookup-sandbox/SKILL.mdfor checking if an email thread exists in the sandbox database during testing
19. Customer Asks (Request Tracker)
A standalone web page (dashboard/requests.html, separate from the main renewals dashboard) that surfaces every distinct customer request extracted from email threads (Phase 2: Salesforce meeting transcripts). Each ask is classified into legal / compliance / finance / document / other and routed to the appropriate ticket system. The board hides any opportunity that is not in an in-progress stage or has zero open asks.
graph LR
GMAIL["Gmail inbound"] --> WATCH["gmailwatch<br/>Apps Script"]
WATCH -->|/log-inbound| API["fionn-dashboard-api"]
API --> LOGS[("FionnEmailLogs")]
SF[("Salesforce<br/>Opportunity + Transcripts")] --> EXT["fionn-request-extractor<br/>EventBridge 30 min"]
LOGS --> EXT
EXT -->|"OpenAI classify"| REQS[("FionnRequests")]
EXT -->|doc lookup| CIDX[("FionnComplianceIndex")]
CIDX -. auto-resolves doc asks .-> REQS
EXT -->|writes rollup| DASH[("FionnDashboard<br/>OPP#id#DETAILS")]
REQS --> PAGE["dashboard/requests.html<br/>standalone page"]
DASH --> PAGE
PAGE -->|"POST /asks/create-ticket<br/>(Phase 3)"| ROUTER["fionn-ticket-router"]
ROUTER --> JIRA["Jira REST<br/>legal"]
ROUTER --> KCOMP["Kayako Compliance dept"]
ROUTER --> KFIN["Kayako Finance dept"]
SYNC["fionn-ticket-sync<br/>EventBridge 30 min<br/>(Phase 4)"] --> JIRA
SYNC --> KCOMP
SYNC --> KFIN
SYNC --> REQS
Components (Phase 1 shipped)
| Component | Source / location | Purpose |
|---|---|---|
fionn-request-extractor | backend/lambdas/lambda_request_extractor.py | EventBridge cron + ad-hoc invoke. Reads FionnEmailLogs deltas per in-progress opp, classifies asks via OpenAI, dedupes by sha1(opp + category + normalisedQuote), auto-resolves document asks against FionnComplianceIndex, writes rollup attrs (aiOpenAsksSummary, asksCategoryCounts, asksOpenCount, asksOldestOpenAt, asksAttentionScore, asksLastExtractedAt) onto each OPP#<id>#DETAILS row in FionnDashboard-prod. |
FionnRequests table | DynamoDB (us-east-1) | pk = OPP#<oppId>, sk = REQ#<ulid>. GSI1 (CATEGORY#cat#STATUS#st), GSI2 (THREAD#<tid>), GSI3 (TICKET#<sys>#<id>). Canonical store of every extracted ask. |
API routes on fionn-dashboard-api | backend/lambdas/lambda_handler.py → _route_asks() | GET /asks/board (single composite call powering the board), GET /asks?opportunityId=, PATCH /asks?opportunityId=&askId=, POST /asks/resolve, POST /asks/snooze, POST /asks/extract. |
dashboard/requests.html (+ requests.js, requests.css) | Standalone S3 page | Auth via the same Cognito flow as the main dashboard. Opportunity-centric card grid (one card per in-flight opp with at least one open ask), heat strip header, slide-in detail drawer, inbox-style keyboard shortcuts (J/K/Enter/R/S///?). |
Categorisation & ticket routing
| Category | Examples | Ticket destination |
|---|---|---|
legal | Contracts, MSAs, redlines, NDAs, DPAs, terms negotiation | Jira (Phase 3) |
compliance | SOC, ISO, infosec questionnaires, GDPR, security reviews | Kayako Compliance dept (Phase 3) |
finance | Invoicing, PO, payment terms, refund, credit, AR | Kayako Finance dept (Phase 3) |
document | Specific files (W9, COI, bank letter, SOC 2 report, etc.) | Auto-resolves against FionnComplianceIndex if indexed; otherwise Kayako Compliance ticket (Phase 3) |
other | Scheduling, support, onboarding | Kayako general (Phase 3) |
Board visibility rules (server-side, non-toggleable)
- Stage ∉ {
Closed Won,Closed Lost,Finalizing} — the board only ever shows live deals. asksOpenCount ≥ 1— opps with zero open asks fall off the board automatically.- Sorted by
asksAttentionScore=Σ (urgencyWeight × (askAgeDays + 1)), descending.
Phasing
- Phase 1 (shipped) —
FionnRequeststable, extractor (email-only), API routes, standalone page, sidebar link in renewals dashboard. - Phase 2 — ingest Salesforce meeting transcripts (object/field shape TBD with user).
- Phase 3 —
fionn-ticket-routerLambda + Jira / Kayako secrets + drawer Create Ticket buttons. - Phase 4 —
fionn-ticket-syncEventBridge cron for ticket status backfill. - Phase 5 — mirror to Salesforce custom object
Customer_Request__c(gated on explicit user approval per workspace rules).
20. Product Portfolio
Products are organized by Business Unit. Each product has an Ephor Project ID for CuChulainn integration and may have Salesforce name aliases for normalization.
| Business Unit | Products |
|---|---|
| JigTree | Tivian, BroadVision, Influitive, MessageOne, Artemis, Bonzai, ACRM, Pivotal, Aurea Platform, Stratifyd, Playbooks, Saratoga, Jigsaw Platform, Onyx, CRMagic, Engine Yard, CallStream |
| IgniteTech | DNN, NorthPlains, Jive, Tradebeam, Verdiem, Gensym, Everest, ObjectStore, Autotrol, StreetSmart, Gomembers, Infobright, TAKE, Coretrac, Nuview, AnswerHub, Smart Routines, Acorn, Computron, Prysm, SupportSoft, Aurea Social, EPM Live, Myalerts, ScaleArc, AtHand, Prologic, Knova, Pricer, NextDocs, Config, Fog Bugz, Eloquens, Sococo, Olive Software, Suuchi, School Loop |
| Skyvera | NewNet, STL, Mobilogy, Service Gateway, ResponseTek, VoltDelta, Cloudsense, Kandy, PeerApp |
| Canopy | Contently, Kayako, CloudFix |
| Aurea E-Commerce | Aurea SAS, SLI, Spiral, Quantum Retail, Finserv(AIS) |
| Ignite SMB | Kerio, GFI, Exinda |
21. Automated Contact Discovery
When Fionn's outreach goes unanswered for 30 days (or a hard bounce occurs immediately), this system automatically discovers and validates new contacts at the customer company using a role-prioritized external lookup, then restarts outreach.
Discovery Flow
graph TB
subgraph Detection [Detection — Daily Cron]
Scan[Scan FionnDashboard<br/>for stale opps]
Bounce[Hard bounce<br/>immediate trigger]
Stale[0 replies after<br/>30 days]
end
subgraph Discovery [Discovery — Per Opportunity]
Adobe[AdobeSign Delegation<br/>Lookup — Priority 0]
Apollo[Apollo People Search<br/>Role Priority Matrix 1-7]
Merge[Merge & Deduplicate<br/>vs existing SFDC contacts]
Verify[Email Verification<br/>via Apollo]
end
subgraph WriteBack [Write-Back]
SFDC[Create Contact in<br/>Salesforce + ContactRole]
DDB[Store queue in<br/>FionnContactDiscovery]
Fionn[Fionn picks up<br/>contact on next cycle]
end
subgraph Fallback [14-Day Fallback — Daily Cron]
Check[Check active<br/>discovery timers]
Advance[Advance to next<br/>contact in queue]
Escalate[Escalate to human<br/>after 3 contacts]
end
Scan --> Stale
Scan --> Bounce
Stale --> Adobe
Bounce --> Adobe
Adobe --> Apollo
Apollo --> Merge
Merge --> Verify
Verify --> SFDC
SFDC --> DDB
DDB --> Fionn
Check --> Advance
Advance --> Escalate
Role Priority Matrix
| Priority | Role | Apollo Search Terms |
|---|---|---|
| 0 | AdobeSign Delegate (internal) | N/A — delegation history lookup |
| 1 | Procurement / Purchasing | procurement, purchasing, sourcing, vendor management |
| 2 | Finance / Accounts Payable | finance manager, accounts payable, controller, CFO |
| 3 | IT / License Administration | IT manager, license administrator, IT director |
| 4 | Operations / Administration | operations manager, office manager, business operations |
| 5 | C-Suite / Executive | CEO, COO, CTO, founder, managing director |
| 6 | Department Head | director, head of, VP |
| 7 | Original Buyer / Prior Contact | Re-verify email only |
Lambda Functions
| Function | Handler | Trigger |
|---|---|---|
fionn-contact-discovery | lambda_contact_discovery.lambda_handler | Function URL — HTTP routes |
fionn-contact-discovery-detect | lambda_contact_discovery.scheduled_detect_handler | EventBridge daily cron |
fionn-contact-discovery-advance | lambda_contact_discovery.scheduled_advance_handler | EventBridge daily cron |
HTTP API Routes
| Method | Path | Description |
|---|---|---|
| POST | /discover | Run discovery for a single opportunity |
| POST | /detect | Scan all opps for 30-day non-response or bounce |
| POST | /advance | Advance 14-day fallback for a single opportunity |
| GET | /status | Get discovery queue status |
| GET | /escalation-report | Structured escalation report for human takeover |
DynamoDB Table: FionnContactDiscovery
Partition key: pk (OPP#<opportunityId>), Sort key: sk (DISCOVERY). Stores the discovery queue, current contact index, status (active/exhausted/resolved), and source summary for each opportunity.
External Integrations
- Apollo.io — People Search API for contact discovery + built-in email verification. Secrets:
fionn/apollo - Adobe Sign — Delegation history lookup for high-signal prior signers. Reuses existing
fionn/adobesecrets - Salesforce (NSS) — Contact + OpportunityContactRole write-back with
Contact_Source__ctag
Escalation
When all 3 discovery contacts are exhausted (3 × 14-day cycles = 42 days), the system generates a structured escalation report for Clarisa/Jay containing: company name, renewal date, every contact tried (name, title, source, dates, verification status), and a recommendation.