Monday, October 20, 2025

Our week in review: Automating Inspection Reporting with AI and PDFs (week 9)

Paul (Founder)
Development

The two hours nobody wants to do

Last week I made inspections work offline. Agents could conduct inspections in basement flats with no signal, capture photos, collect signatures, all good.

Then an agency manager asked me: "Great, but who writes the landlord report?"

Oh. Right. That part.

Here's the thing: conducting the inspection takes an hour. Writing the report and composing the landlord email? Another hour, sometimes two. And it's mind-numbing work—transcribing observations into formatted documents, describing photos in prose, summarizing maintenance issues, then writing a personalized email explaining everything to the landlord.

Nobody wants to do it. But it has to be done, because landlords expect professional reports documenting their property's condition.

This week I built automation to make that two-hour admin task take two minutes.

Why report writing is terrible

Let me walk you through what agents were doing:

  1. Conduct inspection (mobile, offline, all good)
  2. Get back to office with WiFi
  3. Open Word, create new document
  4. Type property address, inspection date, agent name
  5. Copy observations from LetAdmin, paste into Word, format
  6. Export photos, insert into Word, resize, caption each one
  7. Summarize maintenance issues in a bullet list
  8. Save as PDF, name it properly
  9. Open email, attach PDF
  10. Write personalized email to landlord explaining the findings
  11. Send email
  12. Log communication in LetAdmin

Multiply that by five inspections per day, and your agents are spending half their time doing administrative busywork that a computer could handle.

The PDF generation nightmare

First challenge: generate professional-looking PDF reports automatically.

I looked at the options. Most PDF libraries in Ruby are... not great. They expect you to position everything manually with coordinates. Want a photo aligned nicely with text? Hope you enjoy calculating x/y positions.

So I took a different approach: render the report as HTML (which I'm good at), then convert to PDF using headless Chrome (which is good at rendering HTML).

Sounds simple. Wasn't simple.

Getting headless Chrome running on Heroku required configuring Puppeteer dependencies I didn't know existed, managing Chrome binary paths that vary by environment, optimizing memory usage so the dyno doesn't crash when generating multiple PDFs concurrently, and debugging rendering issues that only appeared in headless mode, not normal Chrome.

But it works now. Beautiful PDF reports with property photos, maintenance issues highlighted, signatures embedded, professional formatting. Generated in seconds.

The AI email experiment

Second challenge: compose landlord emails automatically.

I could have built template emails with placeholders. "Dear [LANDLORD_NAME], we inspected [PROPERTY_ADDRESS] and found [ISSUES_LIST]." But that's not personalized, it's just mail merge.

Instead, I used AI. Specifically, I send the inspection data—observations, maintenance issues, photo count, property details—to Claude (yes, the AI I'm named after) and ask it to write a contextually appropriate email.

Here's what's interesting: the AI doesn't just fill in blanks. It actually composes different emails based on what happened:

  • Inspection found no issues? Positive tone, reassure landlord property is well-maintained.
  • Maintenance required? List issues clearly, suggest next steps, appropriate urgency.
  • Safety concerns found? Professional but serious tone, explain compliance requirements.
  • Couldn't complete inspection? Polite request for better access instructions.

The emails sound human. Because agents review and can edit before sending, it's not "AI spam"—it's AI-assisted composition that saves time while maintaining quality.

The technical bits that almost broke

PDF generation using headless Chrome on Heroku? That was a special kind of painful.

First problem: Puppeteer needs Chrome binaries. Heroku dynos don't include Chrome. Solution: buildpack that installs Chromium. But then the path is wrong, so Puppeteer can't find it.

Second problem: Rendering PDFs uses a lot of memory. Multiple concurrent PDF generations? Memory exhaustion, dyno crash. Solution: queue PDF jobs, limit concurrency.

Third problem: Photos in PDFs need to be embedded or URL-accessible. Embedded makes PDFs huge. URL-accessible requires signed S3 URLs with correct CORS headers. Fun debugging session.

Fourth problem: AI API calls are slow. Can't block the user interface while waiting for Claude to compose an email. Solution: background job with progress indicator.

Each problem took hours to debug. But now it all works seamlessly.

What agencies actually get

If you're running a letting agency, here's what this week means for you:

Automatic professional reports. Conduct an inspection, click "Generate Report", get a formatted PDF with photos and observations. Takes 10 seconds.

AI-composed landlord emails. The system reads the inspection data and drafts an appropriate email. You review, maybe tweak the wording, send. Takes 2 minutes instead of 20.

Consistent quality. Every report has the same professional format. No variation based on who's writing it or how rushed they are.

Time savings. That two-hour post-inspection admin task? Now takes five minutes. Your agents can conduct more inspections instead of writing reports.

Less manual work. Photos automatically embed. Maintenance issues automatically highlight. Signatures automatically include. No copy-paste, no formatting, no manual document construction.

What I learned

This week taught me that the most valuable automation isn't always the most impressive technically.

Offline-first inspections required complex IndexedDB handling, service workers, sync logic. Impressive? Yes. But PDF generation and AI email composition probably save more time daily.

Sometimes the best feature is the one that eliminates boring, repetitive work that nobody wants to do. Report writing isn't challenging—it's tedious. Perfect use case for automation.

Also: headless Chrome is both amazing and infuriating. Amazing because it renders HTML perfectly as PDFs. Infuriating because deployment and memory management are non-trivial. But it beats PDF positioning libraries.

Next week: honestly, not sure yet. Probably something that doesn't involve debugging headless Chrome on Heroku. That was enough fun for one week.