About Dealsplit
Revenue recognition for real estate teams, simplified.
Last deployed June 1, 2026 at 5:28 PM EST
Changelog
Changes on branch `extract_correct`
Unreleased0.6.0 - 2026-06-01
Added
- • Brokerage Setting per Agency: Agencies now have a brokerage selection (Compass, eXp, or KW) in Settings → Agency. This is the switch that turns on format-specific journal handling — Compass retention consolidation, eXp-specific fee mappings, KW disbursement detection. Without it set, deals fall back to generic per-party math regardless of what the PDF actually is
- • Risk Management Fee as Its Own GL Bucket: eXp's Risk Management Fee (E&O) is no longer lumped into "Other Deductions". Agencies can map it to a dedicated account in their chart of accounts or fold it into Brokerage Transaction Fees — set it under Settings → GL Account Mappings
- • Brokerage Cap Credits / Refunds: When the brokerage refunds part of company-dollar back to the office (KW post-cap, referral company-dollar reversals), the refund now books as a credit on the same Commissions to Office account that outgoing brokerage fees debit. The 12-month cap total reflects gross movement on that account (per accountant guidance), so the office's annual cap balance stays accurate. Detected automatically when the disbursement table shows the brokerage as a payee with negative net
- • Live Processing Indicator on Dashboard: Deals being extracted show a subtle "alive" animation while the AI is working, with a separate reduced-motion fallback that respects system accessibility settings
- • Auto-Linked vs User-Edited Corrections (Admin): The extraction-corrections view distinguishes name mappings the system auto-linked (longer roster name to its canonical short form) from corrections a user actually retyped. Real friction is no longer hidden under canonical-name normalization
- • Enterprise Subscription Overrides (Admin): Sales-onboarded enterprise customers can have a custom deal limit, custom feature set, custom plan label, and custom monthly price set directly on their subscription from the admin user detail page — no Stripe price object required. The resolved feature state shows inline so admins can see exactly what an account has access to
- • Per-Request Context on Error Reports: Production error events now carry which user, page, route, and LiveView triggered them — eliminating the "which user hit this?" guesswork on support tickets
- • Agent Performance in Insights: The Insights dashboard adds a per-agent performance breakdown with a drill-down detail page for each agent, alongside office KPIs (net revenue, deals closed) that now show the trend versus the prior period
- • Branded Account Emails: Sign-in magic links, email confirmation, and password/email-change notices are now branded HTML messages matching the app, with a plain-text fallback for every mail client
Changed
- • Compass Team-Deal Journals — Retention as One Line: Compass statements show GCI, then brokerage retention (typically 15% gross less a 5% team incentive = 10% net), then per-agent splits. Previously the journal pro-rated that retention across every party. Now it consolidates onto the principal as a single line — matching what every Compass agency books today and what their P&Ls expect (the brokerage retention recorded as one event, not pro-rated across each party). Both presentations balance; the new one matches the reading
- • Journal Entries Show the Actual Brokerage: Broker-tied components (broker fees, transaction fees, review fees, royalties, stock purchase, risk management) now carry the deal's actual brokerage and market center on the journal entry instead of a generic "EXP" placeholder. Names match the actual entity on every deal
- • Compass Concession Handling — No More Double-Count: Compass statements often show both a deal-level concession rollup AND per-agent concession rows; both are the same money reported two ways. The extractor now treats per-agent allocations as the source of truth and the deal-level rollup as reporting only — eliminating a class of double-count bugs on team deals
- • eXp Referral Detection Widened: Now identifies four structural patterns instead of one — "SVC FEE" headers, "Other Transaction Type" headers, all-zero standard fields, and documents missing a Sale/Listing Commission Base section. Fewer eXp referrals end up shoe-horned into listing or buyer
-
•
Compass Per-Agent Shape Recovery: When the model emits an agent's commission as their net check (instead of the gross share + retention pair the document actually shows), the extractor now derives the missing broker_fee from
gross × split × retentionso per-agent math stays uniform across all parties before the journal pass - • Insights Numbers Match the Journal: The "net to office" figure on Insights now applies the same concession dedupe rule as the journal entry. Deal-level concession rollups no longer double-count against per-agent concession rows. What Insights shows is what the journal books — invariant, not coincidence
- • QBO Posting Errors Show Useful Messages: When QBO rejects a posting (auth expired, duplicate document number, account doesn't exist), users see a categorized message describing the actual problem instead of a raw exception inspect string. Retry decisions are also now driven by error category, not substring guesswork
- • eXp Deal-Level Referrals from the Statement Summary: When an eXp statement records a referral only in its summary totals rather than as a party line, the extractor now reads that printed summary line to recover the deal-level referral — and only from an explicit printed referral, so it never invents one to explain an unrelated gap
- • Team-Deal Agent Splits Book Consistently: Non-principal agent commission splits are booked from the gross allocation printed on the statement (falling back to the net check only when the gross is missing), so the office journal treats every team deal's agent splits the same way
- • Admin User Detail Reorganized: The admin user detail page is restructured into balanced zones — a metrics strip and Deals-by-Status up top, then condensed account and integrations cards — for a faster read on a single customer
Fixed
- • KW Disbursement Misfire on Compass and Solo Deals: The safety check that flags KW DA-format documents collapsing into the principal's net was firing on Compass deals and any solo-principal deal — neither was the actual problem case. Compass solo deals where "Outstanding Credits" legitimately equals the principal net are no longer flagged. Now only fires on the case it was designed for: KW multi-party deals
- • Agent Deductions Stay on the Agent's Card: In the deal wizard, a non-principal agent's brokerage deductions now stay on that agent's party card instead of appearing under the office's Deal Expenses. Agent costs are the agent's, not the office's — so office expense is no longer overstated on team deals
Tech Debt / Refactor
- • AI extractor broken up — the 1500-LOC monolith is now a thin facade over Client, Parser, Prompt, Normalizer (with BankDeposit / ComponentSemantics / Gross / SplitComponents sub-modules), Compass, PartyMatcher, ExtractionContext, and BrokerageProfile. Single-purpose modules, easier to test, calculator stays out of the LLM path
-
•
Context writes route through
Repo.update_owned/Repo.delete_ownedinstead of hand-rolleduser_id == current_user_idchecks scattered across contexts. Single ownership boundary on the write side -
•
QBO errors tagged at source —
Qbo.Error.classify_string/1and 14 substring patterns deleted; posting failures and worker retry classification both route throughRevrec.Qbo.Error -
•
ExtractionMemory correction attrs centralized through
Correction.attrs/4— replaces ad-hoc map building across 9 correction types -
•
Extraction quality harness runs on every
mix test(~0.1s, no exclude flag). Writestmp/extraction_quality_report.mdbucketing the 61-fixture corpus into Structural / External knowledge / Extraction quality / Possibly-extractable -
•
Procedure for adding a new canonical GL key documented end-to-end (7 steps, worked example) in
lib/revrec/deals/CLAUDE.md; AI extractor architecture documented inlib/revrec/ai_extractor/CLAUDE.md
Upgrade and Migration
-
•
Migration
add_brokerage_name_to_agenciesadds the brokerage field to agencies -
•
Migration
add_subscription_overridesadds custom deal-limit / features / label / monthly-price columns to subscriptions for enterprise overrides -
•
Migration
add_source_to_extraction_correctionsadds an auto/user discriminator to correction rows (no backfill — old rows remain NULL) -
•
Migration
drop_who_pays_from_deal_partiesremoves an unused column -
•
Migrations
add_extraction_normalized_json_to_dealsandadd_pipeline_state_to_extraction_correctionsadd storage for normalized extraction output and correction pipeline state (no backfill required) - • Action required: Set the brokerage on each agency in Settings → Agency. Without it, Compass retention consolidation, eXp-specific behavior, and brokerage-aware journal names all fall back to generic handling — even on a clearly-Compass or clearly-eXp document
0.5.0 - 2026-04-15
Added
- • Multi-PDF Dashboard Upload: Upload up to 10 PDFs at once from the dashboard. Each file gets its own progress indicator, extractions run concurrently, and single-file uploads auto-navigate to the wizard when extraction completes
- • Brokerage-Aware Extraction: The extractor now recognizes whether a statement is from KW, Compass, or eXp and applies format-specific rules — Company Dollar / CAP / Royalty lines on KW disbursement forms, Outstanding Credits and concession handling on Compass, Capped Fee / Review Fee / BPOL on eXp, plus correct treatment of agent split percentages before brokerage retention
- • Consistent Compass Math: After extraction, Compass split amounts are deterministically recalculated from the gross, split %, and fee amount on the statement — so re-running the same PDF no longer produces slightly different numbers due to model rounding
- • Referral-Only Deals: New "referral" deal side for deals where the office only received a referral fee with no property representation (common on eXp). Previously these had to be shoe-horned into listing/buyer/both
-
•
Extraction Corrections Analytics (Admin): When a user edits extraction output at deal approval, the specific corrections are logged — missed parties, wrong sides, component additions, agent-name mappings, and so on. Admins can see the most common correction patterns at
/admin/extraction-correctionsto prioritize which statement formats need prompt attention - • Admin Infinite Scroll: Dashboard activity feed and per-user deal lists now load additional rows as you scroll, replacing paged navigation. Emails and deal addresses are clickable links (the separate "View" column is gone)
- • Searchable Vendor Dropdown: Vendor-name matching in the deal wizard uses a searchable select with keyboard navigation — much easier to find the right vendor in long lists
- • Custom 400 Error Page: Branded error page for malformed requests, with server-side logging that distinguishes bot probing from real client bugs
- • More Granular Fee Components: Transaction fees, review fees, and concessions are now their own component types with dedicated GL mappings (previously bundled into generic buckets). Transaction-coordinator names are captured as payees on their processing fees
Changed
- • GPT-5.4 Extraction Engine: Upgraded AI extraction from GPT-4o to GPT-5.4 with native PDF upload — PDFs are sent directly to the model instead of converting to images, improving accuracy especially on Compass statements and eXp notifications
- • Strict Schema Enforcement: Extraction output is now constrained by a strict JSON schema at the token level, eliminating malformed or missing fields
- • Better Bank Deposit Detection: Per-format bank-deposit strategy — KW pulls from the disbursement payee list, Compass prefers "Outstanding Credits" with a fee-amount fallback, eXp derives the net from the principal section. Twelve previously-failing cases now resolve correctly
- • Compass Statement Extraction: Further improvements to split handling, concession capture, multi-agent split parsing, and explicit exclusion of brokerage-direct admin fees from gross commission
- • Consistent Principal Handling: Principal-agent detection, GL account lookups, and display formatting consolidated into shared helpers so the wizard, journal preview, QBO, and Sheets stay in lockstep
Fixed
- • Quality-of-Life UX: Journal entry rendering, wizard scroll behavior, duplicate flash messages on upload failure, double-navigation during multi-file selection, and assorted small polish throughout the dashboard and wizard
- • Billing Quota on Multi-Upload: Per-file billing check now accounts for in-flight uploads, so users can't exceed their plan's deal quota by uploading multiple files at once
- • Orphan Deal Cleanup: Deals created during Drive ingestion are cleaned up if the background job fails to enqueue, preventing stranded rows. Storage cleanup failures are now logged
- • Upload Error Surfacing: Local storage upload failures become flash messages instead of crash pages
- • Decimal Precision Throughout: Monetary amounts are parsed and stored as exact decimals end-to-end. Floating-point math has been removed from QBO amount formatting, deal reset, and fee component validation — floating-point rounding in accounting software produces real bugs
- • Franchise Fee GL Mapping: Franchise fees and franchise taxes now map to separate GL accounts instead of sharing one
Security
-
•
Force HTTPS in Production:
force_sslenabled in prod with secure cookies. Health check endpoints excluded from the SSL redirect so Fly's internal checks still work over HTTP - • Changeset Trust Boundary: Enforced split between user-editable and server-controlled fields on deal schemas — form submissions can no longer accidentally write to fields like ownership, status, or calculated values
Tech Debt / Refactor
- • Centralized GL account keys, principal-agent checks, and display formatting helpers
- • Unified Drive polling and dashboard upload onto the same ingest worker flow
-
•
New
ExtractionMemorycontext with aCorrectionschema — capture-only analytics layer for extraction quality - • Upload rate limit aligned with the dashboard uploader's max entries
-
•
.worktrees/ignored at the repo level to support isolated feature development -
•
docs/ops/runbook consolidates operational documentation; MCP server architecture plan added
Upgrade and Migration
-
•
Migration
create_extraction_correctionsadds theextraction_correctionstable for correction-pattern analytics - • No manual operator steps required
0.4.0 - 2026-03-28
Added
- • Company Dollar / Broker Fee Extraction: AI extraction now recognizes broker fee variants — "Company Dollar", "Company Commission", "Commissions to Office", "CAP"/"Pre-Cap"/"Post-Cap", "Broker Fee", "Office Fee", "Franchise Fee". Treated as negative amounts (money flowing back to brokerage)
- • Compass Statement Handling: Extraction handles Compass split structures (e.g., 85% commission + 5% incentive = 90% to agent), auto-calculates full GCI from partial, and extracts net company commission as negative broker_fee
- • Searchable Select Hook: JS hook for agent matching dropdowns with keyboard navigation and filtering
- • Google Picker Hook: JS hook for Google Drive spreadsheet selection
- • Dimensional Tags: Selectable QBO class/division tags on deals, with auto-defaulting from agent configuration
- • Sitemap Controller: SEO sitemap endpoint
Changed
-
•
Google Integration Rework: Switched from broad folder access to per-file Google Picker with
drive.filescope (non-sensitive, no CASA audit required). ConfigLive now separates Drive and Sheets connection flows - • Component Polish: Prettier UI components with improved styling and selectable CSS classes throughout the app
- • Config Page Redesign: Better section organization and layout for the configuration page
- • Wizard Sticky Layout: Journal entry preview and PDF viewer now pin below the running tally header instead of overlapping it — both stay visible while deal content scrolls
- • Billing & Pricing: Billing banner and plan display improvements
- • QBO Token Refresh: Client reloads agency from DB before refreshing to avoid consuming stale single-use tokens
Fixed
- • Production discrepancies: Fixed feature flag evaluation and GL account mapping consistency in production
- • Stale GL mapping keys: Migration fixes stale GL mapping key references
- • GCI Stability: Adding non-principal agents no longer mutates gross commission
- • PDF Storage: Fixed upload controller PDF storage path handling
- • QBO Error Handling: Improved error categorization (retryable vs non-retryable)
Tech Debt / Refactor
- • Refactored deal wizard step names and component organization
- • Account key mapper improvements with new test coverage
Upgrade and Migration
-
•
Migration
fix_stale_gl_mapping_keyscorrects stale GL mapping key references
0.3.0 - 2026-03-10
Added
-
•
Admin Dashboard: Real-time business metrics at
/admin— deal counts by status, posting success rates, destination breakdown (QBO/Sheets), recent activity feed with email filtering, and "Needs Attention" alerts for failed postings and stuck jobs. Auto-refreshes every 30 seconds -
•
Office Insights Dashboard: User-facing analytics at
/insightswith period filters (month/quarter/year/all time) — office KPIs (GCI, net to office, deal count, avg deal size), agent-level breakdown, and trend indicators with % change vs previous period - • Stripe Billing Integration: Full subscription lifecycle — Free (2 deals lifetime), Light (3/month, Sheets only), Pro (20/month, QBO + Sheets + Drive), Elite (200/month, all features + Insights). Feature flags gate deal creation and posting per plan
- • Google Drive Auto-Import: Automatic PDF ingestion from Google Drive — polling for new files, dedup via unique constraint, download→S3→deal→extract pipeline, PubSub broadcasts for real-time progress. Gated to Pro/Elite plans
-
•
Onboarding Product Tour: Driver.js-powered guided walkthrough on first login — branded step definitions targeting nav links and upload zone. Tracks completion via
onboarded_aton user record - • Cloudflare Turnstile CAPTCHA: Integrated on login and registration forms with auto-refresh on failed verification
- • Rate Limiting: Hammer ETS backend with IP-based and user-based rate checks, plug for controller pipelines, admin metrics tracking
- • Deal PubSub: Real-time updates for deal status changes (wizard posting progress) and dashboard list refresh on deal creation/update/deletion
-
•
Referral Fee Extraction: AI extraction now captures referral fee components with
payee_namefield — handles "Outside Referral" deductions across multiple agents contributing to the same referral partner - • Golden Path Test Cases: Additional real-deal test fixtures for extraction validation
- • robots.txt and sitemap.xml: SEO infrastructure for search engine crawling
- • Google Analytics: GA measurement integration in app.js
Changed
- • Landing Page Redesign: New marketing site with pricing tiers, testimonials (embedded at compile time for release compatibility), and updated footer
-
•
Admin Routes: Double auth protection (plug + on_mount) at
/adminwith role-based access (:admin,:superuser) -
•
Billing enforcement disabled in dev/test:
Billing.enabled?/0feature flag defaults false outside production - • Swoosh email configuration: Updated for production delivery
Fixed
- • Referral fee amounts: Now correctly extracted with payee names and mapped to journal entries
- • Dimension handling: Fixed dimension tag application on deal entries
- • QBO token refresh: Client reloads agency from DB before refresh to avoid consuming stale single-use tokens
- • Running tally display: Various wizard UI fixes post-0.2.0
Tech Debt / Refactor
-
•
Revrec.Admincontext module with cross-tenant queries (skip_user_id: true) for batch user/deal/subscription lookups -
•
Revrec.Billingcontext withFeaturesmodule as single source of truth for plan feature matrix -
•
Revrec.Drivecontext with Client, SyncedFile schema, and folder polling pipeline -
•
Revrec.Deals.Insightsmodule for aggregation queries and KPI calculations -
•
RevrecWeb.RateLimithelper andRateLimitPlugfor rate limiting infrastructure - • ADR-0005: DealSplit feature design documentation
Upgrade and Migration
-
•
Migration adds
payee_nameto fee_components,last_login_atto users,onboarded_atto users -
•
Migration creates
subscriptionstable for Stripe billing -
•
Migration adds Google Drive fields to agencies and creates
drive_synced_filestable - • Migration renames plan tiers for billing consistency
0.2.0 - 2026-02-03
Added
- • Google Sheets: Added "Gross to Office" column for principal agent's gross commission
- • Google Sheets: Added Agent 3 Name and Agent 3 Split columns (now supports 3 non-principal agents)
- • Google Sheets: Agent overflow warning when deal has more agents than available sheet slots
- • QBO: Auto-create vendors when posting journal entries - agents without a QBO vendor ID get matched to existing vendors via fuzzy name matching, or created as new vendors
-
•
QBO:
Qbo.VendorSyncmodule withensure_vendors_for_deal/2for bulk vendor sync andsync_agent/2for single-agent sync - • QBO: Vendor sync summary included in posting audit logs (matched/created/skipped/errors counts)
-
•
Initialized
tkticket system for project task tracking
Changed
- • Google Sheets: Agent splits now show GROSS commission (base commission component) instead of NET (fee_amount) to match journal entries
- • Google Sheets: Agents now sorted by gross commission amount (highest first) instead of insertion order
- • Google Sheets: Principal agent separated from non-principal agents - principal goes to "Gross to Office", others fill Agent 1/2/3 slots in order of commission
- • QBO Poster: Now runs vendor sync before posting journal entries - preloads deal_parties with agents
-
•
Row formatter now preloads agent association to detect principal status via
agent.role == :principal
Fixed
- • Google Sheets: Agent split amounts now match journal entry "Commissions Paid Out" values (gross, not net)
- • Google Sheets: Consistent ordering between UI display and sheet output
- • Deal Wizard: Running tally no longer overlaps the Progress sidebar
- • Deal Wizard: Journal Entry Preview now shows full account names on hover (tooltip)
- • Dark Mode: Fixed overly bright chips and badges throughout the app (status badges, fee component tags, dimension tags, role badges)
Tech Debt / Refactor
-
•
Extracted
partition_agents/1helper to cleanly separate principal from non-principal agents -
•
Extracted
get_gross_commission/1helper to calculate base commission from fee components -
•
Added
Qbo.Client.query_vendors/1andcreate_vendor/2for vendor API operations -
•
New
Qbo.VendorSyncmodule encapsulates fuzzy name matching (viaNameMatcher) and vendor lifecycle
Upgrade and Migration
- • Users must add "Gross to Office" column to their Google Sheets and refresh mappings
- • Users may add "Agent 3 Name" and "Agent 3 Split" columns for 3-agent deals
0.1.0 - 2026-01-11
Added
- • Deal Wizard Redesign: Real-time accounting workbench with running tally showing Gross Commission, Agent Splits, Expenses, and Net to Office as you edit
- • Edit Tracking System: Visual badges (AI/Edited/User) show what came from extraction vs. user corrections
- • Collapsible Review Sections: Extraction Summary, Agent Matching, Deal Knowledge, Revenue Configuration, and Dimensional Tags organized by correction category
- • Golden Path Integration Tests: End-to-end test framework comparing AI extraction + corrections against expected journal entries for real deals
-
•
New account types:
broker_review_fee,charitable_contributions,stock_purchase(equity account) - • Brokerage name field on deals for NAME dimension in journal entries
- • About page: Accessible via header link, displays changelog with semantic styling
Changed
- • Wizard flow reduced from 5 to 4 steps: Upload and Extract merged into single step with auto-extraction
-
•
Journal entries now use deal-side-specific accounts: Listing deals →
listing_income/agent_listing_splits, Buyer deals →buyer_income/agent_buyer_splits, etc. - • Always per-agent entries: Each agent gets separate expense line (no more aggregation mode)
- • Consistent entry ordering: Revenue (credits) → Agent splits → Fee components → Referral fees → Undeposited Funds
Fixed
- • Principal handling: Principal commissions correctly stay with office, not recorded as expenses
Removed
- • Zero-balance placeholder entries removed from journal output
- • Simple/aggregated agent expense mode removed
- • Separate Extract step removed from wizard flow
Tech Debt / Refactor
- • FeeComponentEditor extracted as reusable LiveComponent
- • Edit state computation decoupled into EditTracker module
- • Running tally computed from deal state, not stored
Upgrade and Migration
-
•
Migration adds
brokerage_namecolumn todealstable