Openfront Real Estate
Listings, leads, showings, offers, deals, closing records, and commissions for a brokerage, with a public listing site.
Source · Live site · Catalog
Openfront Real Estate is a self-hosted app for one brokerage. Visitors browse listings, ask questions, request tours, and save homes and searches. Brokerage staff manage listings, leads, showings, deals, closing records, commissions, and team setup in the dashboard.
To install it, see Getting started.
Escrow, title, mortgage, commission, and syndication records hold what staff enter and track.
Concepts
| Concept | Meaning |
|---|---|
| Brokerage | The tenant. The storefront serves the primary one |
| Membership | A user's seat: owner, admin, team_lead, agent, coordinator, analyst |
| Property | A listing, sale or rent |
| Authority records | License, listing engagement, publication, and representation records that gate publishing and actions |
| Lead | A person with an interest, deduplicated per listing by an email or phone identity key |
| Deal | A transaction with offers, milestones, documents, and closing records |
| Ledger | Append-only commission entries |
Tenancy
Brokerageis the tenant. Operational records have a required or derivedbrokeragerelation. Child records such as media, inspections, and milestones take their brokerage from the parent.- Access comes from
activeBrokerageIds(session): the user's selectedactiveBrokerage, or their one live membership. A user with two live memberships and no selection sees nothing. BrokerageMembershiplinks a user to a brokerage with a role (owner,admin,team_lead,agent,coordinator,analyst) and a status (invited,active,suspended).Roleflags decide what a member can do:canAccessDashboard,canManageListings,canManageLeads,canManageShowings,canManageDeals,canManagePeople,canManageRoles,canViewReports,canManageOnboarding,canSeeOtherPeople,canEditOtherPeople. WithoutcanManagePeople, agents work only on records assigned to them.- Storefront customers are
Userrows with anactiveBrokerageand no membership. Their showings, inquiries, saved homes, and saved searches are linked to their account by the server, never by matching an email. - The storefront serves the first active brokerage marked
isPrimary.
Data model
The model registry has 44 lists.
| Area | Lists |
|---|---|
| Brokerage and people | Brokerage, BrokerageSettings, BrokerageMembership, User, Role, AgentTeam, AgentTask |
| Listings | Property, PropertyMedia, OpenHouse, ListingSyndication, MarketComp, PropertyValuation, Neighborhood, SourceFeed |
| Authority records | ListingEngagementAuthority, ListingPublicationAuthority, PractitionerLicenseAuthority, RepresentationAuthority |
| Leads and showings | Lead, LeadActivity, LeadRoutingRule, Showing, ShowingFeedback |
| Shopper data | SavedProperty, SavedSearch, SavedSearchAlert |
| Deals and closing | Deal, Offer, TransactionMilestone, DealDocument, DocumentEvidenceEvent, Disclosure, PropertyInspection, Escrow, TitleOrder, MortgageApplication |
| Commission | Commission, CommissionLedgerEntry |
| Records and events | RetentionPolicy, TransactionFileEvent, DomainOutboxEvent, DomainAuditEvent |
Neighborhood has no brokerage field. It is shared reference data and is managed through the generic list page.
Main state machines
| Record | States | Changed by |
|---|---|---|
| Property | draft → coming_soon → active ⇄ pending → sold or rented; any → off_market | transitionPropertyStatus |
| Lead | new → attempted_contact → qualified → tour_scheduled → offer → closed or lost | transitionLeadStatus |
| Showing | requested → scheduled → completed or no_show; requested or scheduled → cancelled | transitionShowingStatus, reviewShowingCommand, completeShowingWithFeedback, cancelCustomerShowing |
| Deal | prospecting → active_search → offer_drafted → under_contract → inspection / financing → closed_won; open → closed_lost | transitionDealStage |
| Offer | draft → submitted → countered, accepted, rejected, or withdrawn | transitionOfferStatus, createCounterOfferCommand |
| Milestone | not_started → in_progress → complete; blocked | transitionTransactionMilestoneStatus |
| Document | draft → sent → signed → archived | transitionDocumentCommand |
| Disclosure | draft → sent → acknowledged; expired | transitionDisclosureStatus |
| Inspection | scheduled → completed, needs_follow_up, or waived | transitionInspectionCommand |
| Commission | projected → approved → paid; clawed_back | transitionCommissionStatus |
| Open house | scheduled → completed or cancelled | transitionOpenHouseStatus |
| Agent task | open → in_progress → done; blocked | transitionAgentTaskCommand |
| Outbox event | pending, processing, dispatched, failed | replayDomainOutboxEvent resets failed or dispatched to pending |
Authority records, DocumentEvidenceEvent, CommissionLedgerEntry, RetentionPolicy, TransactionFileEvent, and DomainAuditEvent are append-only.
Workflows
Publish a listing. Create a draft Property and add media and open houses. A listing shows on the storefront only when it is active or coming_soon and there is an effective practitioner license, a signed listing engagement with marketing authority, and public_site publication authority for it.
Capture a lead. The storefront question form (submitListingInquiry) and tour form (requestPropertyShowing) create or reuse a Lead. Leads are deduplicated per listing by an email or phone identity key. The first matching active LeadRoutingRule picks the agent, then the listing agent, then a fallback rule. The agent must still hold an active membership; otherwise the lead stays unassigned. Staff can also add leads by hand.
Tour a home. A tour request creates a requested showing. Its length comes from showingDurationMinutes in brokerage settings, clamped to 15–240 minutes. Staff confirm it, complete it with feedback, mark it no-show, or cancel it. Confirming checks that the property and agent have no other confirmed showing at that time.
Close a deal. Create a deal from a lead and listing. Add offers and counters, checklist milestones, documents with evidence events, disclosures, inspections, a mortgage application, a title order, and escrow. Move the deal stage to closed_won or closed_lost.
Track commission. Create a commission per side. Use the ledger commands to propose and approve a split, record a receipt, reverse an entry, and reconcile.
Run the team. Owners and admins invite and suspend members. Only an owner can add another admin. Staff manage teams, tasks, and lead routing rules.
Keep records. Record retention policies, apply retention to a deal file or document, place or release a legal hold, and create an export manifest.
Named GraphQL operations
All custom operations are in features/keystone/mutations/index.ts.
Public and customer queries: publicBrokerageIdentity, publicRealEstateListings, publicRealEstateListing, customerShowingHistory, customerInquiryHistory, customerSavedProperties, customerSavedHomes, redirectToInit.
Public and customer mutations: submitListingInquiry, requestPropertyShowing, registerRealEstateCustomer, cancelCustomerShowing, savePropertyForCurrentUser, removeSavedPropertyForCurrentUser, saveSearchForCurrentUser, deleteSavedSearchForCurrentUser.
Operator queries: platformContacts, platformLeadDetail, platformShowingRequestViewer, platformListings, platformShowings, platformShowingDetail, scheduledShowingReceipt, platformPipeline, platformPeople, platformReports, platformOperations, platformStorefrontSettings, domainOutboxEventStatus.
Status transitions: transitionLeadStatus, transitionPropertyStatus, transitionShowingStatus, reviewShowingCommand, transitionOpenHouseStatus, transitionOfferStatus, transitionDealStage, transitionCommissionStatus, transitionDisclosureStatus, transitionTransactionMilestoneStatus. They take an idempotency key and can check the expected status or updatedAt.
Operator commands:
- Leads and showings:
addLeadActivityCommand,resolveDuplicateLeadCommand,scheduleShowingForLeadCommand,completeShowingWithFeedback. - Deals:
createOfferCommand,createCounterOfferCommand,createChecklistItemCommand,transitionDocumentCommand,transitionInspectionCommand,updateDealFinancialTermsCommand,updateDealNextStepCommand. - Authority and evidence:
recordPractitionerLicenseAuthorityCommand,recordListingEngagementAuthorityCommand,recordListingPublicationAuthorityCommand,recordRepresentationAuthorityCommand,appendDocumentEvidenceEventCommand. - Commission ledger:
proposeCommissionAllocationCommand,approveCommissionAllocationCommand,recordCommissionReceiptCommand,reverseCommissionLedgerEntryCommand,reconcileCommissionLedgerCommand. - Records:
recordRetentionPolicyCommand,assignTransactionFileRetentionCommand,recordTransactionLegalHoldCommand,createTransactionExportManifestCommand. - Feeds and alerts:
queueSourceImportCommand,transitionListingSyndicationCommand,queueSavedSearchAlertCommand,updateSavedSearchAlertCommand,replayDomainOutboxEvent. - People and tasks:
inviteBrokerageMemberCommand,suspendBrokerageMemberCommand,transitionAgentTaskCommand. - Setup:
runRealEstateOnboarding,dismissRealEstateOnboarding,updatePlatformStorefrontSettings.
Some dashboard pages also use the generated Keystone CRUD mutations, for example to create listings, leads, media, open houses, deals, tasks, routing rules, inspections, escrow, title orders, mortgage applications, and commissions. Those writes still go through list access rules and tenant hooks.
Onboarding
The first user is created at /dashboard/init together with a starter brokerage, an Admin role, and an owner membership. The dashboard then offers a basic or complete setup through runRealEstateOnboarding. Details are in Getting started.
Integrations
- Email: password reset email through nodemailer and the
SMTP_*variables. No other email is sent. - AI chat: an optional dashboard chat at
/api/completionuses OpenRouter. It is available only to signed-in users with dashboard access and calls the MCP endpoint at/api/mcp-transport/[transport]with the user's session cookie. - MCP endpoint: exposes generic tools that list models, query, search, create, update, and delete data through GraphQL with the caller's session. The same file still declares e-commerce tools (products, carts, checkout, orders). Only the real estate tools apply here.
- Calendar files: the storefront generates
.icsfiles for a customer's own showing and for open houses. - Feeds and syndication:
SourceFeedandListingSyndicationhold status that staff record.queueSourceImportCommandandqueueSavedSearchAlertCommandwrite outbox events. Events staypendinguntil your own process dispatches them.