CONFIDENTIAL — STRATEGIC ADVISOR REVIEW

PCMA Brain

Comprehensive Technical Audit Document
Module 1 Conversion Strategy V5 Elite Partner Portal 16 Tools Live 5 Conversion Paths 4 ICPs 7-Tier Pipeline Engine Twilio WhatsApp

Generated: 06 April 2026 at 09:30 UTC

Sender: Zoya Abid <resources@thepcma.uk>

Offer URL: https://thepcma.uk/elitepartners  |  Partnership: £897/month

Live Document — This audit is generated fresh on each download. Sections driven by live code: ICP tables, tool list (16 tools), path definitions (5 paths), swing constants (STALL_DAYS=7, FAST_TRACK_TOOLS=3). Narrative sections (form fields, GPT prompts) are maintained in app/audit_generator.py.

Table of Contents

  1. 1. Architecture Overview
  2. 2. Complete Route Map
  3. 3. Portal Brain Logic
  4. 4. All 16 Tools — Individual Audit
  5. 5. Conversion Events & Sequences
  6. 6. Swing Mechanics
  7. 7. Dashboard & Admin
  8. 8. Known Limitations & Gaps
  9. 9. Pipeline Engine — 7-Tier Autonomous Conversion
  10. 10. Twilio WhatsApp Integration
  11. 11. Safety, Scoring & Activity Log
  12. 12. Scheduler & Background Jobs

1. Architecture Overview

Tech Stack

LayerTechnologyDetail
Web FrameworkFastAPI (Python 3.11)Async HTTP + Jinja2 templating
ORMSQLAlchemy 2.xSync sessions via get_db() dependency
DatabasePostgreSQLAccessed via DATABASE_URL env var (Replit managed)
AI ModelOpenAI GPT-4.1-miniAll reports & emails — key: OPENAI_API_KEY
CRM IntegrationGoHighLevel API v2Contact sync — keys: GHL_API_KEY, GHL_LOCATION_ID
WhatsAppTwilio APIWhatsApp Business messaging — keys: TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_WHATSAPP_NUMBER
SchedulingAPScheduler (BackgroundScheduler)Pipeline tick (1h), backfill (6h), swing scanner (6h), legacy maintenance (6h)
Static FilesFastAPI StaticFilesMounted at /static
TemplatesJinja2Directory: templates/
HostingReplit → Custom DomainAuto-run via python run.py; portal at app.thepcma.uk
Session AuthCookie-based (SESSION_SECRET)Admin dashboard only

Python Files

FilePurpose
run.pyEntrypoint — imports FastAPI app and starts uvicorn
app/main.pyFastAPI app factory — mounts routers, static files, CORS, startup events
app/database.pySQLAlchemy engine + get_db() session dependency + Base
app/models.pyAll SQLAlchemy ORM models (20+ tables)
app/config.pyEnvironment variable loading, constants (AUTO_SEND_MODE, etc.)
app/portal_brain.pyAll 16 tool engines, ICP detection, CTA selection, GPT prompts, swing functions
app/portal_swing_scanner.pyAPScheduler job — checks every 6 h for swing up/down on all active portal leads
app/pipeline_engine.py7-tier autonomous pipeline: queuing, tier advancement, multi-channel delivery (email+WhatsApp), conversion detection
app/pipeline_templates.pyICP-specific email/SMS templates for all 7 tiers, TIER_WAIT_DAYS, ICP_TOOL_MAP
app/twilio_whatsapp.pyTwilio WhatsApp send module — phone normalisation, message delivery
app/short_links.pyShort link system — generates human-readable codes (/portal/go/strategy-wasim), click tracking
app/safety.pyRate limiting — 48h cooldown, daily caps, opt-out checks, message logging
app/scoring.pyContact scoring engine — profile + engagement points → Bronze/Silver/Gold/Platinum tiers
app/activity_log.pyCentralised event logging — all engines write to activity_log table
app/scheduler.pyAPScheduler — pipeline tick (1h), backfill (6h), portal swing (6h), legacy maintenance (6h)
app/nurture_engine.py8-step nurture sequence engine — auto-enrollment, step advancement, multi-channel delivery
app/nurture_content.py71-row nurture content library — ICP-segmented templates for email/SMS/WhatsApp
app/ascension_engine.pyAscension sequence — post-conversion Elite Partner engagement
app/ascension_content.pyAscension content seeds — 9-row config
app/path_e_engine.pyPath E dormant nurture — 4-phase reactivation (nudge→drip→social proof→quarterly)
app/wave_engine.pyBulk marketing waves — batch scheduling, delivery rate tracking
app/wave_config.pyWave config — 14 rows: batch sizes, thresholds, auto-scaling rules
app/ai.pyLLM interface — GPT-4.1-mini content generation for emails and reports
app/ghl.pyGoHighLevel API layer — contact CRUD, email sends, tag management
app/audit_generator.pyTHIS FILE — generates the live technical audit document at request time
app/routers/portal.pyAll public portal routes: registration, dashboard, 16 tool endpoints, one-click entry, offer doc, VSL, webinar, apply
app/routers/dashboard.pyAdmin dashboard routes: main view, stats API, portal registrations, portal metrics, audit download
app/routers/webhook.pyWebhook receiver — GHL events, pipeline intake, Twilio status/inbound callbacks
app/routers/contacts.pyInternal CRM contact CRUD, tagging, scoring
app/routers/messages.pyMessage send/receive endpoints (email, SMS, WhatsApp)
app/routers/nurture.pyNurture sequence management endpoints
app/routers/ascension.pyAscension sequence — signal detection, score-triggered emails
app/routers/sync.pyGHL sync triggers and monitoring
app/routers/waves.pyWave campaign configuration and approval
app/routers/ops.pyOperational tools, system health, maintenance
app/routers/invoices.pyInvoice CRUD, payment recording, PDF export
app/routers/test_harness.pyE2E simulation and test harness
app/routers/journey_pdf.pyContact journey PDF report generator

HTML Template Files → Routes

TemplateRouteNotes
templates/dashboard.htmlGET /Admin dashboard main view
templates/portal_metrics.htmlGET /portal-metricsAdmin portal KPI/funnel metrics
templates/portal/register.htmlGET /portal/registerPublic registration form
templates/portal/enter_confirm.htmlGET /portal/enter/{{token}}Pipeline one-click entry — confirmation page (anti-bot: GET→POST)
templates/portal/dashboard.htmlGET /portal/dashboardLead's personalised portal dashboard
templates/portal/tools/[slug].htmlGET /portal/tools/{{slug}}Individual tool form pages (×16)
templates/portal/tool_result.htmlGET /portal/tools/{{slug}}/result/{{id}}Tool report + CTA panel
templates/portal/offer_doc.htmlGET /portal/offer-docGPT-generated personalised offer document
templates/portal/vsl.htmlGET /portal/vslICP-personalised VSL page (6 variants)
templates/portal/webinar.htmlGET /portal/webinarEvergreen webinar embed page
templates/portal/apply.htmlGET /portal/applyStrategy call booking / application page
templates/portal/live_webinar.htmlGET /portal/live-webinarMonthly live webinar registration page
templates/portal/stage2_panel.htmlPartialStage 2 dashboard panel
templates/portal/stage3_panel.htmlPartialStage 3 dashboard panel
templates/portal/stage4_panel.htmlPartialStage 4 dashboard panel (offer viewed)
templates/portal/contact.htmlGET /portal/contactContact/enquiry form

Database Schema — Portal Tables

TableKey ColumnsPurpose
portal_leadsid, token (unique 64-char), name, email (unique), phone, icp_type, source, path (A–E), path_state, stage (1–4), contact_id (FK), ghl_contact_id, offer_viewed, offer_view_count, application_clicked, vsl_shown, webinar_registered, live_webinar_registered, offer_doc_generated, last_active_at, swing_last_checked_atPrimary portal lead record — one per registrant
tool_completionsid, portal_lead_id (FK), tool_id (T01–T16), tool_name, inputs (JSON), report_html, report_summary, recommended_strategy, deal_viable, profit_margin_pct, cta_primary_label/url, cta_alt_label/url, email_sent, completed_atOne row per tool submission per lead
portal_eventsid, portal_lead_id (FK), event_type (register/tool_start/tool_complete/cta_click/offer_view), tool_id, data (JSON), created_atAppend-only event log for every lead action

Database Schema — CRM Tables

TableKey ColumnsPurpose
contactsid, name, email, phone, icp_type, score, tier, status, ghl_contact_id, portal_registered, offer_viewed, last_message_atMain CRM contact record synced from GHL
messagesid, contact_id (FK), channel, subject, body, sent_at, opened, replied, pending_approvalAll messages sent/received per contact
sequencesid, contact_id (FK, unique), current_wave, current_angle, next_send_dateWave/angle position per contact
daily_statsid, date, sms_sent, emails_sent, whatsapp_sent, replies_receivedDaily send volume counters
human_queueid, contact_id (FK), incoming_message, suggested_reply, objection_type, resolvedEscalated conversations
wave_approvalsid, wave_number, status, total_messages, approved_by, approved_at, sent_atWave campaign approval workflow
nurture_sequencesid, contact_id (FK), source, icp, status, current_step, total_steps, next_send_at8-step nurture journey
ascension_sequencesid, contact_id (FK), trigger_score, status, current_step (max 3), step_1/2/3_sent_atHigh-intent ascension journey
activity_logid, event_type, engine, contact_id, detail, metadata (JSON), created_at (indexed)System-wide activity stream
invoicesid, invoice_number (unique), contact_id, pod, status, subtotal, vat_amount, total_amount, amount_paidInvoice CRUD
app_settingsid, key (unique), valueKey-value runtime config (auto_send_mode, webinar settings, etc.)

Database Schema — Pipeline Columns (on contacts table)

Pipeline state is stored directly on the contacts table (not a separate table):

ColumnTypePurpose
pipeline_tierInteger (1–7), nullable, indexedCurrent tier in the 7-tier journey
pipeline_statusString(30), nullable, indexedStatus: queued, sent, registered, converted, paused, send_failed
pipeline_entered_atDateTime, nullableWhen contact was enrolled in pipeline
pipeline_last_tier_changeDateTime, nullableLast tier advancement timestamp
pipeline_icpString(50), nullableAssigned ICP for pipeline template selection
pipeline_assigned_toolString(10), nullableTool ID assigned for Tier 1
pipeline_sourceString(50), nullableSource tracking (e.g., ghl_webhook)
pipeline_campaign_sourceString(100), nullableCampaign source tracking
pipeline_contact_tokenString(64), unique, indexed32-char urlsafe token for one-click URLs

Database Schema — Short Links Table

ColumnTypePurpose
idInteger PKAuto-increment
codeString(80), unique, indexedHuman-readable short code (e.g., strategy-wasim)
destination_urlTextFull target URL to redirect to
contact_idInteger FK → contactsContact this link was generated for
created_atDateTimeLink creation timestamp
clicked_atDateTime, nullableTimestamp of first click (null = never clicked)

2. Complete Route Map

Public Portal Routes (portal.py)

MethodPathAuthTemplate / ResponseDescription
GET/portal/registerNoportal/register.htmlShows registration form with profile/source fields
POST/portal/registerNoRedirect → /portal/dashboard?token=…Creates PortalLead, assigns ICP+path, syncs to GHL, fires welcome email
GET/portal/enter/{{token}}Pipeline tokenportal/enter_confirm.html OR auto-redirectOne-click pipeline entry — already-registered leads redirect to tier-correct destination; new leads see bot-proof confirmation page
POST/portal/enter/{{token}}Pipeline tokenRedirect → tool / VSL / webinar / apply / dashboardPerforms actual registration and redirects based on next or tool param (T1→tool, T3→VSL, T4→webinar, T5→apply)
GET/portal/go/{{code}}Short link codeRedirect 302 → destination URLShort link redirect — records first click timestamp in clicked_at
GET/portal/dashboardToken (query)portal/dashboard.htmlPersonalised portal hub — tool cards, stage panels, path badge, progress
GET/portal/tools/{{slug}}Token (query)portal/tools/{{slug}}.htmlTool input form for one of the current tools
POST/portal/tools/{{slug}}/submitToken (query)Redirect → result pageProcesses tool, saves ToolCompletion, fires email, logs event, updates stage/path
GET/portal/tools/{{slug}}/result/{{id}}Token (query)portal/tool_result.htmlShows GPT report, structured calc data, 3-CTA panel
GET/portal/offer-docToken (query)portal/offer_doc.htmlGPT-generated personalised offer document; sets offer_viewed=True
GET/portal/vslToken (query)portal/vsl.htmlICP-personalised VSL page; sets vsl_shown field
GET/portal/webinarToken (query)portal/webinar.htmlEvergreen webinar embed; sets webinar_registered=True
GET/portal/applyToken (query)portal/apply.htmlStrategy call / application page
GET/portal/live-webinarToken (query)portal/live_webinar.htmlMonthly live webinar registration page
POST/portal/live-webinar/registerToken (query)JSON {success}Sets live_webinar_registered=True, fires GHL webinar confirmation email
POST/portal/eventToken (query)JSON {ok}Records a PortalEvent, updates last_active_at
GET/portal/contactToken (query)portal/contact.htmlContact/enquiry form

Admin Dashboard Routes (dashboard.py)

MethodPathAuthTemplate / ResponseDescription
GET/Sessiondashboard.htmlAdmin dashboard main view with CRM stats
GET/api/statsSessionJSONLive stats JSON for dashboard polling
GET/portal-registrationsSessionHTML fragmentList of portal leads with stage/path/tools
GET/portal-metricsSessionportal_metrics.html6 KPI cards, 7-step funnel, path distribution, ICP breakdown, top tools chart, activity feed
GET/portal-audit/downloadSessiontext/html (download)Downloads THIS dynamically generated technical audit document
POST/settings/auto-sendSessionJSONToggle auto_send_mode on/off
POST/sync-ghlSessionJSONTrigger manual GHL contact sync
GET/POST/wave/*SessionVariousWave preview, approval, and send
GET/POST/api/portal/live-webinarSessionJSONSave live webinar settings to AppSettings
GET/api/pipeline-statsSessionJSONPipeline funnel KPIs: queued/sent/registered/converted counts, tier breakdown, ICP stats
POST/api/pipeline/backfillSessionJSONTrigger manual pipeline backfill of existing GHL contacts

Webhook Routes (webhook.py)

MethodPathAuthDescription
POST/webhook/ghlNoneGHL general events — InboundMessage, ContactUpdated, OfferViewed, DiscoveryCallClicked, bounce
POST/webhook/ghl/new-contactGHL_WEBHOOK_SECRETPipeline intake — creates/updates contact, enrolls in pipeline engine
POST/webhook/new-leadNoneNew lead processing — sets nurture eligibility, detects ICP/Source from tags
POST/webhook/bridge-to-portalNoneMarks contact as portal_registered, logs if during active nurture
POST/webhook/twilio/statusNoneTwilio delivery status callbacks (sent, delivered, failed, undelivered)
POST/webhook/twilio/inboundNoneTwilio inbound WhatsApp messages — logs activity, marks contact replied

3. Portal Brain Logic

ICP Detection

ICP is assigned at registration from a single dropdown (profile field) and is immutable thereafter. There are currently 4 ICP types.

Form ValueICP CodeICP LabelCore PainPCMA Promise
newAsp-DevAspiring DeveloperI don't know what I don't know about property development.We will guide you through your first project with a full professional team behind you.
landlordSc-LLScaling LandlordMy portfolio is working hard but not growing fast enough.Your existing properties are worth more than you think — if you convert instead of refurbish.
busyTP-ProTime-Poor ProfessionalI have the capital but not the time to manage a development.We do everything. You approve the decisions. The project runs without you.
experiencedAc-ProjActive ProjectI need a professional team I can trust with my capital.We become your outsourced development department.
PROFILE_TO_ICP = { "new": "Asp-Dev", "landlord": "Sc-LL", "busy": "TP-Pro", "experienced": "Ac-Proj" }

First Tool Recommendation (TOOL_FOR_ICP)

On registration the Brain selects the first recommended tool based solely on ICP:

ICP CodeICP LabelFirst Tool IDTool NameTool Tagline
Asp-DevAspiring DeveloperT02Strategy SelectorFind Your Best Development Strategy
Sc-LLScaling LandlordT01RRA Compliance CheckerKnow Your Renters' Rights Act Obligations
TP-ProTime-Poor ProfessionalT05Deal AnalyserGet Your Deal Feasibility Report
Ac-ProjActive ProjectT05Deal AnalyserGet Your Deal Feasibility Report
TOOL_FOR_ICP = { "Asp-Dev": "T02", "Sc-LL": "T01", "TP-Pro": "T05", "Ac-Proj": "T05" }

CTA Selection Logic (1+1+1)

After every tool result, three CTAs are shown: Primary, Alternative, and Soft Exit. The function select_cta(icp, tools_done, source) selects them:

Rule 1 (highest priority): tools_done >= 2 Primary: "Read the Partnership Overview" → OFFER_URL Alternative: "Book a Strategy Preview" → /portal/contact Soft Exit: "Save my results & explore" → /portal/dashboard Rule 2: last_tool == "T05" (Deal Analyser) Primary: "Read the Partnership Overview" → OFFER_URL Alternative: "Identify Your Best Strategy" → /portal/tools/strategy-selector Soft Exit: "Save my results & explore" → /portal/dashboard Rule 3: last_tool == "T02" AND icp == "Asp-Dev" Primary: "Analyse Your First Deal" → /portal/tools/deal-analyser Alternative: "Read the Partnership Overview" → OFFER_URL Soft Exit: "Save my results & explore" → /portal/dashboard Rule 3b: last_tool == "T02" (other ICPs) Primary: "Read the Partnership Overview" → OFFER_URL Alternative: "Analyse a Deal" → /portal/tools/deal-analyser Soft Exit: "Save my results & explore" → /portal/dashboard Default (no tools done): Primary: "Read the Partnership Overview" → OFFER_URL Alternative: "Start with the Strategy Selector" Soft Exit: "Explore your portal"

Lead State Tracking

FieldTypeTriggers Change
stageInteger 1–4Stage 1: registration. Stage 2: 1 tool. Stage 3: 2+ tools. Stage 4: offer viewed or 4+ tools.
pathA–ESet on registration by assign_path(); updated by swing scanner every 6 h. 5 paths defined.
offer_viewedBooleanSet when lead visits /portal/offer-doc (triggers Stage 4 and Swing Up to Path A).
vsl_shownString (icp key)Set when lead visits /portal/vsl/{{icp_key}}.
webinar_registeredBooleanSet when lead visits /portal/evergreen-webinar.
live_webinar_registeredBooleanSet when lead POSTs to /portal/live-webinar/register.
last_active_atDateTimeUpdated on every portal event (tool submit, CTA click, page visit).
swing_last_checked_atDateTimeUpdated by swing scanner after each check run.
email_sent (ToolCompletion)BooleanSet after tool completion follow-up email is dispatched (fires once per completion).

4. All 16 Tools — Individual Audit

There are currently 16 tools in the portal. This section is generated from the live TOOLS dictionary and the narrative data in app/audit_generator.py.

T01 — RRA Compliance Checker

GET/POST /portal/tools/compliance-checker 4 min Planner

Know Your Renters' Rights Act Obligations
Answer 8 questions about your rental property and get a personalised compliance action plan — traffic-light status, estimated costs, and a clear timeline of what to do by when.

Form Fields

FieldTypeOptions / Notes
Property typeSelectHMO | Single let | Flat block | Mixed use | Holiday let | Student let
How many tenants/rooms?Select1–2 | 3–4 | 5–6 | 7+
When was it built?SelectPre-1930 | 1930–1960 | 1960–1990 | 1990–2000 | Post-2000
Current EPC ratingSelectA | B | C | D | E | F | G | Unknown
Is it currently let?SelectYes | No | Partially
Deposit scheme registered?SelectYes | No | Not sure
Gas Safety cert current?SelectYes | No | Exempt
EICR in last 5 years?SelectYes | No | Not sure

Processing Logic

Traffic-light scoring engine — each answer adds risk points. score≥70→RED (HIGH RISK), 40–69→AMBER, <40→GREEN. Hardcoded 10-area compliance check covering Gas Safety, EICR, EPC E, Smoke/CO alarms, Deposit Protection, Tenancy Structure, PRS Database, Ombudsman, EPC C by 2030, Decent Homes Standard by 2035. Cross-pollination: score≥70→T03 | score 40–69→T08 | score<40→T02.

GPT Report Sections

  1. 1. Your Compliance Status
  2. 2. Your Immediate Legal Requirements
  3. 3. What the Renters' Rights Act Changes for You
  4. 4. EPC Obligations
  5. 5. Your 30-Day Action Plan
  6. 6. What You Need to Confirm Next
  7. 7. Your Next Steps

T02 — Strategy Selector

GET/POST /portal/tools/strategy-selector 3 min All four roles

Find Your Best Development Strategy
Answer 5 quick questions and get a personalised strategy recommendation backed by your specific goals, budget, and situation.

Form Fields

FieldTypeOptions / Notes
Available capitalSelectUnder £30k | £30k–£75k | £75k–£150k | £150k–£300k | £300k+
Development experienceSelectBeginner | Landlord | Some experience (1–3) | Experienced (4+) | Professional
Primary goalSelectGenerate capital | Build cashflow | Replace income | Build a business | Optimise portfolio
Time availabilitySelectUnder 5 hrs/week | 5–15 hrs | 15–30 hrs | Full-time
Risk appetiteSelectConservative | Moderate | Aggressive | Analytical

Processing Logic

6-strategy scoring matrix with 5 weighted dimensions: Capital(30%), Experience(25%), Goal(20%), Time(15%), Risk(10%). Strategies: C2R, HMO, Title Split, House→Flats, Heritage, New Build. Each strategy scored 0–100 per dimension from hardcoded matrices. Top 3 strategies shown. Cross-pollination: all strategies→T05 (Deal Analyser).

GPT Report Sections

  1. 1. YOUR STRATEGY PROFILE
  2. 2. PRIMARY RECOMMENDATION: [Strategy]
  3. 3. YOUR FIRST PROJECT SCENARIO
  4. 4. KEY CHALLENGE & HOW IT'S MANAGED
  5. 5. SECONDARY OPTION: [Strategy]
  6. 6. YOUR NEXT STEP

T03 — EPC Upgrade ROI Calculator

GET/POST /portal/tools/epc-calculator 3 min Planner

See Your Energy Savings Breakdown
Enter 6 details about your property and get a personalised EPC upgrade plan — specific measures, estimated costs, EPC band improvements, and the financial ROI.

Form Fields

FieldTypeOptions / Notes
Property typeSelectSemi-detached | Terraced | Detached | Flat (PB) | Flat (converted) | Bungalow | HMO | Commercial | Mixed use
Built dateSelectPre-1930 | 1930–1960 | 1960–1990 | Post-1990 | Post-2000
Current EPC ratingSelectA–G
Target EPC ratingSelectA–C
Monthly rent (£)Number
Property sizeSelectSmall (<60sqm) | Medium (60–90) | Large (90–150) | Very large (>150)

Processing Logic

36-measure EPC database with band-conditional eligibility filter. Measures sorted by points_gain DESC (greedy selection) until target band reached. total_cost = sum of selected measure cost_mid values. ROI = annual_savings / total_cost. Cross-pollination: EPC≤D + cost>£15k→T01 | commercial/mixed→T15 | default→T12.

GPT Report Sections

  1. 1. Your EPC Upgrade Summary
  2. 2. The Measures You Need
  3. 3. The Financial Case
  4. 4. The Compliance Timeline
  5. 5. What Your Tenants Will See
  6. 6. Your Next Steps

T04 — Development Cost Estimator

GET/POST /portal/tools/cost-estimator 3 min Quantity Surveyor

Get Your Project Cost Breakdown
Enter 7 details about your project and get a comprehensive cost breakdown across 6 categories — acquisition, construction, professional fees, statutory costs, finance, and contingency.

Form Fields

FieldTypeOptions / Notes
Project typeSelectLight refurb | Heavy refurb | HMO | House to flats | C2R | Barn | Listed | New build (single) | New build (multi) | Loft/Extension
Gross floor area (sqm)Number
Number of unitsNumber1–20
Location typeSelectPrime London | Central London | South East | Midlands/North/Wales | Scotland/NI
Specification levelSelectBudget | Mid-range | High spec | Luxury
Purchase price (£)Number
Finance typeSelectCash | Bridging | Development finance | JV/investor

Processing Logic

6-category cost breakdown: Acquisition, Construction (build_cost × sqm × location_mult × spec_mult), Professional Fees (12%), Statutory Costs, Finance, Contingency (listed/barn=15%, c2r/new_build=12%, others=10%). Location multipliers: prime_london=1.8×, central=1.5×, south_east=1.2×, midlands=1.0×, scotland=0.9×. Spec multipliers: budget=0.85×, mid=1.0×, high=1.15×, luxury=1.35×. Cross-pollination: cost>£1m or new_build→T10 | htf/c2r→T06 | default→T05.

GPT Report Sections

  1. 1. Your Cost Summary
  2. 2. The 6-Category Breakdown
  3. 3. Comparing to Market Benchmarks
  4. 4. Where Costs Most Often Overrun
  5. 5. How to Reduce Your Costs
  6. 6. The Finance Effect
  7. 7. Your Next Steps

T05 — Deal Analyser

GET/POST /portal/tools/deal-analyser 2 min Quantity Surveyor

Get Your Deal Feasibility Report
Enter your deal numbers and get an instant profit/loss analysis, ROI assessment, and viability verdict — the same analysis our QS runs on every deal.

Form Fields

FieldTypeOptions / Notes
Purchase price (£)Number
Total build cost (£)Number
Professional fees (£)Number0 if unknown
Finance costs (£)Number0 if unknown
Expected GDV (£)Number
Number of unitsNumberDefault 1
Strategy typeSelectHMO | House to flats | C2R | New build | Refurb | Title split | Other

Processing Logic

profit = gdv - total_costs. margin_pct = profit/gdv×100. roi_pct = profit/total_costs×100. Verdict: margin≥20%→STRONG, 15–20%→VIABLE, 10–15%→MARGINAL, 5–10%→WEAK, <5%→NOT VIABLE. Stores: deal_viable = margin≥15, profit_margin_pct = margin_pct. Cross-pollination: gdv>£500k→T06 | margin<15%→T04 | default→T02.

GPT Report Sections

  1. 1. Deal Verdict
  2. 2. Numbers Breakdown
  3. 3. Profit Margin in Context
  4. 4. Biggest Risk
  5. 5. How to Improve Margin
  6. 6. What a Professional Team Would Add
  7. 7. Next Steps

T06 — Unit Mix Optimiser

GET/POST /portal/tools/unit-mix-optimiser 3 min Architect

See Your Best Unit Mix
Enter your building's size and location and see the top 3 unit mix options ranked by GDV — using NDSS space standards so you know every option is buildable.

Form Fields

FieldTypeOptions / Notes
Gross floor area (sqm)Number
Number of floorsSelect1–6 | 7+
LocationSelectPrime city | City centre | Town centre | Suburban (good) | Suburban (avg) | Rural town
GoalSelectMaximise sale value | Maximise rental income | Mix of both
Build typeSelectHouse to flats | C2R | New build | Barn conversion

Processing Logic

NDSS minimum sizes enforced (studio=37sqm, 1bed_2p=50sqm, 2bed_4p=70sqm, 3bed_5p=86sqm). NLA = gross_area × 0.85. Regional GDV values (£/sqm): prime_city=6500, city=4500, town=3200, suburban_good=3800, suburban_avg=3000, rural=2500. 3 unit mix candidates generated, ranked by GDV. Cross-pollination: total_cost>£500k→T10 | default→T05.

GPT Report Sections

  1. 1. Your Optimal Unit Mix
  2. 2. Why This Mix Maximises Value
  3. 3. Three Options Side-by-Side
  4. 4. NDSS Standards Explained
  5. 5. What the Market Tells Us
  6. 6. Your Next Steps

T07 — Site Scanner

GET/POST /portal/tools/site-scanner 4 min All four roles

Get Your Site Development Potential
Enter a postcode and answer 7 questions about any property. Get a development potential report covering all applicable strategies, planning routes, and value uplift estimates.

Form Fields

FieldTypeOptions / Notes
PostcodeTextUK postcode for region detection
Property typeSelectHouse (detached) | House (semi) | House (terraced) | Bungalow | Flat | Commercial | Mixed use | Agricultural
Building ageSelectPre-1930 | 1930–1960 | 1960–1990 | Post-1990
Floor area (sqm)Number
Number of floorsSelect1 | 2 | 3 | 4+
Planning constraintsMulti-selectConservation area | Listed | Flood zone | Article 4 | Green belt | None
Owner goalSelectMaximise profit | Create income | Planning uplift | Explore options

Processing Logic

8 development strategies assessed (HMO, House→Flats, C2R, New build, Loft, Extension, Title split, Barn). Each scored 0–100 from property type, floor area, constraint penalties, age bonuses. Conservation:-20, listed:-40, flood:-15, article_4 HMO:-50. eligible = strategies with score≥40, sorted DESC. Cross-pollination: top>70 + old→T14 | top=c2r→T15 | default→T04.

GPT Report Sections

  1. 1. Your Site's Development Potential
  2. 2. Your Top Strategy
  3. 3. All Eligible Strategies
  4. 4. Planning Considerations
  5. 5. Value Uplift Estimates
  6. 6. What You Need to Confirm Next
  7. 7. Your Next Steps

T08 — Portfolio Health Check

GET/POST /portal/tools/portfolio-health-check 6 min Planner

Get Your Portfolio Optimisation Plan
Enter details for up to 5 properties. Get a performance ranking by yield and equity efficiency, plus a strategic recommendation for each property — hold, improve, convert, or sell.

Form Fields

FieldTypeOptions / Notes
Property name/labelTextPer property (up to 5)
Property typeSelectHMO | Commercial | Detached | Semi | Terraced | Flat (PB) | Flat (converted) | Mixed
Current value (£)NumberPer property
Outstanding mortgage (£)NumberPer property
Monthly rent (£)NumberPer property
Annual costs (£)NumberAuto 25% of rent if blank
EPC ratingSelectA–G | Per property
Building ageSelectPre-1930 | 1930–1960 | Post-1960

Processing Logic

Per property: gross_yield=rent/value, net_yield=net_income/value, equity_eff=net_income/equity. Compliance risk: EPC A/B=0, C=1, D=2, E=3, F/G=5 + age +1. Conversion potential 0–10: commercial=8, detached=7, semi=6, terraced=5, HMO=2, flat_pb=1. Recommendation: yield≥7%+risk≤2→HOLD | conv≥6+equity>50k→CONVERT | risk≥4→IMPROVE | yield<3%→SELL. Cross-pollination: worst=CONVERT→T07 | IMPROVE/EPC-F/G→T03 | SELL→T12 | default→T01.

GPT Report Sections

  1. 1. Your Portfolio Snapshot
  2. 2. Your Best Performer
  3. 3. Your Weakest Performer
  4. 4. Strategic Recommendations
  5. 5. Portfolio-Level Risks
  6. 6. The Opportunity in Your Portfolio
  7. 7. Your Next Steps

T09 — Project Timeline Estimator

GET/POST /portal/tools/timeline-estimator 3 min Project Manager

See Your Project Timeline
Answer 6 questions about your project. Get a phase-by-phase timeline with best/likely/worst-case scenarios and the financial cost of each month of delay.

Form Fields

FieldTypeOptions / Notes
Project typeSelectLight refurb | Heavy refurb | HMO | House to flats | C2R | Barn | Listed | New build (single/multi) | Loft/Extension
Current statusSelectJust an idea | Owned no design | Design done | Planning submitted | Planning approved | Construction started
Planning neededSelectPermitted development | Prior approval | Full planning | None
ComplicationsMulti-selectAsbestos | Party wall | Listed | Contamination | Structural
Finance typeSelectCash | Bridging (£4,500/month) | Dev finance (£6,000/month)

Processing Logic

7-phase timeline engine: Pre-Design, Design, Planning, BC&Tender, Construction, Completion, Sale/Let. Base months per project type. PD→planning-4m, prior_approval→planning-2m. Complication adds: asbestos+2m, party_wall+1m, listed+4m, contamination+3m, structural+2m. Per phase: best=base×0.8, likely=base+extras, worst=base×1.35+extras. Overrun cost = (worst-likely) × monthly_finance. Cross-pollination: planning_months>6→T16 | construction>8m→T14 | default→T04.

GPT Report Sections

  1. 1. Your Programme Summary
  2. 2. Phase-by-Phase Breakdown
  3. 3. The Cost of Delay
  4. 4. Your Critical Path
  5. 5. How to Compress Your Timeline
  6. 6. Your Next Steps

T10 — Funding Readiness Scorecard

GET/POST /portal/tools/funding-readiness 4 min Planner

Check Your Funding Readiness
Answer 8 questions that mirror what development finance lenders assess. Get a readiness score across 5 categories and specific actions to close each gap.

Form Fields

FieldTypeOptions / Notes
Development experienceSelectNone | 1 project | 2–3 | 4–5 | 6+
Qualifications heldMulti-selectFormal qualification | Construction exp | Investment exp | Business exp | Finance exp
Expected profit marginSelectNot calculated | Under 10% | 10–15% | 15–20% | 20%+
Deal sizeSelectUnder £500k | £500k–£1m | £1m–£2m | £2m+
Professional team in placeMulti-selectArchitect | QS | PM | Solicitor | Planning Consultant
Exit strategySelectUncertain | Refinance | Let | Sell (open) | Sell (agreed)
Equity contributionSelectUnder 20% | 20–25% | 25–35% | 35%+
Credit historySelectClean | Minor issues | CCJ | Previous bankruptcy

Processing Logic

5 categories: Experience(25pts), Deal Quality(25pts), Team(20pts), Exit(15pts), Finances(15pts). Verdict: 80+→READY, 60–79→NEARLY READY, 40–59→WORK TO DO, <40→NOT YET. Biggest gap (largest pts shortfall) drives cross-pollination: Deal Quality→T05 | Team→T02 | Exit→T07 | score>80→T05 | default→T04.

GPT Report Sections

  1. 1. Your Readiness Score
  2. 2. What Lenders See
  3. 3. Your Strongest Category
  4. 4. Your Biggest Gap
  5. 5. The Action Plan
  6. 6. When to Approach a Lender
  7. 7. Your Next Steps

T11 — Lease Extension Calculator

GET/POST /portal/tools/lease-extension 3 min Planner

See Your Lease Extension Savings
Enter 6 details about your leasehold property. Get an estimated extension premium under current law and the incoming 2024 reforms — and see what acting now could save you.

Form Fields

FieldTypeOptions / Notes
Years remaining on leaseNumber1–999
Ground rent (£/year)Number
Ground rent escalationSelectFixed | Doubles every 10 years | Doubles every 25 years
Property typeSelectDetached | Semi | Terraced | Flat (PB) | Flat (converted)
Current property value (£)Number
GoalSelectExtend lease | Enfranchise | Understand options

Processing Logic

1993 Act: premium = term_value + reversion_value + marriage_value (if <80 years). Deferment rate = 5%. Relativity table: 100yr=97%, 80yr=88%, 60yr=68%, 40yr=47%, 20yr=28%. 2024 Reform: marriage value abolished → premium = term + reversion only. new_lease = lease_years + 90. value_uplift = after_ext - current. Cross-pollination: premium>30k + house→T13 | premium>30k (other)→T07 | default→T08.

GPT Report Sections

  1. 1. Your Lease Extension Summary
  2. 2. How the Premium Is Calculated
  3. 3. The 2024 Reform Opportunity
  4. 4. The Financial Case for Acting Now
  5. 5. The Conversion Alternative
  6. 6. Your Next Steps

T12 — Refurb-or-Convert Decision Engine

GET/POST /portal/tools/refurb-or-convert 4 min Architect

Should You Renovate or Convert?
Enter 8 details about a property. Get a side-by-side comparison of renovation vs conversion — cost, timeline, end value, and profit for each option.

Form Fields

FieldTypeOptions / Notes
Property typeSelectTerraced | Semi | Detached | Bungalow | Commercial | Mixed use | Flat (converted)
Floor area (sqm)Number
Number of floorsSelect1 | 2 | 3 | 4+
Current conditionSelectExcellent | Good | Fair | Poor | Very poor
Current value (£)Number
GoalSelectMaximise profit | Create income | Minimise hassle
ConstraintsMulti-selectListed | Leasehold | Conservation | Flood zone
FinanceSelectCash | Bridging | Dev finance

Processing Logic

Renovation: condition_mult (excellent=0.5 → very_poor=1.5) × refurb_cost_per_sqm. Uplift %: very_poor=25%, poor=20%, fair=15%, good=10%, excellent=5%. Conversion viable if: floor_area≥80 AND floors≥2 AND not flat AND not listed. Conv costs/sqm: terraced=£1,200–£2,000, semi=£1,100–£1,900, detached=£1,000–£1,800. units=max(2, area//60). unit_value = current×0.7. conv_value = units × unit_value × 1.05. winner = convert if conv_roi > refurb_roi else renovate. Cross-pollination: winner=convert→T04 | listed→T16 | default→T03.

GPT Report Sections

  1. 1. The Verdict
  2. 2. The Renovation Case
  3. 3. The Conversion Case
  4. 4. The Side-by-Side
  5. 5. The Risks
  6. 6. Your Next Steps

T13 — Title Split Feasibility Tool

GET/POST /portal/tools/title-split 3 min Planner

Get Your Title Split Viability Report
Answer 7 questions about your property. Get a 5-criteria viability assessment, estimated value uplift from splitting, and exactly what needs to happen to make it work.

Form Fields

FieldTypeOptions / Notes
Property typeSelectTerraced | Semi | Detached | Bungalow | Commercial | Flat (converted)
Ownership typeSelectFreehold | Leasehold | Share of freehold
Current configurationSelectSingle dwelling | Already converted | Informally split
Floor area (sqm)Number
Current value (£)Number
Planning statusSelectNone | Full planning | LDC issued | PD confirmed
Building regs statusSelectUnknown | Full sign-off | Regularised cert

Processing Logic

5 viability criteria: Freehold | Physical Separation (≥100sqm or already converted) | Planning Consent | Building Regs | Separate Council Tax. Verdict: 5/5→FULLY VIABLE | 3+/5+freehold→VIABLE WITH WORK | 2+/5+freehold→CONDITIONAL | else→NOT YET. Uplift: units=max(2, area//65), unit_value=current×0.65, legal_costs=3000+(units×1000). Cross-pollination: no planning→T16 | not freehold→T11 | viable→T06 | default→T05.

GPT Report Sections

  1. 1. Your Title Split Verdict
  2. 2. The 5 Viability Criteria
  3. 3. The Financial Opportunity
  4. 4. The Path to Viability / Process from Here
  5. 5. The Risks
  6. 6. Your Next Steps

T14 — Project Risk Scanner

GET/POST /portal/tools/risk-scanner 4 min Project Manager

Scan Your Project Risks
Answer 7 questions about your project. Get a prioritised risk register filtered from 120+ development risks, a heat map, mitigation actions, and a recommended contingency budget.

Form Fields

FieldTypeOptions / Notes
Project typeSelectHouse to flats | HMO | C2R | Barn | Listed | New build | Refurb (light/heavy)
Building ageSelectPre-1930 | 1930–1960 | 1960–1990 | Post-1990
Location constraintsMulti-selectConservation | Listed | Flood zone | None
Planning statusSelectNot applied | Applied | Approved | PD confirmed
Finance typeSelectCash | Bridging | Dev finance
Project manager in placeSelectYes | No
Previous issuesMulti-selectAsbestos | Party wall | Structural | Contractor issue | Planning refusal

Processing Logic

30-risk database (R01–R30) across 6 categories: Planning, Design, Construction, Financial, Legal, Market. Each risk: severity (deal_killer/major/moderate/minor) × likelihood (high/medium/low) = risk_score. SEV: deal_killer=4, major=3, moderate=2, minor=1. LIKE: high=3, medium=2, low=1. has_pm AND Construction/Financial → downgrade likelihood. planning_approved AND Planning → downgrade likelihood. Contingency: avg_score≥8→20%, ≥6→15%, ≥4→12%, else 10%. Cross-pollination: dominant_cat=Financial→T10 | Planning→T16 | default→T09.

GPT Report Sections

  1. 1. Your Risk Profile Summary
  2. 2. Deal-Killer Risks
  3. 3. Top Priority Risks — Full Register
  4. 4. Your Risk Heat Map
  5. 5. Contingency Budget Recommendation
  6. 6. The Role of a Project Manager
  7. 7. Your Next Steps

T15 — Commercial Conversion Scorer

GET/POST /portal/tools/commercial-conversion 4 min Planner

Score Your C2R Conversion Potential
Answer 8 questions about your commercial building. Get a Class MA eligibility assessment, estimated GDV, conversion score, and a full profit/loss analysis.

Form Fields

FieldTypeOptions / Notes
Duration in Class E useSelectUnder 2 years | Over 2 years
Use classSelectClass E (offices/retail/café) | Class B2/B8 (industrial) | Other
ConstraintsMulti-selectListed | Protected area (AONB/NP) | Article 4 | Conservation | Flood | None
Floor area (sqm)Number
Number of floorsSelect1 | 2–3 | 4–6 | 7+
Building conditionSelectGood | Fair | Poor | Very poor
Location typeSelectPrime city | City centre | Town centre | Suburban (good/avg) | Rural town
Purchase price (£)Number

Processing Logic

Class MA eligibility: under_2yrs/listed/protected_area/article_4 → NOT ELIGIBLE. Penalties: conservation-20, flood-15, not_class_e-30, 7+floors-20. NLA=area×0.85. build_cost=1500×condition_mult×NLA. prof_fees=12%. contingency=12%. GDV=res_per_sqm×NLA (regional: prime_city=6500, city=4500, town=3200). conv_score = eligibility_score + margin bonus (≥20%→+20, ≥10%→+10, <0%→-30). Cross-pollination: eligibility=0→T12 | margin≥15%→T06 | default→T04.

GPT Report Sections

  1. 1. Your Conversion Score
  2. 2. Class MA Eligibility
  3. 3. The Financial Case
  4. 4. The Development Opportunity / Improving the Numbers
  5. 5. The Planning Route
  6. 6. Your Next Steps

T16 — Planning Permission Decoder

GET/POST /portal/tools/planning-decoder 4 min Planner

Decode Your Planning Route
Answer 7 questions about your project. Get a clear recommendation on which planning route applies (PD/Prior Approval/Full Planning/LDC), with timeline, cost, and success rate.

Form Fields

FieldTypeOptions / Notes
Project typeSelectHouse to flats | HMO | C2R | Barn/agricultural | New build | Extension | Refurb | Listed building works
Property typeSelectHouse (det/semi/terraced) | Commercial | Mixed use | Agricultural | Flat
Planning constraintsMulti-selectListed | Conservation | Article 4 | AONB/NP | Flood | None
Change of use required?SelectYes | No | Not sure
Planning historySelectNone | Previous refusal | Previous approval | LDC issued
Target useSelectResidential | HMO | Mixed | Commercial | Agricultural

Processing Logic

Decision tree recommends up to 3 planning routes from 7 available: PD (free), Householder (£258–2k, 83% success), Prior Approval Class MA/Q (£120, 78%), Full Planning (£578–15k, 74%), LDC (£258–500, 90%), Class Q (£120, 65%), LBC (free, 55%). listed→always LBC | barn→Class Q | c2r not constrained→Prior Approval + Full Planning | htf/hmo/change_of_use→Full Planning | extension→Householder or PD. Cross-pollination: listed→T14 | change_of_use→T15 | default→T09.

GPT Report Sections

  1. 1. Your Planning Route
  2. 2. What This Route Involves
  3. 3. Timeline and Cost
  4. 4. Why Other Routes Don't Apply
  5. 5. How to Maximise Approval Chances
  6. 6. Your Next Steps

5. Conversion Events & Sequences

Portal Event Types

Event TypeTriggerData CapturedWhat Happens Next
registerPOST /portal/registername, email, phone, icp, source, pathGHL contact created, welcome email sent, stage=1 set
tool_startGET /portal/tools/{{slug}} with tokentool_id, tool_namelast_active_at updated
tool_completePOST /portal/tools/{{slug}}/submittool_id, tool_name, report_summaryToolCompletion created, stage updated, email sent (once), swing check triggered
cta_clickPOST /portal/eventcta_type (primary/alternative/soft_exit), urllast_active_at updated, GHL tag applied if offer URL clicked
offer_viewGET /portal/offer-docoffer_view_count++offer_viewed=True, stage set to 4, swing up to Path A triggered
vsl_viewGET /portal/vsl/{{icp_key}}icp_keyvsl_shown set, path recalculated
webinar_registerGET /portal/evergreen-webinarwebinar_registered=True
live_webinar_registerPOST /portal/live-webinar/registerlive_webinar_registered=True, GHL email sent

Email Sequences Active

SequenceTriggerGPT?Key Content
Welcome emailRegistrationNoFixed template via GHL API — from Zoya Abid <resources@thepcma.uk>
Tool completion follow-upEach tool (fires once — email_sent flag)Yes4 paragraphs referencing actual result summary, recommends next tool. Max 200 words.
Swing Up emailSwing Up event (path → A)Yes3 paragraphs, CTA: apply for fit check at OFFER_URL. Max 160 words.
Swing Down / Re-engagement7-day inactivity detected by scannerYes3 paragraphs, low-friction CTA. Max 130 words.
Live Webinar RegistrationPOST /portal/live-webinar/registerNoFixed GHL template with webinar date/link
Offer DocGET /portal/offer-doc (first visit)Yes6-section HTML document, ICP-personalised, ~450 words, £897/month

Stage Progression

StageConditionDashboard Panel Unlocked
1Registration complete, 0 tools doneTool recommendation card only
21 tool completedStage 2 panel: second tool recommendation, VSL prompt
32+ tools completedStage 3 panel: Offer Doc CTA, webinar prompt, partnership benefits
4Offer viewed OR 4+ tools completedStage 4 panel: direct application CTA, discovery call button

Offer Document - GPT Prompt Structure

Role: Zoya Abid, founder of PCMA Elite Partners Inputs: lead first name, ICP label, ICP pain, ICP message, all completed tool summaries Model: gpt-4.1-mini, max_tokens=900, UK spelling, ~450 words 6 HTML sections: <h2>Hi {first_name} - here's what your diagnostics revealed</h2> <h2>What PCMA Elite Partners delivers for a {icp_label}</h2> <h2>What the partnership looks like in practice</h2> <h2>The numbers</h2> (897/month - what it covers, why not a course) <h2>Who this is - and isn't - for</h2> <h2>The next step</h2> (apply for mutual fit check CTA) OFFER_URL = 'https://thepcma.uk/elitepartners'

6. Swing Mechanics - 5-Path State Machine

The Paths (from live PATHS dict - 5 currently defined)

PathLabelEmojiMomentumDescription Shown to Lead
AFast TrackacceleratingYou're ready — the next step is the mutual fit check.
BVideo First🎬activeA strategy deep-dive video is your next recommended step.
CMasterclass First🎓activeThe Integration Masterclass is your next recommended step.
DDiagnosis First🔍activeComplete one more diagnostic tool to deepen your profile.
ERe-engagement🔔stalledPick up where you left off — your results are still saved.

Key Constants (live from portal_brain.py)

ConstantValueMeaning
STALL_DAYS7Lead inactive for 7 days triggers Swing Down
FAST_TRACK_TOOLS3Completing 3+ tools qualifies high-intent ICPs for Swing Up to Path A
OFFER_URLhttps://thepcma.uk/elitepartnersURL used in all CTA primary buttons and emails

Path Assignment on Registration

def assign_path(icp, source, completed_ids, offer_viewed, vsl_shown, webinar_registered): n = len(completed_ids) FAST_TRACK_TOOLS = 3 # Path A: offer viewed, or 3+ tools + high-intent ICP if offer_viewed: return "A" if n >= FAST_TRACK_TOOLS and icp in ("Ac-Proj", "TP-Pro"): return "A" # Path B: TP-Pro ICP, or VSL already shown if icp == "TP-Pro" or vsl_shown: return "B" # Path C: Sc-LL ICP, or Meta traffic source, or webinar registered if icp == "Sc-LL" or "meta" in (source or "").lower() or webinar_registered: return "C" # Default: D (Asp-Dev, Ac-Proj starting out) return "D"

Swing Up Logic

def should_swing_up(icp, completed_ids, offer_viewed, vsl_shown, webinar_registered, current_path): if current_path == "A": return False # already there if offer_viewed: return True if len(completed_ids) >= 3 and icp in ("Ac-Proj", "TP-Pro"): return True if webinar_registered and len(completed_ids) >= 2: return True return False Effect: path -> "A", generate_swing_up_email() fired via GHL

Swing Down Logic

def should_swing_down(last_active_at, current_path): if current_path == "E": return False # already at bottom if last_active_at is None: return False return (now_utc - last_active_at) > timedelta(days=7) _PATH_ORDER = ['A', 'B', 'C', 'D', 'E'] def swing_down_path(current_path): # Moves one step down: A->B, B->C, C->D, D->E, E->E idx = _PATH_ORDER.index(current_path) return _PATH_ORDER[min(idx + 1, len(_PATH_ORDER) - 1)] Effect: path moves down one step, generate_swing_down_email() fired via GHL

Swing Scanner (APScheduler)

File: app/portal_swing_scanner.py Schedule: every 6 hours (BackgroundScheduler, starts with FastAPI app) For each active PortalLead (not unsubscribed): 1. Load all completed tool_ids 2. should_swing_up(...) -> if True: path="A", fire swing_up_email 3. should_swing_down(last_active_at, current_path) -> if True: path = swing_down_path(path), fire swing_down_email 4. Update swing_last_checked_at = now() 5. Commit DB All emails sent via GHL API. tool_completion_email fires on tool submit (not scanner).

7. Dashboard & Admin

Main Admin Dashboard (GET /)

Dark Bootstrap theme. Background #0f1117, card background #1a1d2e. Renders templates/dashboard.html. Live stats polled from /api/stats.

KPI Cards

CardMetricData Source
Total ContactsCount all contactscontacts table
Tier BreakdownPlatinum / Gold / Silver / Bronze countscontacts.tier
Portal RegistrationsToday / This week / Totalportal_leads.created_at
Active Deal OwnersCount status=Active Deal Ownercontacts.status
Messages TodaySMS + Email + WhatsApp sent todaydaily_stats
Human QueueUnresolved escalated conversationshuman_queue.resolved=False
Auto-Send ModeOn/Off toggle (persisted)app_settings key=auto_send_mode

Admin Actions

Portal Metrics Admin (GET /portal-metrics)

6 KPI cards: Total Leads, Offer Views, Tools Completed, Path A count, Live Webinar Registrations, Stage 4 Leads.

7-step conversion funnel: Portal Registered → First Tool → Second Tool → Webinar → Offer Viewed → Stage 4 → Application Clicked.

Additional panels: Path distribution (A–E), ICP breakdown, Top 10 tools by completion count, 25-item activity feed, Live Webinar admin settings.

Live Stats Endpoint

GET /api/stats -> JSON Returns: { total_contacts, tier_counts (Platinum/Gold/Silver/Bronze), portal_today, portal_week, portal_total, active_deal_owners, msgs_today, human_queue_count, auto_send }

8. Known Limitations & Gaps

Features Not Yet Implemented

WhatsApp Integration — Built, Gated Off ✓
Twilio WhatsApp module fully coded in app/twilio_whatsapp.py, wired into pipeline engine, webhooks at /webhook/twilio/status and /webhook/twilio/inbound. Gated (WHATSAPP_ENABLED = False) pending Meta Business API approval for +447378665987.
Pipeline Engine — Fully Operational ✓
7-tier autonomous pipeline with 200/day cap, hourly tick, 6h backfill. 6,077 GHL contacts enrolled. One-click URLs at app.thepcma.uk. Bot-proof GET→POST entry prevents email scanner false registrations.
VSL Video URLs — 6 Variants Configured ✓
VSL pages at /portal/vsl configured in VSL_URLS. Pipeline Tier 3 emails link directly with one-click login.
Evergreen Webinar URL Configured ✓
The page at /portal/webinar has YouTube embed via WEBINAR_URL. Pipeline Tier 4 emails link directly with one-click login.
Discovery Call — GHL Calendar Configured ✓
Calendar ID FA2qo7uaAiGv5UEy9oo7. Tier 5 emails link to strategy call. discovery_call_clicked triggers pipeline conversion detection.
Short Links — Click Tracking ✓
app/short_links.py generates human-readable codes at /portal/go/{code}. Click count and last_clicked_at tracked per link per contact.
Admin Authentication Is Session-Only
No user account system, password management UI, or role-based access control. Anyone with a valid session cookie can access all admin routes.
No Portal Lead GDPR/Deletion Flow
No admin UI to delete or anonymise a portal lead. The unsubscribe flag stops emails but does not purge data.

Hardcoded Values That Should Be Configurable

The following values are currently read directly from portal_brain.py at audit generation time. Any future change to these constants will be reflected automatically in the next download of this document.

ConstantFileCurrent ValuePurpose
STALL_DAYSportal_brain.py7Days before Swing Down
FAST_TRACK_TOOLSportal_brain.py3Tools to qualify for Swing Up to Path A
OFFER_URLportal_brain.pyhttps://thepcma.uk/elitepartnersOffer page URL used in all CTAs
Partnership priceGPT prompt in generate_offer_doc()£897/monthThe price stated in the offer document
Deferment rate (T11)portal_brain.py5%DEFERMENT_RATE for lease extension calc
Finance cost/month (T09)portal_brain.pyBridging=£4,500, Dev=£6,000Monthly finance charges used in overrun cost calc
Contingency rates (T04)portal_brain.pyListed/Barn=15%, C2R/New=12%, Others=10%Contingency % per project type
Sender emailGHL templateresources@thepcma.ukFrom address on all outbound emails
Swing scanner freq.portal_swing_scanner.pyEvery 6 hoursAPScheduler interval
PORTAL_BASEshort_links.py / pipeline_templates.pyhttps://app.thepcma.uk/portalBase URL for all one-click links and short links
MAX_PIPELINE_SENDS_PER_DAYpipeline_engine.py200Daily pipeline send cap
PIPELINE_BATCH_SIZEpipeline_engine.py50Contacts per tick batch
SEND_DELAY_SECONDSpipeline_engine.py2Seconds between pipeline sends
MIN_HOURS_BETWEEN_MESSAGESsafety.py48Cooldown between any messages to same contact
GHL Calendar IDpipeline_templates.pyFA2qo7uaAiGv5UEy9oo7Strategy call booking calendar

Error Handling Coverage

LayerHandling Present
GPT calls (all 16 tools)try/except on every OpenAI call — falls back to minimal HTML. Errors logged via Python logger.
GHL API callstry/except — failures logged; portal lead still created/updated locally.
Tool form submissionMissing required fields → HTTP 422 (FastAPI validation). No custom user-facing error page.
Invalid/expired tokenReturns HTTP 404 if token not in portal_leads. No redirect to register.
Database errorsSQLAlchemy session rollback on exception; error logged.
Swing scannerPer-lead try/except — one lead failure does not halt the rest.
Pipeline enginePer-contact try/except in tick loop; MAX_CONSECUTIVE_FAILURES=5 stops batch. send_failed status on persistent errors.
Twilio WhatsApptry/except with error code logging (63007, 63031). Errors recorded in last_send_error. Gated by WHATSAPP_ENABLED flag.
Activity loggingRobust try/except with DB rollback — logging failures never crash primary execution threads.

Known Edge Cases

9. Pipeline Engine — 7-Tier Autonomous Conversion

Overview

The pipeline engine (app/pipeline_engine.py) is the primary contact conversion system. It processes 6,077 GHL contacts through a 7-tier progression, delivering ICP-specific content via email and WhatsApp on an automated schedule. The scheduler runs a pipeline tick every 1 hour and a backfill every 6 hours (batch of 200).

Domain: All one-click URLs use https://app.thepcma.uk/portal/enter/{token}
PORTAL_BASE is hardcoded in app/short_links.py and app/pipeline_templates.py

The 7 Tiers

TierContent TypeWait Before Next Tier
1Diagnostic Tool — ICP-specific free tool (e.g., Strategy Selector, Compliance Checker)5 days
2Case Study — Social proof relevant to ICP6 days
3Video Walkthrough — 12-minute VSL7 days
4Live Masterclass — Free training registration7 days
5Strategy Call — 15-minute 1-on-1 offer7 days
6Partnership Summary — Detailed offer document (£897/month)7 days
7Quarterly Nurture — Long-term retention for unconverted contacts (90-day loop)90 days

ICP → First Tool Mapping (Pipeline)

When a Tier 1 message is sent, the tool CTA is personalised per ICP:

ICP CodeICP LabelRecommended Tool Slug
Asp-DevAspiring Developerstrategy-selector (Strategy Selector)
Sc-LLScaling Landlordcompliance-checker (Compliance Checker)
TP-ProTime-Poor Professionaldeal-analyser (Deal Analyser)
Ac-ProjActive Projectdeal-analyser (Deal Analyser)

Contact Status Flow

pipeline_contacts.pipeline_status state machine: queued ──(tick sends message)──▸ sent sent ──(TIER_WAIT_DAYS elapsed)──▸ queued (next tier, current_tier++) sent ──(portal_registered detected)──▸ registered sent ──(discovery_call_clicked / elite_member tag / Active Deal Owner)──▸ converted queued/sent ──(send fails 5x consecutively)──▸ send_failed send_failed ──(admin reset)──▸ queued Tier 7 is a quarterly loop: after 90-day wait, re-queues at tier 7.

Rate Limiting & Safety

ParameterValuePurpose
MAX_PIPELINE_SENDS_PER_DAY200Total messages sent across all contacts per day
PIPELINE_BATCH_SIZE50Contacts processed per tick
SEND_DELAY_SECONDS2Pause between individual sends to avoid throttling
MAX_CONSECUTIVE_FAILURES5Stops batch if 5 sends fail in a row
MIN_HOURS_BETWEEN_MESSAGES48Cooldown between any messages to same contact (safety.py)

One-Click URL System

Token Generation: generate_contact_token(contact_id) → 32-char urlsafe token Stored in pipeline_contacts.pipeline_token URL Structure (per tier): T1: https://app.thepcma.uk/portal/enter/{{token}}?tool={{slug}} T2: https://app.thepcma.uk/portal/enter/{{token}}?tool={{slug}} (case study tool) T3: https://app.thepcma.uk/portal/enter/{{token}}&next=/portal/vsl T4: https://app.thepcma.uk/portal/enter/{{token}}&next=/portal/webinar T5: https://app.thepcma.uk/portal/enter/{{token}}&next=/portal/apply T6: https://app.thepcma.uk/portal/enter/{{token}}&next=/portal/offer-doc T7: https://app.thepcma.uk/portal/enter/{{token}} (quarterly check-in) Short Links (for SMS): get_or_create_short_link(db, contact, destination_url, tool_slug) → https://app.thepcma.uk/portal/go/strategy-wasim (human-readable, first-click tracked)

Bot Protection (One-Click Entry)

The /portal/enter/{token} endpoint uses a GET→POST anti-bot flow:

Multi-Channel Delivery Logic

_send_pipeline_message(contact, pipeline_contact, db): 1. Check safety.can_send(contact) — cooldown, opt-out, channel validation 2. Build template from pipeline_templates.get_tier_template(tier, icp, contact) 3. Email: ghl.send_email_by_address(email, subject, body) via GoHighLevel API 4. WhatsApp: twilio_send_whatsapp(phone, message) via Twilio API - Currently gated: WHATSAPP_ENABLED = False (line ~242) - Awaiting WhatsApp Business API approval for +447378665987 5. On success: status → sent, tier_sent_at = now, send_count++ 6. On failure: last_send_error recorded, failure counter incremented

Conversion Detection

detect_pipeline_conversions() runs every tick before sends. It checks all pipeline contacts with status sent or queued for:

10. Twilio WhatsApp Integration

Module: app/twilio_whatsapp.py

Provides WhatsApp message delivery via the Twilio API. Currently gated off (WHATSAPP_ENABLED = False) pending WhatsApp Business API approval.

Phone Normalisation

UK phone numbers are normalised before sending:

Webhook Endpoints

EndpointPurpose
POST /webhook/twilio/statusDelivery status callbacks (queued, sent, delivered, undelivered, failed). Updates activity log.
POST /webhook/twilio/inboundIncoming WhatsApp messages. Logs to activity_log, marks contact as replied.

Configuration

SecretPurpose
TWILIO_ACCOUNT_SIDTwilio Account SID
TWILIO_AUTH_TOKENTwilio Auth Token
TWILIO_WHATSAPP_NUMBERWhatsApp-enabled Twilio number (currently +447378665987, not yet approved)
Current Status: WhatsApp is fully coded and wired into the pipeline engine but gated off. Twilio error 63007 ("Cannot find Channel with specified From address") confirms the number does not yet have WhatsApp Business API enabled. Plan: new UK SIM + separate Meta Business account.

11. Safety, Scoring & Activity Log

Safety Module (app/safety.py)

Enforces rate limits and opt-out checks before any message is sent:

CheckDetail
CooldownMIN_HOURS_BETWEEN_MESSAGES = 48 hours. Enforced via contact.last_message_at.
Daily CapsMAX_SMS_PER_DAY, MAX_EMAIL_PER_DAY, MAX_WHATSAPP_PER_DAY — tracked in daily_stats table.
Opt-OutChecks contact.unsubscribed flag and GHL tags (e.g., "stop", "unsubscribe", "pcma-unsubscribed").
Channel ValidationVerifies contact has at least one valid delivery channel (email, phone, or whatsapp) before attempting send.
Message LoggingEvery outgoing message recorded in messages table; updates contact.last_message_at.

Scoring Engine (app/scoring.py)

SignalPoints
Email present+10
Phone present+10
WhatsApp present+10
Portal registered+10
Lessons completed (1–3)+5 to +15
Model downloads+10
Offer viewed+15
Offer viewed 2+ times+10 (bonus)
Discovery call clicked+20

Max achievable score: 130.

Tier Thresholds

TierScore Range
Platinum70+
Gold45–69
Silver20–44
Bronze0–19

Pipeline Scoring Bands (pipeline_engine.py)

Used to determine pipeline next param routing:

Score RangePipeline Path
≤20path_e (dormant nurture)
≤40path_e_phase2 (content drip)
≤60path_b_c (moderate engagement)
≤80offer_doc (ready for offer)
81+application (direct conversion)

Activity Log (app/activity_log.py)

Centralised log_activity(event_type, engine, contact_id, detail, metadata) function used by all engines. Writes to activity_log table with JSON metadata. Includes robust error handling with DB rollback to prevent logging failures from crashing primary threads.

12. Scheduler & Background Jobs

APScheduler Configuration (app/scheduler.py)

Job IDIntervalFunctionDescription
pipeline_tick1 hourrun_pipeline_tick()Runs detect_pipeline_conversions() then pipeline_tick() — advances tiers, sends messages
pipeline_backfill6 hoursrun_pipeline_backfill()Enrolls up to 200 existing GHL contacts not yet in pipeline
portal_swing_scan6 hoursrun_portal_swing_scan()Checks all active portal leads for swing up/down conditions
legacy_maintenance6 hoursrun_legacy_maintenance()Legacy outbound path (retired) — maintenance only

Startup Behaviour

start_scheduler() is called from app/main.py on FastAPI startup event. All jobs use BackgroundScheduler and run in background threads. Each job wraps its logic in try/except to prevent one failure from stopping subsequent runs.

PCMA Brain — Technical Audit  |  Confidential  |  For Strategic Advisor Review Only

Generated: 06 April 2026 at 09:30 UTC  |  Zoya Abid, PCMA Elite Partners  |  resources@thepcma.uk

Partnership: £897/month  |  Apply: https://thepcma.uk/elitepartners