The job evidence pack: answer next year's complaint with a record, not a memory
Every photo, note and signature from a job lands under one job number on the day it happens and seals into a single dated PDF at close, so the dispute eighteen months later is settled by the file instead of by whoever sounds more certain
Setup: A weekend (~6-14 h)Running cost: $5-15/mo(software included)Time saved: none directly— no trustworthy figure exists for what undocumented disputes cost a small firm - the numbers in circulation trace back to software vendors' own blogs, so they are not used here. What is verifiable is the alternative's price: CompanyCam standard tiers list at $19-29 per user per month by 2026 third-party listings, which is $114-174 a month for a crew of sixAfter setup: An employee runs it— the filing, the nudge and the sealed PDF are automatic; taking the photographs and getting the signature is the crew, every single jobData lives: Your server— Photographs of customers' homes and premises, plus their signatures, sit on your box. Nothing goes to a third-party account, and the only thing that leaves is a PDF you deliberately send.
Built for small businesses in general — not a sector list.
Before you start
A written shot list of six to ten things photographed on every job - condition on arrival, meter or serial, work in progress, finished state, anything already damaged. Without it the archive is full and useless
A job number that is generated rather than typed, because it is the only key holding the photos, the notes and the signature together
Crew willing to scan a QR code on site instead of sending photos to the office by chat, and a supervisor who says so more than once
A machine that stays on with real disk, since photos and not CPU are what this costs
A written line on why you keep pictures of people's homes, how long, and who can see them - agreed before the first job
Someone whose habit it is to ask for the signature at the door, every time, or half the archive has photos and no acceptance
What breaks firstFAILS SILENTLY
the habit, not the software: photos stop being taken on site and start being uploaded days later, or not at all. An empty album looks the same as a job that needed no photographs. Check the last ten closed jobs against the shot list every quarter - the archive reads as healthy right up to the moment you need it.
Version history
v1.0 · 2026-08-13 — First release. Immich public upload links per job as the capture layer, Grist as the job spine, DocuSeal for the on-the-day signature, Gotenberg for the sealed PDF, n8n wiring it. Says plainly that the camera timestamp is not the authority and that the shot list, not the software, is the product.
A photo you cannot tie to a job number, a date and a place is not evidence. It is a picture. This is the machine that keeps the difference, on your own box, for the price of the hosting.
The architecture
the same flow as text
[ Job created in Grist ] job number, customer, address, dates
▼
[ n8n ] creates the job's Immich album + one public upload link
│ link printed as a QR code on the job sheet
▼
[ Crew phones ] scan the QR → upload → lands in that job's album
[ Subcontractor, no app ] → Nextcloud File Drop link → same job folder
▼
[ Immich ] keeps the camera's date and place, and your server's receipt time
[ DocuSeal ] customer signs the acceptance on a tablet, at the door
▼
[ n8n at close ] → [ Gotenberg ] → one dated PDF
photos in time order · site notes · signature · job facts
Nudge branch: job open, work started, album still empty → message to the crew lead before they leave site.
The job number is the spine. Everything hangs off it, and nothing enters the system without one. That single rule is what turns a pile of images into a file, and it is the reason the upload link is created per job rather than per person or per week.
The problem
The photos exist. That is not the problem. The problem is that they sit on four phones, inside camera rolls of twelve thousand images, and the one that shows the wall was already cracked when you arrived was on the phone that died in March. Eighteen months later the complaint arrives, or the insurer asks, or the customer charges back. At that point the argument is settled by whoever has a record. Whoever has a memory pays.
One honest note before the architecture. There are figures circulating about what poor documentation costs a contractor, and every one I could trace ends at a software vendor's own blog. I am not going to anchor this on a number I cannot verify. The case here is the mechanic, not a statistic: a photo that cannot be connected to a job, a date and a place is weak, and a photo that can be is close to unarguable.
The commercial answer is a per-seat subscription. CompanyCam, the category leader for exactly this, is roughly $19–29 per user per month on its standard tiers by 2026 review listings. For a crew of six that is $114–174 a month, indefinitely, and your evidence lives in someone else's account under their retention rules. This blueprint does the same job with software that costs €0 and a box you already pay for.
Tool choices — and why
Immich
(AGPL-3.0, 110k stars, commit today — 13/08/2026) is the capture layer. It is a self-hosted photo server built around phones, and the feature that matters here is documented plainly: a public share link can be created per album, given an expiry and a password, and set to allow uploads from someone who has no account on your server. That is the whole mechanic. One link per job, one QR on the job sheet, and a subcontractor's apprentice can contribute to the file without you provisioning anything.
Nextcloud
(AGPL-3.0, 36k stars, commit today) covers the case where someone will not scan anything or install anything. File Drop is an upload-only public link: they can put files in, they cannot see what is already there. Slower, uglier, works on any device with a browser. Keep it as the fallback path, pointed at the same job folder.
Grist
(Apache-2.0, 11k stars, commit today) holds the job record. One row per job: number, customer, address, opened, closed, who was on it, and the links to the album and the signed acceptance. A spreadsheet would work for the first fifty jobs and then stop working; Grist gives you the same feel with real records, an API n8n can drive, and access rules so the crew sees their jobs and not your margins.
DocuSeal
(AGPL-3.0, 18.3k stars, commit 11/08/2026) collects the acceptance signature on a tablet while the customer is still standing in the doorway. A signature obtained on the day, against a document that names the job number, is worth more than an email six weeks later saying it was fine. Same tool as the contract signing blueprint in this library, so it earns its container twice.
Gotenberg
(MIT, 12.8k stars, commit today) turns HTML into PDF as a service. n8n renders the job page — facts at the top, photos in time order with their dates underneath, notes, then the signature — and Gotenberg seals it into one file. This is the deliverable a customer, an insurer or a lawyer can actually open, and it is why the stack ends with a PDF rather than a link into your systems.
n8n
(Sustainable Use License, free for internal business use, 200k stars, commit today) is the wiring: create the album on job creation, nudge on an empty album, assemble at close, flag a late arrival. Nothing here needs a language model, and I would not put one near it — an evidence file is the last place you want a component that improvises.
Monthly cost
Software €0 across all six. One VPS or an office box runs the lot at roughly €5–15/month, and photos are what drives that number, not CPU. At phone resolution a busy job-based month is a few gigabytes, so storage is the line to watch after year one, not on day one. Set against $114–174/month for a crew of six on the subscription route.
Setup outline
1. Write the shot list first, before any software. What must be photographed on every job: the condition on arrival, the meter or serial, the work in progress, the finished state, anything already damaged. Six to ten items. This list is the product; the rest is filing.
2. Deploy Immich, Nextcloud, Grist, DocuSeal, Gotenberg and n8n with Docker behind HTTPS on your own domain.
3. Build the Grist jobs table. Job number is generated, not typed, and it is the only key that matters.
4. In n8n: on a new job row, create the Immich album, create the public link with upload enabled and an expiry past your expected close date, write both back to the Grist row, and render the QR onto the job sheet.
5. Add the Nextcloud File Drop fallback link on the same row, pointed at a folder named with the job number.
6. Add the nudge: job status "in progress", no assets in the album by a set hour, message the crew lead. Once per job, not hourly.
7. Build the close flow: render the job page, send it to Gotenberg, store the PDF against the job row and in your archive, and mark anything uploaded after close as a late arrival rather than quietly merging it in.
8. Run it on one crew for three weeks before rolling it out. The failure you are testing for is human, not technical: do the photos actually get taken.
Pitfalls — the real ones
The camera date is not proof, and it is editable
The timestamp in the file is written by the phone, and the phone's clock can be wrong, changed, or set by a person with a motive. What is hard to fake is the moment your server received the file. Record the receipt time, print it in the PDF next to the camera date, and stop treating the camera date as the authority. When the two disagree, that disagreement is itself information.
WhatsApp destroys exactly the thing you need
Sent the ordinary way, WhatsApp compresses the image and strips the EXIF block — GPS and timestamp gone. Sent "as document" it passes the original through untouched. So if your crew's habit is to WhatsApp photos to the office, your evidence is arriving pre-laundered and you will not notice until you need it. The upload link exists to break that habit, and you will have to say so out loud more than once.
Contemporaneous or worthless
A photo uploaded three weeks late, after the complaint landed, is a photo taken by someone who already knew about the complaint. Whatever it shows, its weight collapses. Same-day upload is not tidiness, it is the entire value, and the nudge is not a nicety.
Do not turn on full camera-roll backup
Immich's phone app will happily back up an employee's entire personal camera roll to your server. That is family photos, medical letters and holiday pictures on business infrastructure, a data-protection problem you created for free, and a conversation you do not want to have. Upload-per-job link only, and say it in writing when you hand out the job sheet.
People are in the frame
Site photos catch employees, the customer, the neighbours and the inside of someone's home. Write one paragraph on why you hold them, how long, and who can see them, before the first job rather than after the first complaint. And never put a job photo on social media without asking the customer, however good the before-and-after looks.
Storage is silent until it is not
Photos grow steadily, and the failure mode is an upload that fails on site with an error nobody reads. Alarm the disk at 70% and again at 85%, and decide early whether originals go to cold storage after the retention period or stay forever.
The signature is the socially weakest link
Everything technical here works on the first try. Asking a customer to sign on a tablet before you leave does not, until it becomes routine for the crew. Script the sentence they say. If the signature is skipped on half the jobs, that half of the archive is photos with no acceptance, which is a much weaker file.
This proves what you recorded, not what you did
If nobody photographs the pre-existing crack, the system does not invent it. No amount of automation compensates for a shot list nobody follows. Go back to step 1 every quarter and check the last ten jobs against it.