ClientsFlow Pipeline · Owner deliverable · 2026-06-24

Meeting-Transcription Pipeline — BUILT & LIVE

Fireflies HYBRID „smart relay" · EBO + implementation + provider rec · merged to main, deployed v102

🟢 built / wired / live-verified 🟡 residual — needs a real Meet or an owner account action SEAM testable via uploadAudio + sim_call_tts (no live Meet) RESIDUAL one golden-journey per infra change

Provider recommendation

One line, then the deciding factors for THIS codebase.

RecommendationWhy (for this repo)
Fireflies HYBRID (not Fathom Business) Repo is 100% Fireflies-wired; native Hungarian AI summaries; client_reference_id deal-id round-trip already passed by ingest_call_audio; CI-able uploadAudio test seam. Fathom Business has no HU summaries (6 non-HU langs), no external-id passthrough, and no upload seam → a full client/handler/HMAC/desktop rewrite for a strictly worse fit. Fathom only wins on bot-free >3 coverage, which the bot relay handles.

The pipeline (delivered)

Capture → webhook → match → store → AI → surface. The smart relay chooses SDK (≤3) vs bot (>3).

① Capture (smart relay)
≤3 → SDK· >3 → bot·upload ·paste
route_capture() + handle_participant_joined(store=); bot dispatch single-flighted via put_if_absent (NOT set(ttl=)).
② Webhook + match
/fireflies/transcription clientReferenceIdcal_id email
NEW: clientReferenceId read FIRST, then the email→CRM→meeting_id chain.
③ Store + AI (HU)
deal store Gemini extractHU summary
Notes-only — nothing auto-sent / auto-tasked to the lead (human-gate intact).
④ Surface
board pill+ Notion calls-DB row
Idempotent Notion row (dedup on Transcript ID), Lead→CRM relation, markdown transcript body.

EBO — positive scenarios 8

IDScenarioVerify layerBehavior
S1≤3 call → bot-free Meet SDK capture (common case)🟡 RESIDUAL (capture) / 🟢 SEAM (rest)Bot-free SDK records, webhook → match → store → HU summary → board pill → Notion row.
S2>3 call → Notetaker BOT auto-invited (the relay)🟢 BUILD/SEAM / 🟡 RESIDUAL (join)route_capture → 'bot' → addToLiveMeeting once (single-flight). LIVE-verified: success:true.
S3No-bot audio upload (record-anything → public URL)🟢 LIVE/SEAMingest_call_audio → uploadAudio with client_reference_id = deal_id. Already wired.
S4Manual paste (bridge for any transcriber)🟢 LIVE + BUILD (Notion row)process_pasted_transcript → extract + HU summary + NEW Notion calls-row (Source=Upload).
S5Idempotent webhook (duplicate delivery)🟢 SEAMSecond delivery is a no-op; Notion row deduped on Transcript ID (query-before-create).
S6HU AI summary as CRM NOTES only (human-gate)🟢 LIVE/BUILDSummary + items are notes; nothing auto-sent to the lead, no auto-task. Test asserts it.
S7Board card pill reflects state🟢 LIVE📞 Sales call megvolt · N perc + Transcript: betöltés…/megvan/hiányzik. Pre-built.
S8Notion calls-DB row complete + Lead-linked🟢 BUILDName/Lead→CRM/Recording/Date/Duration/Source/Transcript ID/status/AI summary + markdown body.

EBO — negative / anti-fragility 9

IDScenarioVerify layerBehavior
N1No CRM match, real external attendee🟢 LIVE/SEAMffseen marked + Slack #ai-new-lead flag; no silent drop, no auto-link.
N2Webhook before transcript ready (early)🟢 LIVE/SEAMget_transcript raises → not marked done → 10-min backup poll retries.
N3Transcription never arrives (missing)🟢 LIVE/BUILDPill stays 'hiányzik'; Notion status not flipped to done; nothing fabricated.
N4>3 escalation when SDK would truncate🟢 BUILD/SEAM / 🟡 RESIDUAL4th joiner re-fires the event → route 'bot', single-flight; ≤3 SDK is the floor.
N5Fireflies API/key failure🟢 LIVE/SEAMStructured {ok:false,error}; no unhandled raise; backup poll + paste remain.
N6Duplicate bot dispatch / rate limit🟢 BUILD/SEAMput_if_absent('meet_bot_sent:{url}') → exactly one dispatch. LIVE single-flight verified.
N7Consent: NO consent UX (Q5)🟢 DESIGNZero consent code added — explicit non-requirement (spoken consent verbally).
N8Account-level Fireflies webhook missing🟢 LIVEPer-upload webhook + 10-min poll cover it; owner registers account webhook (checklist).
N9SA lacks Meet/Workspace-Events scopes🟡 DESIGN/RESIDUALSDK + participant.joined impossible until owner adds scopes; build FAILS CLOSED, no crash.

What was built (additive)

ChangeFileEBO
route_capture() smart relay + handle_participant_joined(store=) single-flightapp/transcription.pyS1/S2/N4/N6
handle_meet_participant_joined() + POST /meet/participant-joined (dormant)app/flows_calls.py · app/modal_app.pyS1/S2/N9
clientReferenceId-first deal matchapp/flows_inbound.py§4 #1 / S3
write_call_record() idempotent Notion calls-DB writer, wired into both handlersapp/flows_calls.pyS8/S5/N3
get_transcript requests transcript_url/audio_urlapp/clients/fireflies.pyS8 (Recording)
NOTION_DB['call_recordings'] wired to the live DBapp/config.pyS8
Landmine fix: store().set(ttl=)put_if_absentTRANSCRIPTION_WIRING.mdS5/N6
Live bug fixed: AddToLiveMeeting selection = success onlyapp/transcription.pyS2 (live)

TDD: +27 tests (test_capture_router, test_call_record_notion, test_meet_participant_route) red→green; legacy test_transcription_s6 updated to the HYBRID contract. Suite 558 green.

Live status — what you can test NOW

Now (live on v102)Blocked on an owner account action
Dash + full funnel render (200, badge c88ec77-dirty+v102)≤3 bot-free SDK capture — Workspace admin approval + Fireflies SDK plan
Upload route (S3) + manual paste (S4) → Notion calls rowAccount-level Fireflies webhook (so bot/SDK transcripts fire)
/meet/participant-joined: ≤3→sdk, >3→bot dispatch (success:true)Workspace-Events participant.v2.joined subscription (for live trigger)
Duplicate-webhook idempotency + Slack no-match flagOne real ≤3 + one real >3 golden-journey Meet (after SDK approval)

Owner checklist (ordered) — the remaining prerequisites

#ActionUnlocks
1Confirm FIREFLIES_API_KEY valid (Pro for the floor; Business for the bot-free SDK)All routes
2Register the account-level Fireflies webhook → <PUBLIC_BASE_URL>/fireflies/transcription + set the x-hub-signature shared secretBot/SDK transcripts fire (N8)
3Confirm PUBLIC_BASE_URL in the Modal env (matyas--clientsflow-pipeline-web.modal.run)Per-upload webhook + form links
4Google Workspace admin approval for the Fireflies Meet SDK + enable the integration≤3 bot-free capture (S1)
5(For the live >3 trigger) Workspace-Events sub for meet.participant.v2.joined/meet/participant-joined (Meet scopes on DWD + Pub/Sub topic + publisher role + renewal cron). Lighter: Fireflies calendar auto-join with „wait for ≥2".Automatic >3 relay (S2)
6Sign the Fireflies DPA (GDPR; EU Private Storage = Enterprise). Consent stays verbal — no code.Compliance

Artifacts

EBO: plans/fireflies-ebo/EBO.md · Implementation: plans/fireflies-ebo/IMPLEMENTATION.md · Wiring + landmine fix: TRANSCRIPTION_WIRING.md · Notion calls DB: „Call Recordings & Transcripts" (92cae219-a975-4a34-ae2e-a8981982a22c) · Live dash: https://matyas--clientsflow-pipeline-web.modal.run/dash · git: merged to local main, NOT pushed.