Hood Cleaning Report
NFPA 96 compliance reports for commercial kitchen exhaust contractors.

- 64
- organic search clicks, 90 days
- 2
- compliance standards covered
The problem
A hood cleaning crew finishes a job and owes the client an inspection-ready report with before and after photos, measurements and a signature. Most of them assemble it by hand from a phone camera roll, or pay a VA to retype it. The report is the deliverable the whole job is billed against, and it is the part nobody has time for.
What I owned
- Multi-tenant backend
- CompanyCam integration
- Document vault
- PDF pipeline
- Field drafting
How it works
- 01
CompanyCam OAuth, encrypted at rest
Third-party tokens are Fernet-encrypted in the database and webhooks are verified with HMAC-SHA1. Photos arrive from the crew's existing tool, so nobody has to change how they shoot a job.
- 02
Document vault with signed share URLs
Reports go out as expiring signed links rather than attachments, and every view is written to an audit log, which is the part that matters when an inspector asks who saw what and when.
- 03
AI drafts the compliance fields
The imported photo set is used to draft the NFPA 96 and ANSI-IKECA C10 fields, which the technician reviews rather than types. The review step is not optional: this is a document an inspector reads, so a wrong field is worse than an empty one.
- 04
Block-based PDF generation
Reports are composed from typed blocks and rendered through Playwright, so the layout is real HTML and CSS rather than a coordinate-pushing PDF library.
- 05
Multi-tenant from the first migration
Workspaces, roles and soft deletes were in the schema before the first customer, because retrofitting tenancy onto a live compliance product is not a weekend.
Stack
- Django 5
- DRF
- PostgreSQL
- Playwright
- Cloudflare R2
- CompanyCam API
- React
- Tailwind v4