02 · The product
Every job, from the first phone call to the closed invoice
One app, two very different faces. Here is what each part does, and why it works the way it does.
The spine
Three things hold the whole system up
If intake, status and filing are right, everything else is a feature. If any one of them is wrong, nothing else matters. This is the part we built first and guard hardest.
Smart intake and Promote
the QuickBooks bridgeEvery new job is created in DUDE — third-party dispatches included — with a live type-ahead against existing QuickBooks customers. Promote then does four things in one press: creates the QuickBooks sub-customer under the right parent, captures its customer id, binds the QuickBooks Time jobcode, builds the Drive folder tree and copies in the estimate template.
A job's identity in three systems is established in one press, and bound by id, never by name — because names change and collide, and ids don't. A QuickBooks error writes nothing at all; a partial landing tells you exactly where it stopped and offers the button that finishes only the missing part.
The status spine
15 statuses, zero automatic transitionsNew, Initial Contact, Needs Quote, Estimating, Estimate Pending, Waiting, Waiting on Materials, Waiting on Customer, Ready to Schedule, Active, Work Completed, Invoice Ready, Closed, Lost, Cancelled. Only admin and dispatch move a job, and every move writes a history row in the same transaction as the change.
Leads and jobs are one table — a lead is simply a job whose QuickBooks fields are still empty — so a job never has to be re-created when it becomes real.
The fifteen statuses roll up into six lifecycle phases, and the app refuses to start if those six ever stop exactly partitioning the fifteen. A sixteenth status can never quietly vanish off the board.
Documents in Google Drive
no destination choiceOne shared drive, tiered by customer type: Residential, Commercial, 3rd Party, Internal → customer → [Job ID] - [Job Name] → Admin, Signed Docs, Documents, Pictures, Receipts. A backend service account does all the Drive work, so field techs keep their permissions but never have to navigate Drive.
The uploader gets exactly one decision — before, after, or today's visit — and the server turns that into a real folder. Notes append to a single Notes.txt, newest first, stamped with author and local time. A Drive read failure degrades softly: the page still renders, with a note saying what it couldn't reach.
Misfiling is structurally impossible, because the person uploading never names a destination. An "Open Job Folder" deep link exists anyway, as a required fallback.
The field day
What a tech on an iPad actually sees
The governing rule is blunt: complexity lives with admin, never the field. Field techs are not technology-inclined; several would rather use no technology at all. So the field surface is small, fixed, and fast on bad signal.
My Week, and one tap on the clock
A tech lands on their own week, one day at a time, and nothing else. Three pinned buttons sit at the bottom: all jobs, the contacts directory, and a gas receipt. Clocking in is one tap on the job page — the job is pre-selected by definition, and the two fields every timesheet here is required to carry are filled in automatically.
DUDE stores no timesheets and no location trails. It holds a sixty-second state cache and a token-health flag, and every punch verifiably lands or visibly fails.
Punches are bounded to two attempts of ten seconds, because mobile Safari abandons a hung request at about sixty — so the honest answer from a slower retry could never have arrived anyway.
Customer sign-off on the iPad
the worst job in the company, fixedThe office pre-loads the document that needs signing. It appears under Ready to sign on the tech's screen. He taps once, hands the iPad to the customer, the customer signs on the glass, and he drags the signature into position — with optional printed name and date stamps. The backend stamps and flattens it into the PDF and files [document] - signed.pdf into Signed Docs/.
It handles scanned, rotated and inset-crop-box PDFs, which is to say the print-driver and Word exports that real customers actually send. Emailing the finished file is deliberately manual — DUDE has no email capability at all, on purpose.
Six steps of Drive-and-markup juggling became sign, drag, file. Entirely on open-source libraries, at no added monthly cost.
Job hazard analysis
A seven-category hazard matrix, a task action plan, PPE selection, site emergency information, and signature pads for the lead tech and any subcontractor. On submit, DUDE composes a formal PDF and files it into Signed Docs/. A compliance artifact, produced from a form a tech can actually fill in on a phone-sized screen.
The daily log
append-onlyA per-job, per-day narrative from the field. There is no edit path and no delete path anywhere in the code — a correction is another entry. Admin can read across the whole company filtered by date range, job and tech, in any combination. When a job reaches a terminal status the whole log is written once into the job folder as Daily Log.txt.
If that final write fails, the notice on the job page is derived, not a stored flag — so it clears itself the instant the archive lands. No queue, no worker, no flag to go stale.
Expenses, with the receipt read for you
Anyone signed in can file an expense against a job. DUDE writes a real QuickBooks purchase, marks it pending review, attaches the receipt and drops a copy into the job's Receipts/ folder. The receipt image is run through Google's expense parser, and the amount, date and vendor come back as editable pre-fills marked from receipt — check it.
Vendors, categories, payment accounts and classes are cached locally, so the whole form runs fast on one bar of signal. A duplicate guard plus an idempotency key make a double tap safe.
The gas button is the neatest thing in the app: fuelling up asks for the vehicle and the odometer, and that odometer reading is the same number that later tells the fleet coordinator the van is due for service. Entered once, at the pump.
Refusals a technician can act on
a whole slice about error messagesA later hardening pass went through the money path and gave every silent branch a sentence: an amount over the ceiling, a vendor typed but never picked from the list, a date the system won't accept, a job with no folder, an upload too big to send. Each one now says what happened and what to do.
The checks were deliberately ordered so the ones a tech is likeliest to trip fire first — because every refusal costs them re-attaching the receipt photo.
Small things, from daily use
Clock in from the shift page as well as the job page. A clock-out note prompt that works with no JavaScript at all. Long dropdowns replaced with type-to-find boxes once the job list got big enough to scroll. Settings messages that appear in the section you were working in instead of somewhere off-screen.
None of these came from a plan. They came from using it, which is the advantage of the person who decides what gets built also being the person who has to live with it.
The office
Where the complexity is allowed to live
Filter state is the URL — a view is a link you can paste to somebody.
Schedule — cached to read, write-through to change
A manual Sync Schedule button, plus a nightly backstop around 4am, pulls the QuickBooks Time schedule into DUDE's own cache. There is no polling during business hours. The field's week view and the office's tech-by-day dispatch grid read only that cache, which is why they load instantly on weak signal.
Writing goes the other way: admin schedules a shift from the job page or a plus sign on any grid cell, saves it as a draft or publishes it, and DUDE writes to QuickBooks Time first, then immediately re-syncs. Stale edits are refused rather than merged. Creates never auto-retry, because a duplicate shift is worse than a failed one.
Nobody at this company types a class, a service item or a shift address any more — all three derive from data admin already entered once. A blank class used to leave techs unable to clock out at all.
Estimates — one pipeline, two very different jobs
Big jobs are finished in the job's Google Sheet, because that is the tool the office already trusts and we were never going to out-build a spreadsheet. Import Estimate reads named ranges into DUDE's scope of work, materials list and proposed budget, behind a preview and a confirm, and it is safely re-importable — a missing named range saves nothing.
Small jobs go the other way: a tech submits an on-site estimate — labour lines, material lines, site notes — and DUDE writes it into the sheet, checking capacity first with real numbers ("the labour area fits nine lines, you entered twelve"). The tech's raw submission is preserved verbatim, forever.
Budget versus actual
The estimate's proposed budget sits beside the actuals, read live and never stored: hours from QuickBooks Time, expenses from QuickBooks purchases tagged to the job, with an "as of" timestamp and a refresh button. Labour is compared in hours, not dollars, because we don't connect payroll.
It is honest about what it can't know. Reading live rather than mirroring is what stops DUDE becoming a second book of record that disagrees with the first.
The contacts directory
deliberately not syncedCustomers, vendors, subcontractors and third parties — with a distinction QuickBooks does not make: the account (a company) versus the attached person inside it, like a facility's maintenance supervisor. Directory records link to jobs with a role label, and on the field job page a tech simply taps the number to call.
The field's read-only view names its columns explicitly and never carries the QuickBooks fields, so the fence is a property of the query rather than a template's good behaviour.
Repair verbs as real features
Adopt binds a DUDE job to a QuickBooks sub-customer that already exists. Re-link fixes a mis-adopt in place, behind a confirmation that spells out what does and does not follow — and refuses outright once money has been filed against the job. Plus finish Drive setup, retry rename, link or unlink a folder, archive a daily log, and link or ignore an unmatched jobcode.
The app knows its own failure modes by name. Every partial state has a button that repairs exactly what is missing, and every one of them is safe to press twice.
One Save, and a guard against the other person
The status card used to carry four separate Update buttons — status, next step, project manager, lead technician. It now carries one Save that writes only what you actually changed, in a single transaction. The four unguarded write routes behind the old buttons were deleted rather than left open.
If anyone changed one of those fields while your page sat open, the save refuses as a whole and names the field. A partial save would need a message explaining two outcomes at once, and the page must not guess which of two people was right.
Fleet
The second module: vans and equipment
There was no system of record at all for our own machines. Maintenance history lived in people's heads and vehicle spend landed in one undifferentiated bucket. Fleet is a full module built on the same rules as the rest of the app — and unlike most of what gets written about internal tools, it is not a demo: the rollout closed on 20 October 2026 with every active vehicle entered, foldered and labelled, and equipment now gets added as ordinary use rather than as a project.
3 active machines have no active schedule, so nothing above can warn about them — see them in the registry
A registry where the label is not stored anywhere
Every vehicle and machine gets a permanent number and a derived label — V-1, E-2 — computed from category and id by one expression that both the list and the search read. The paint on the van and the searchable string cannot drift apart, because there is only one of them. Numbers are never reused, gaps are allowed, and correcting a machine's category flips the letter while the number never moves.
Each asset gets its own Drive folder for photos, registration and service records, renamed and moved automatically when the asset is renamed or recategorised.
Readings, intervals, and a working board
Usage readings are a dated, append-only log — hand-entered, baseline, gas fill-up, or captured at a service. Current usage is derived as the latest non-voided reading, so voiding one bad odometer entry corrects everything downstream instantly. Service intervals run every N days and/or every N miles or hours, whichever comes first.
The landing page is a board, not a menu: Overdue, Coming due, Not computable yet, Recently completed. "Coming due" is the last tenth of the interval, so the warning scales with the job. "Not computable yet" names its own reason for each machine, and the fix. And the slice that closed the rollout added a line counting the machines with no schedule at all — the ones no board can warn about — linking to the registry filtered to exactly those.
Implausible readings get a confirmation, never a rejection. The tech at the pump is usually right and always in a hurry.
A maintenance pipeline that starts outside the module
Techs report problems from their own week screen — machine, description, one urgent flag, optional photo. Never a severity menu. The button shipped dark behind a single setting and was switched on once the registry held the real fleet; it has been live for every technician since 16 October 2026, and the first two reports — real records against a real van — were filed that same afternoon, on an iPad, as the pass that proved the button worked. Reports land in a queue, urgent first then oldest, and the coordinator moves each one through a matrix that only ever offers the legal next verbs: acknowledge, schedule, start, park as waiting on parts or shop or budget, re-slot, reject, complete.
Completing a record happens in one transaction: what was done, preventive or reactive, in-house or a validated vendor, the date, the usage reading, and an optional pass-or-fail inspection checklist. Costs file as ordinary QuickBooks purchases against a permanent internal fleet job, and the coordinator never picks an accounting code — DUDE derives it.
A tech's report can be attached to the schedule it satisfies instead of being rejected as a duplicate. "Rejected" is reserved for work that isn't real, always.
Inspections, costs, and what the report won't claim
A completed job can carry an inspection checklist — pass, fail or not-applicable per item, with notes. The checklist lives in code rather than in the database, so rewording an item is a deploy and old answers stay attached to what was actually asked. A failed item records the problem and triggers nothing: raising the work is a person's decision.
The cost report gives maintenance, fuel and total per machine, by year or lifetime, including retired and zero-cost machines.
It prints its own limits on the page: this is not total cost of ownership — no depreciation, insurance or registration — and fleet costs start where DUDE started, because nothing was imported from before.
And a second product
The client portal
Our first client has had a door of their own since September: a separate application, now at portal.donedone.services, where a facility contact files a maintenance request from their phone, follows it through six plain-language states, and talks to us on the request itself. It is a window into DUDE with a letterbox in it — the work never leaves here.
The split
Two products wearing one name
| Field tech, on an iPad | Office, on a desktop | |
|---|---|---|
| Lands on | My Week — their own shifts, one day at a time | A dashboard with glanceable alerts |
| Navigation | Three pinned buttons. Nothing else. | Full top nav: jobs, schedule, contacts, daily log, fleet, settings, guide |
| Job page | Nine cards, fixed order, fixed defaults. The page remembers nothing. | Collapsible blocks that remember themselves per device |
| Why | Field support needs "what do you see?" to have exactly one answer | Admin is trainable; a block you work in daily should be where you left it |
| Money visible | Material unit prices and subtotal, so a tech can shop to budget. Never labour rates, fees, margin or variance. | Everything |
| Packaging | Added to the home screen — full screen, no browser chrome. No offline mode, on purpose. | An ordinary browser tab |
No offline pretence. There is no service worker and no offline mode. The weak-signal story is "pages that read from a local cache and load instantly", not a synchronisation model that lies to a tech standing in a basement.
Around the edges
The manual is a screen
The three user guides are not a separate artifact that can rot — their source is rendered inside the app at /guide, behind the same sign-in, and served by role: techs get the field guide, admins the office one, fleet-access holders get fleet appended. Moving the manual is part of a slice's definition of done.
Sign-in, and exactly one exception
Google sign-in restricted to the company domain. No passwords anywhere. Everyone is admin or tech — until fleet needed a coordinator who wasn't either, which became a single boolean beside the role rather than a third role. A third role would have been mutually exclusive with admin, so every fleet gate would have had to spell out both — the rule written once per gate instead of once, full stop.
The not-to-exceed calculator
A faithful port of a standalone script the office already trusted: type a destination, pick regular, overtime or emergency, and it looks up the one-way driving distance from the shop and returns the number to quote — same rates, same boundary, same rounding. Stateless; nothing stored.
What it deliberately doesn't do
DUDE itself sends no email, ever — signed documents are emailed by hand, on purpose. No automated migration of historical jobs. No automatic status changes. No payroll connection. Every one of those is a written decision with reasoning attached, not an omission. (The client portal does send transactional email; DUDE still doesn't, and the two are separate applications for exactly that kind of reason.)
DUDE