Skip to main content

Reports & Publishing

This article covers two related concerns:
  1. Publishing an inspection report — the workflow that takes a finalized inspection from internal review to client delivery
  2. The Reports module — the business-intelligence reporting surface at /reports (Monthly Reconciliation, Outstanding A/R, Service Mix, Agent Referral, Inspector Productivity, Activity Log, Tax Summary)
The two share the word “report” but mean different things — publishing is per-inspection PDF delivery; the Reports module is multi-inspection business analytics. For the conceptual model behind the report-publishing workflow, see Generate Your First Report. For the architecture and data model behind the Reports module, see the BI Dashboard architecture doc.

Publishing an inspection report

What “publish” actually does

Clicking Publish in the Inspection Reviewer is one click that triggers a sequence:
  1. Server-side PDF rendering — your template, branding, narratives, photos, ratings, SPOs, summary, and cover photo are composed into a single PDF by the backend’s PDF pipeline (using pdf-poppler, pdfkit, Handlebars)
  2. Upload to Google Cloud Storage — the PDF lands in your tenant’s GCS bucket at a deterministic path
  3. reportStatus = 'published' is written to the inspection in Firestore
  4. report.published workflow trigger fires — every workflow step you’ve wired to that trigger in Comms Cockpit executes
  5. Versioning — the report version increments. Previous versions remain in GCS for audit. The Reports tab on Inspection Details shows the version history.

Pre-flight checks before publish

The Reviewer surfaces warnings if the inspection isn’t ready: Each warning is a soft block — you can publish anyway, but the report quality suffers.

What clients see after publish

The report.published trigger fires whatever workflow steps you’ve configured. The canonical setup is two steps: See Communications → Report Delivery for the rationale for splitting these.

The Client Portal view

Client recipients click $ReportLink and land on the Client Portal (/client-portal/:portalSlug). From there they can:
  • Download the PDF
  • View the inspection summary
  • Access the Repair Request Builder to mark deficiencies they want resolved before closing
  • See payment options (if balance is outstanding)
  • Sign any post-inspection documents

The Realtor Portal view

Agents land at /portal/:tenantSlug after clicking $AgentReportLink. The view:
  • Summary-only — does not include pricing, repair request, or full inspector contact
  • Magic-link authenticated — no account creation required
  • 90-day expiration on the link
  • Branded with your company logo

Re-publishing after edits

You can edit a published inspection and re-publish — every Publish action increments the version. Behaviors:
  • The new version becomes canonical for $ReportLink and $AgentReportLink
  • Previous versions remain in GCS and accessible from the Reports tab on Inspection Details
  • A report.published trigger fires again — your workflow re-sends the delivery emails (set conditional rules in Comms Cockpit if you only want the first publish to email)
  • The History tab logs each republish event
Operationally, most teams set the report-delivery workflow steps to conditional on first publish only (e.g. previousReportStatus != 'published') so re-publishes don’t re-spam the client.

The Reports module — business intelligence

The Reports module lives at /reports (the Reports item in the sidebar). It’s a separate workspace from the per-inspection report workflow above — it produces business analytics reports about your inspection business. [SCREENSHOT: reports-module.png — desktop, the Reports module showing a card grid of available reports: Monthly Reconciliation, Outstanding A/R, Service Mix, Agent Referral, Inspector Productivity, Activity Log, Tax Summary.]

The 7 standard reports

Common controls

Every report shares the same control row:

Monthly Reconciliation — the most-used report

The Monthly Reconciliation report shows, for each order in the selected period: A footer row totals all columns. Below the table, four summary stat cards:

By Order vs By Payout

A toggle (By order / By payout) changes the view:
  • By Order — one row per order (default). Match individual orders to fees.
  • By Payout — one row per Stripe payout (= one bank deposit). Each row expandable to the constituent orders. This view matches your bank statement line items directly.

Outstanding A/R — collections workflow

Lists every order with paymentStatus IN ['pending', 'partial'] AND a completed inspection. Bucketed by aging: Click an order to drill into Inspection Details. From there, manually record a payment or trigger a payment-request email.

Service Mix — pricing optimization

A pivot over orders.services[]: Sort by revenue or count. Useful for identifying which ancillaries pull in the most revenue per attach.

Agent Referral — relationship management

Pivot over orders.referringAgentId: Sort by revenue to see your top agents. Sort by Last referred ascending to find dormant agents who might be cultivated.

Inspector Productivity — team management

For multi-inspector firms only. Pivot over orders.assignedInspectorId:

Activity Log — audit trail

Chronological list of every workflowEvents entry for the period. Useful for dispute resolution (“when did we send the contract?”) and audit (“who modified this order?”).

Tax Summary — year-end

Aggregates annual revenue by service.taxCategory. The categories are configurable per service in Pricing Manager. Useful inputs for 1099 generation and end-of-year tax prep.

Recurring email subscription

Click Email monthly on any report. A small dialog asks for:
  • Recipient(s) — default to the signed-in user, multi-select your team
  • Frequency — Monthly (1st of month) / Quarterly / Annual
The workflow engine fires the report email on schedule with the latest data — useful for sending the Monthly Reconciliation to your bookkeeper on the 1st of every month without you remembering.

Errors and recovery

Publish errors

Reports module errors


What this page does NOT do