← All documentation

Team

Work hours, expenses, and per-issue time logs

Log crew time and spend three ways — quick time logs on a maintenance issue, payroll work hours on the dashboard, and expenses for reimbursement. Covers the shared draft → submit → approve flow, mileage, category setup, month rollups, and PDF exports for payroll + finance.

TrailsIQ tracks crew labour and spend through three related surfaces: quick time logs you file against a specific maintenance issue in the field, work hours you submit for payroll on the dashboard, and expenses you file for reimbursement. They share the same draft → submit → approve flow, the same rollups, and the same permission model, so once you learn one, the others feel identical.

The three concepts

  • Quick time log (per maintenance issue) — a "how long did I work on this specific issue" note filed straight from the issue's detail card in the field app. Duration in minutes + a short note + the work date. Rolls up to the linked project's Hours worked tile and powers the org-wide Work report at /work-report.
  • Work hours (payroll timesheet) — a decimal-hours entry with a category (regular work, trail maintenance, admin, meeting, training, travel, holiday, vacation, sick, etc.) and optional description + project or task link. Submitted for approval and exported as a PDF timesheet.
  • Expense (reimbursement) — an amount + currency + category + optional receipt image + optional project or task link. Uses the exact same approval + export machinery as work hours.

The two payroll-adjacent surfaces (/work-hours and /expenses) are intentionally mirror-image dashboards — same nav, same Day / Week / Month / Review buttons, same batch-submit and approve buttons — so learning one teaches you the other. The internal comment on the controller literally reads "Mirrors ExpensesController almost line-for-line; hours are tracked the same way money is."

Quick time logs are the outlier — they live inline on a maintenance issue and don't go through the draft → submit → approve flow. They land, they count, they roll up.

Logging time from the field app (quick time log)

Open a maintenance task on the field app. The detail card shows an Work log action alongside Edit and Share, with a small badge counting any entries already filed. Tap it and the full-screen "Work log" overlay slides up.

Header reads "Work log · Xh Ym total" when there are entries. Under Add entry you get three inputs — hrs, min, and What did you do? — and a Log button.

Any active member can log. Owners and managers can delete anyone's log; field workers and volunteers can only delete their own.

Existing entries render under a History heading (empty state: "No time logged yet."). Tap the pencil on any row to edit hours / minutes / activity / date inline, then Save or Cancel.

If you open a task and get "This task isn't in your current organization — it may have been moved, deleted, or you've switched orgs. Refreshing now…", you switched orgs since the task was cached. The app auto-refreshes.

Where the time surfaces:

  • The Project's Hours worked tile — every quick time log on an issue linked to a project rolls up here.
  • The org-wide Work report at /work-report — aggregates by user, by trail, and by issue type over a 30-day default window. Exports as a PDF with the hours totalled, or as a CSV of the raw entries.
  • The maintenance issue's own history — so anyone re-opening the issue sees who logged what.

Nothing about a quick time log flows into /work-hours payroll or expenses. If the crew member also wants payroll credit for the same time, they file a WorkHour entry separately on the dashboard — see the next section.

Logging work hours from the dashboard

Open Work hours from the sidebar. Header reads "Work hours" with the subhead "Log and submit work hours for payroll."

The page has three toggles across the top:

  • Week — every entry for the current week, grouped by day.
  • Month — the current month with a "Monthly total" banner in primary blue, a By category rollup, and (for approvers) a Team summary list of every crew member's total for the month.
  • Review — the approval queue. Managers and anyone with the Approve work hours permission see this button; everyone else doesn't.

Below the toggles: a day nav (prev / next / date picker / Today). Approvers also see a Member: dropdown defaulting to All members so they can filter the visible entries by crew member.

Click + Log hours to open the entry form. Fields:

  • Date — required.
  • Hours — 0.25–24 in 0.25 steps. Client-side error if you fat-finger: "Please enter hours between 0.25 and 24."
  • Category — pick from the enabled categories (see below).
  • Description — optional, up to 2000 characters. Placeholder "What did you work on?"
  • Link to project or task (optional) — pick either a project or a specific maintenance task, not both. If you set both the server silently drops the task link.

Save with Save entry or bail with Cancel. Entries land as drafts — private to you until you tap Submit on the row (or Submit all in the banner on Week / Month views).

There's no hourly-rate field. Payroll rates live outside TrailsIQ.

Logging an expense

Open Expenses from the sidebar. Header reads "Expenses" with the subhead "Track and submit crew expenses for reimbursement." Same three-toggle nav as Work hours (Week / Month / Review), plus a Review badge with an amber count for approvers ("99+" when it overflows).

Click + Add expense for the entry form:

  • Date — required, must be today or earlier.
  • Category — enabled expense categories (see below). Picking Mileage switches the form into miles mode (see the Mileage section).
  • Amount — 0.01 to 99,999.99.
  • Currency — dropdown of 10 codes (USD default: CAD, EUR, GBP, AUD, NZD, CHF, JPY, MXN, ZAR).
  • Description — placeholder "What was this expense for?"
  • Link to project or task (optional) — same shared picker.
  • Receipt — one image, up to 5 MB, JPG / PNG / WebP. Two entry paths:
    • Choose photo — pick from the device photo library.
    • Scan receipt — opens a scanner modal that side-steps the "white-screen iOS bug from <input capture>".

Save with Save expense or Cancel. Same draft → submit → approve flow as work hours.

Categories and org configuration

Both surfaces use a fixed catalog of categories, and both are trimmable to just the ones your org actually uses.

Expense categories: Fuel, Supplies, Tools, Meals, Accommodation, Transport, Mileage, Other.

Work hour categories: split into three groups:

  • Day-to-day work — Regular work, Trail maintenance, Infrastructure, Points (points of interest), Lifts.
  • Office — Admin, Meeting, Training, Travel.
  • Time off — Holiday, Vacation, Sick, Other leave, Other. Kept separate so payroll can split paid work from leave on the same submission surface.

Trim the list per-org in Settings:

  • Settings → Expenses — copy: "Uncheck categories you don't use. Crew members will only see the enabled ones in the expense form."
  • Settings → Work hours — copy: "Includes time-off types (holiday, vacation, sick, other leave) alongside the regular work categories."

Leaving every box ticked (or every box unchecked) both mean "all enabled" — the server coerces the setting back to null so the default kicks in.

Mileage

Mileage is one of the expense categories, with its own UI branch and its own reimbursement rate.

When you pick Mileage on the expense form, the Amount input swaps for a Miles driven input (0.1–99999, step 0.1) and a read-only Amount field labeled with the current rate — e.g. "Amount ($0.73/mi)". A blue helper row confirms the math live: "12.5 mi × $0.73/mi = 9.13".

The org sets the rate in Settings → Expenses → Mileage reimbursement rate with the copy "Rate paid per mile when a crew member logs a mileage expense. Leave blank to use the default (0.73/mi)." Range: 0–9.9999, step 0.0001. If unset, the platform falls back to $0.73/mi.

The rate isn't retroactive. Historical mileage expenses keep whatever amount was computed at save time. Changing the rate tomorrow doesn't rewrite yesterday's mileage. The distance in miles is stored on the row alongside the amount so an auditor can always reconstruct what happened.

From map

Beside Miles driven is a From map button. It opens a map where you tap the stops you actually made — or search an address — and returns the real driving distance along roads rather than a straight line. Round trip is one tap, so the drive home counts, and a route you drive often can be saved and reused on the next claim.

It is available from Core upward. On Starter the button is still there and still opens: it shows what the feature does and what plan includes it, rather than sitting grayed out with no explanation. Typing the miles in by hand works on every plan and always has.

The approval workflow

Both work hours and expenses flow through the same four states: draft → submitted → approved | rejected.

  • Draft — the entry exists on your dashboard but nobody else can see it. If you leave it as a draft, it doesn't count toward reimbursement or payroll.
  • Submitted — you tapped Submit on the row (or Submit all in the banner on Week or Month views). Now it's in the approval queue.
  • Approved — a manager approved it. Green pill, included in every rollup.
  • Rejected — a manager rejected it with an optional review note. Red pill, excluded from expense rollups (see gotcha below), still visible to you so you can see why and re-submit.

Batch submit. On Week or Month views the top banner says "N drafts to submit" with a Submit all button. Fires up to 100 submissions in parallel.

Approvers open Review. The queue groups pending entries by member, each with a header showing count + total for that person. Each row has a yellow Review button that opens the inline panel:

  • Textarea for an "Optional note…" — required if you reject, optional if you approve.
  • Green Approve button.
  • Red Reject button.
  • Cancel to close without acting.

The rejection note is stored on the row and shown to the author so they know what to fix.

At the top of the queue: "N entries pending approval" + a green Approve all button. Fires parallel approve calls (no server-side batch for work hours; expenses have a real batch endpoint).

Nothing pings the submitter on approve/reject today — only submissions notify approvers (via the "Expense submitted for review" mail + push). Add checking the app to your weekly rhythm if you want to see rejections quickly.

Rollups — Day / Week / Month

Every view has a matching total strip at the top:

  • Day"Total: X.XX h" or "Total: X.XX" for expenses.
  • Week — grouped by day with a weekly total per user.
  • Month — three sections:
    • Monthly total — big blue banner.
    • By category — rows of "{category} · Nx · total" so the finance person can see where the money went.
    • Team summary — one row per crew member with a pending badge + their total. Only visible to approvers.

Expense month rollups exclude rejected rows. WorkHour rollups do not. The rationale is that a rejected expense stops being a real expense — it's not being reimbursed — so it doesn't belong in "money spent this month". A rejected work hour is still time worked, even if it wasn't approved for payroll, so it stays in the total.

Per-project rollup: every Project's Show page has a Hours worked tile — "12.5 h — Across N linked items, summed from the work log." This reads from quick time logs (per-issue), not from WorkHour payroll entries. So a project without quick time logs but with plenty of WorkHour entries can show 0 hours on the tile even though the crew has clearly worked on it. Ping if you want the tile to also read WorkHour — for now it's issue-time-logs only.

Org-wide Work report at /work-report — aggregates every quick time log by user, by trail, and by issue type over a rolling 30-day default window. CSV export.

Dashboard tile for approvers: "Expenses to review" stat with a click-through to the queue.

Editing and deleting

Same rule for both work hours and expenses:

  • Drafts — the author can edit or delete freely.
  • Submitted / approved / rejected — locked. Trying to edit shows "Only draft entries can be edited." / "Only draft expenses can be edited."
  • Delete — the author can delete their own drafts. Managers can delete any row regardless of state.
  • Expenses have one exception: the author can also delete their own approved expenses (edge case for reversing a reimbursement they later realize was a mistake).

Confirm dialogs: "Delete this entry?" / "Delete this expense?"

Quick time logs on maintenance issues: field workers can edit + delete their own; managers can edit + delete anyone's. No draft state — the log lands, it counts.

Platform admin acting-as — when a TrailsIQ platform admin is impersonating another user, entries they file are stamped to the target user, not the admin.

Photos and receipts

Only expenses attach a receipt image. One receipt per expense, up to 5 MB, JPG / PNG / WebP. Stored under expenses/{expense_id} on your org's storage. Thumbnails on the row open a full-screen lightbox.

Editing an expense lets you remove existing receipts and add new ones in the same save.

Receipt storage counts against your plan's storage quota. If your org is full, uploads fail with "plan_limit_reached" (HTTP 402). Free space (delete stale images) or upgrade in Billing.

Work hours and quick time logs have no photo attachment. Attach photos to a maintenance issue instead if you need visual documentation of the work.

Exporting for payroll or finance

Work hours exports as PDF:

  • Week export at /work-hours/week/export — the current week for the visible member (or all members).
  • Month export at /work-hours/month/export — the current month.

Reviewer signatures embed on approved rows (the reviewer's stored signature from their Profile → Signature setting). Both are one-click from the page header.

Expenses exports as PDF with more range flexibility:

  • Week export, Month export, and a Custom range export via the range picker in the page header. Range cap: 366 days, else "Range too large — pick a window of 366 days or less."
  • Rejected rows are excluded — the export is what someone hands to a finance department, so it must match the on-screen weekly total exactly.
  • Receipt images embed as base64 data URIs so the PDF renders offline in DomPDF without needing to fetch from storage.
  • Org logo embeds on the header.

Work report at /work-report/export.csv — every quick time log across the org for the selected window, columns: work_date, minutes, person, issue, trail, note. Great for reporting hours to a grant funder or a land manager.

If PDF export returns "PDF export is being provisioned — try again after the next deploy.", the DomPDF package isn't installed. Ping support.

Permissions

Two dedicated permissions gate the approval queues:

  • Approve work hours"Open the work-hours review queue, approve or reject submissions, see team-wide totals." Default on for Owner + Manager, off for Field worker + Volunteer.
  • Approve expenses — same shape. Default on for Owner + Manager.

Grant either to a specific field worker (via Members → Edit → Permission overrides on their row, or org-wide via Settings → Roles & permissions) if you want them helping the manager keep the queue clean.

View team-wide totals"See who-owes-what summaries on the Month views for hours + expenses. Read-only — does not include approval rights." Default off across the board. Grant to someone who needs to see the totals for reporting without giving them approval power (a bookkeeper, say).

Any active member can create their own entries — the log/submit flow is not permission-gated. No role can log for another crew member from the UI; only platform admins impersonating another user get that (and the entry is stamped as that user, not the admin).

Common gotchas

  • Drafts are invisible until you submit. Even to managers filtering by member. If a crew member "logs" but forgets to Submit, no reimbursement or approval happens. The field-app expenses list warns "You have N draft expense(s) waiting for approval — drafts aren't reimbursed." with a Submit all button.
  • Rejected expenses are kept, but leave the totals. The author still sees the red pill + review note, but the row is excluded from weekly / monthly totals, category breakdowns, team summary, and every PDF export. Rejected work hours DO stay in totals.
  • Task vs project link is exclusive. The picker offers one or the other, and sending both is refused with a message that says so rather than quietly keeping one.
  • Mileage rate isn't retroactive. Historical rows keep the amount computed at save time. Change the rate tomorrow and only new mileage expenses use the new rate.
  • Currency is per-entry, not per-org. The picker defaults to USD. A crew member traveling can log an expense in another currency; the finance team reconciles on export.
  • Quick time logs and work hours are separate. A quick time log on a maintenance issue does NOT create a WorkHour payroll entry. If a crew member wants payroll credit for the same time, they log it on /work-hours too. The Projects "Hours worked" tile reads quick time logs; the monthly work-hours page reads the payroll entries. They can disagree on the same day/task by design.
  • The submitter is told when a decision lands. Approved or not, whoever filed the expense gets a notification with the reviewer's note. It sits under Expense decision emails in Settings if somebody would rather not have it.
  • Field-app CREATE for quick time logs, expenses, and work hours goes through the offline outbox — enter offline and the entry queues; it syncs when signal returns. EDIT of an existing entry stays online-only (the row has to be loaded to edit anyway), so a mid-trail edit of yesterday's expense will fail if you're out of signal.
  • Expense reminders are per-user opt-in under Profile → "Expense reminders" (weekly / monthly, email / push). Turn them on if you have crew members who forget to submit.
  • Receipts count against org storage quota. Delete stale receipts (via edit → remove) if you're bumping the plan limit.
  • Custom-range expense exports are capped at 366 days. Longer than that, split into two.

What's next

  • Trim your expense and work-hour categories in Settings → Expenses / Work hours before your crew starts logging — the shorter list is faster to pick from and reads better on the PDF export.
  • Set your Mileage reimbursement rate now if you'll be reimbursing crew for driving. Once entries start landing at the default $0.73/mi, changing the rate won't retroactively fix them.
  • Grant the Approve work hours / Approve expenses permissions to a bookkeeper via Members → Edit → Permission overrides if you want the queue reviewed by someone who isn't a manager.
  • Read the Members, roles & permissions article for the full permission overrides workflow.
  • Read the Projects and work planning article to see how the per-project Hours worked tile is populated from quick time logs.