Human overview · for understanding
Your hand-sorted Notion kanban is now the single source of truth. The app mirrors it, every touchpoint lands in both systems, and the 3 AM pass drafts a follow-up for every active lead. · 2026-07-29
Your hand-sorted Notion kanban is now the single source of truth. The app mirrors it, every touchpoint lands in both systems, and the 3 AM pass drafts a follow-up for every active lead.
Master summary — the gist in 30 seconds
Input: your manually sorted Notion kanban plus everything that happens to a lead (emails in and out, Meet bookings, accepted invites, show-ups). Output: one board that always matches Notion, one activity log both systems share, and a fresh follow-up draft waiting on each active lead's card and Notion page every morning.
flowchart LR N["Your Notion kanban<br/>(hand-sorted truth)"] --> S["Sync engine<br/>(Notion always wins)"] E["Emails, Meets,<br/>invites, show-ups"] --> S S --> B["Pipeline board<br/>(same columns, same leads)"] S --> A["Activity Log<br/>(one shared history)"] S --> D["3 AM sweep<br/>(draft per lead)"]
Input: eight deliverables you dictated (mirrored board, touchpoint parity, contact-page views, a clean event taxonomy, ongoing two-way recording, a manual-wins sync rule, 3 AM drafts, a morning audio recap). Output: all of them built, tested twice, and verified live before morning.
flowchart TD G["Owner's ask:<br/>make my kanban the truth"] --> D1["Mirror the board"] G --> D2["One shared<br/>activity history"] G --> D3["Filtered view on<br/>every contact page"] G --> D4["3 AM follow-up<br/>drafts"] D1 & D2 & D3 & D4 --> M["Working + twice-tested<br/>by morning"]
Input: your hand-renamed Notion columns. Output before the fix: the app compared its old Hungarian labels against your new English ones, matched nothing, and treated whole columns as unknown. Worse, the "Booked" column had an invisible special space character in its name, so even a correct-looking English comparison failed, and the five-minute sync was one push away from creating a duplicate "Booked" column in your Notion that would have looked identical to the real one.
flowchart TD R["You renamed columns<br/>to English in Notion"] --> X["App still expected<br/>the old Hungarian names"] R --> Y["One name carried an<br/>invisible special space"] X --> B1["Whole columns<br/>read as unmapped"] Y --> B2["Near-miss: a duplicate<br/>lookalike column"] B1 & B2 --> F["Fixed: reads are tolerant,<br/>writes use your exact bytes"]
Input: a card moved by hand in Notion, or a real event like a signed contract or a booked call. Output: the app copies your manual move immediately, even backwards. Automatic moves happen only on real events and always carry a logged reason. When the two disagree, Notion wins and the conflict shows up on the Health tab so nothing is ever silently overruled.
flowchart TD
M["You move a card<br/>in Notion"] --> W["App follows,<br/>even backwards"]
E["Real event happens<br/>(payment, booking)"] --> A["App may advance<br/>+ logs the reason"]
W & A --> C{"Conflict?"}
C -->|yes| H["Notion wins,<br/>Health tab shows it"]
C -->|no| OK["Systems agree"]
Input: an activity log where the event type read like robot shorthand. Output: seven human labels — Incoming email, Outgoing email, Meeting with transcript, Phone call, Google Meet event, Created Google Meet event, Accepted Google Meet invitation. The old machine codes were not thrown away, they moved into a hidden field, so nothing automated broke and nothing historical was lost. Four stray rows from the invisible warmup mailbox were archived on sight, as the house rule demands.
flowchart LR OLD["1,653 rows with<br/>machine codes"] --> MAP["Migration map:<br/>code to human label"] MAP --> NEW["7 readable types<br/>on every row"] MAP --> KEEP["Original code kept<br/>in a hidden field"] MAP --> ARC["4 warmup strays<br/>archived, invisible"]
Input: a contact page that used to carry its own hand-maintained history blocks. Output: the same page with a linked view into the one shared Activity Log, showing only that lead's events, sorted newest on top. Rolled out carefully: one pilot contact with visual checks in a real browser, then two more with checks, then all remaining contacts in bulk. Inline history was only archived after the new view was verified to show at least as much.
flowchart TD LOG["One shared<br/>Activity Log"] --> V1["Dupumix page:<br/>pilot + visual QA"] V1 --> V2["2 more leads<br/>+ QA each"] V2 --> ALL["All remaining<br/>contacts in bulk"] ALL --> CLEAN["Inline history archived<br/>only after parity check"]
Input: each lead's full history, plus a library built from 112 of your real past replies, your proven best-scoring reply style, and 233 ready-made drafts. Output: a follow-up draft on the lead's pipeline card and in a text field on their Notion page, line breaks intact. The sweep also triages: a lead who clearly said no gets moved to Lost with a logged, visible reason, a merely quiet lead is left alone, and the four closed columns are skipped entirely. Drafts never reach an outbox, sending stays a human act.
flowchart TD
S["3 AM sweep wakes"] --> R["Reads each active<br/>lead's conversation"]
R --> G["Grounds in your 112<br/>real past replies"]
G --> J{"Per-lead judgement"}
J -->|worth chasing| DR["Draft on card +<br/>Notion page"]
J -->|clearly said no| L["Moved to Lost,<br/>reason logged"]
J -->|closed column| SK["Skipped"]
DR --> H["Human reviews,<br/>human sends"]
Input: the finished build. Output: wave one checks it, then wave two checks it again with brand-new testers following different instructions so shared blind spots cannot pass twice. The finale is one continuous journey on staging: a sentinel test lead is created, moved by hand in Notion, emailed in and out, booked into a Meet, swept at 3 AM logic, and finally purged without a trace. Verdicts come from screenshot pixels, so a blank board can never be waved through as a timeout. Only after that does it ship to production and get verified live.
flowchart LR B["Build done"] --> W1["QA wave 1"] W1 --> W2["QA wave 2:<br/>fresh agents,<br/>different script"] W2 --> F["Live finale:<br/>fake lead walks<br/>the whole funnel"] F --> P["Judged from<br/>screenshot pixels"] P --> SHIP["Ship to prod +<br/>verify live"] SHIP --> PURGE["Test data purged"]
Input: your answers. Output: instant adjustments. The open items: 1) "Website done & fully paid" currently sorts last on the board because Notion's API cannot read your hand-sorted column order — say where you want it. 2) The board deliberately shows 28 active leads your Notion view hides because they have no Deal Type — keep them visible or mirror the filter exactly? 3) Your view excludes two people under Assign, but the API cannot read which two — name them and it is fixed. 4) The stale "Ip. egyeztetve" option is now empty — deleting it is a one-click job in the Notion UI, left for you. 5) The legacy 50-row activity log turned out to be 17 test fixtures plus 33 rows from a different business — purge the fixtures, and where should the 33 go? 6) Optional: a 2-minute admin-console grant would upgrade Meet attendance from transcript-inference to direct detection.
1) The nastiest bug of the night was a single invisible character — a non-breaking space you typed by accident while renaming a column. It defeated both the app and any screenshot-based check, because it renders identically to a normal space. 2) The cloud machine ran out of its monthly AI budget at 00:46, mid-run. The fallback armed at launch worked: your Mac detected the stall in the morning, took over, and finished the remaining steps locally. Nothing was lost because every commit was already pushed. 3) All 1,653 activity rows got their new human-readable type, and the census of 269 contacts processed matched your live CRM count exactly. 4) The drafts are grounded in your own 112 real past replies, and the golden rule is literal: when a similar conversation exists in your history, the sweep reuses your own words first. 5) Column identifiers were kept stable under the renames, so your saved board preferences like collapsed columns survived the whole operation.