Team
Inventory — stock, assets, checkouts, and reservations
Manage the org's shared catalog of tools, lumber, and gear — consumable stock with per-location counts, assets with checkout / check-in, low-stock alerts, reservations against in-progress maintenance items, and a full field-app surface for the shelf and the trail.
Inventory is your org's shared catalog of physical things — tools, lumber, hardware, signs, safety gear, machinery — with per-location quantities for consumables and check-out / check-in for equipment. Every crew member can answer "how much 2×4 do we have at the East Trailhead?" or "who has the chainsaw right now?" from either the dashboard or the field app.
What inventory is in TrailsIQ
Every inventory row is one kind of thing — "2×10 pressure-treated lumber", "Stihl MS 261 chainsaw", "trail-closed signs" — with quantity tracked separately per storage location. When you create an item you pick one of two tracking modes and the item stays in that mode for its whole life:
- Stock count — "Consumables and bulk materials. Track per-location quantities and adjust on counts." Best for anything you count in units, feet, gallons, or bags — lumber, screws, gravel, paint, trail-marking flagging.
- Single asset — "Equipment like a chainsaw or ATV. Set a home location and check it out / in." Best for things one person takes out at a time. The name is slightly misleading: you can set
How many do you own?above 1, so a fleet of five identical shovels can share one asset row.
Two very different workflows behind the same catalog. Consumables get counted, moved, and consumed. Assets get taken out, taken back, and their trip history recorded.
Setting up storage locations
Locations are where inventory lives — the shop, a shed at the trailhead, a job trailer, a gravel cache. Manage them under Settings → Storage locations.
Copy on the page: "Shops, trailers, caches, trailheads — where inventory lives." Under the create form: "Physical spots where your crew stores tools, lumber, signs, and other gear. Inventory items link to these locations so you can answer 'how much 2×4 do we have at the East Trailhead?' at a glance."
Fields:
- Name — required, unique per org, placeholder "Name (e.g. Main Shop)".
- Type — fixed enum: Shop / Warehouse / Shed / Container / Yard / Cache / Trailer / Trailhead / Office / Other.
- Address — optional.
- Lat / Lng — optional; used if you want the location to show on the map.
- Notes — optional.
- Is archived — hides from the default picker without deleting.
Deleting a location with stock still on it fails. Confirmation dialog and server both refuse: "This location still has inventory. Move or remove the stock rows first." Empty the location's stock (or move it elsewhere) before you delete.
Set up your handful of real locations before creating items — the create form's Initial stock field on stock items needs at least one location to be useful.
Categories (and custom categories)
Category is a plain string. Every org ships with these defaults:
Tools · Lumber · Hardware & Fasteners · Trail Materials · Signage · Consumables · Safety & PPE · Equipment & Machinery · Other
The defaults are always available. To add your own — "Wire rope", "Fasteners (galvanised)", "Prescribed-fire kit" — click Manage categories on the inventory Index page. Side panel titled "Inventory categories" with the copy "The defaults are always available. Add your own to fit your workflow — they'll show up in the picker both here and in the field app."
Categories drive the picker on the create form and the filter chip on the Index page. That's it — no per-category custom fields, no per-category permissions, no category-specific reports. The Lumber category is the one exception: picking it reveals a Lumber-dimensions fieldset (see the Every field on the form section) so the bridge-materials calculator can match your stock against a bridge design.
Creating an inventory item
Manager-only. Field workers and volunteers see the inventory list read-only unless the Manage inventory permission is granted to them (which it is by default for field workers, off for volunteers).
Click + Add item on the Index page. Same form covers create + edit. Landing on save goes to the item's Show page.
Every field on the form
- Tracking mode — two radio tiles: Stock count and Single asset. Pick before anything else — the rest of the form changes shape.
- Name — required, up to 120 characters, unique per org.
- Category — pick from the org's effective list (defaults + your custom additions).
- Unit — stock mode only, up to 20 characters. Placeholder "pcs, ft, gal…". Defaults to pcs. This is what shows next to the quantity everywhere ("6.5 gal", "24 pcs").
- Home location — asset mode only. Pick where the asset lives when it's not out. First option: "No home location set" — fine if the fleet doesn't have a permanent home.
- How many do you own? — asset mode only, integer 1–9999. Helper: "Use 1 for a single tool; bump it up for several of the same (e.g. five identical shovels)."
- Low-stock threshold — stock mode only, optional. Placeholder "Leave blank to skip alert". When on-hand crosses from above to below this number, managers get a push notification (see Low-stock alerts).
- Lumber dimensions — appears only when Category = Lumber. Helper: "Fill these in so the bridge calculator can spot this stock when it computes what you need." Sub-fields:
- Lumber type — pick from the built-in list, or add custom lumber types.
- Nominal label — display tag ("2×10"). Helper: "Just a display tag — the actual mm values below are what the calculator matches against."
- Length / Thickness / Board width — each respects the viewer's unit preference (imperial or metric).
- Description — free text up to 2000 characters. Where it lives on the shelf, any peculiarities.
- Photo — one image, up to 5 MB, JPG / PNG / WebP. Optional on create. Existing items get instant API upload with Upload photo / Replace photo / Remove buttons. Remove confirms "Remove this photo?".
- Initial stock (create + stock mode only) — pair a location select with a quantity so you don't have to open the item afterwards to seed a starting count. Warning when the org has no locations yet: "Add a storage location first if you want to log a starting quantity now."
- Archive (hide from default list) — edit only. Ticks the item off the Index unless the Archived filter is on.
- Delete — edit only, manager. Confirm:
Delete "{name}"? Stock rows will be removed too.
Stock — consumables with per-location counts
Stock items track quantity separately per storage location. So 2×10 lumber might be 84 pcs at the Main Shop, 12 pcs at the East Trailhead cache, and 0 pcs at the Job Trailer. The Show page renders a Stock by location card with one row per location, each with a numeric input for the current qty, a Move button, and a last-counted timestamp with the counter's name.
Empty state: "No stock recorded yet. Add a location below."
Any active org member with view_inventory can adjust counts. You don't need Manage inventory. Setting a fresh value writes an audit row (kind = count) so the whole history of counts is queryable — helpful when auditing "when did we last actually walk out to the cache and count?".
Setting vs adjusting: the count API accepts either quantity: X (set to exactly X) or delta: N (add N — negative for consumption). The field app uses delta for the ± buttons and quantity for the manual input; the dashboard uses quantity.
Every non-zero change writes an InventoryMove audit row. So a bump from 84 to 60 records "consumed 24" with the actor and timestamp attached.
Assets — checkouts (who has what)
Asset items don't have per-location stock. Instead they have an at-home count vs an out count — one InventoryCheckout row per "trip out and back". Open row = returned_at is null = it's out.
The Show page's CTA card is titled Take it out with the copy "Record who's taking the {item name}, where, and what for. Anyone in the org can see it's gone (and where it went)."
Fields:
- How many? — only appears when
total_owned > 1. Max = the number currently at home. Helper "Max N (the rest stay at home)." - Who's taking it — dropdown starting with Me ({your name}), followed by every active org member. Helper "Pick someone else if you're checking it out on their behalf."
- Where is it going? — free text, placeholder "e.g. North trailhead". Helper "A place description — doesn't have to be a defined storage location."
- What for? — optional textarea, placeholder "e.g. bridge build at South Loop".
Submit button reads Take it out (or Recording… while in flight).
Concurrency-safe. If two people race to check out the last unit, one wins and the other sees "None available — all are already checked out." or "Only N available right now." — the DB row lock prevents overselling.
Bringing it back. An open checkout shows an amber Currently out card with a Bring it back button (Bringing it back… while saving). Optional return-notes textarea, placeholder "Any notes on return? (optional)". Multiple open trips per item are allowed when total_owned > 1; the return call needs to name which trip to close.
Trips section on the Show page — "Past and present check-outs. Newest first." — shows the last 50 rows.
No due dates. Assets don't carry an expected-return date, so there's no overdue flag. If tracking that matters for your org, put the return date in the "What for?" text or file a follow-up maintenance issue.
Moving stock between locations
The Move button on any stock row opens a sheet titled Move stock with the header "Move from {source} (on hand: X unit)". Pick a destination location and a quantity to shift.
Runs in a DB transaction with row locks so a race between two crew members moving from the same location can't oversell. Writes two audit rows linked by a batch UUID (one debit at source, one credit at destination, kind = move).
Refuses if the source doesn't have enough: "Source location does not have enough stock to move."
Low-stock alerts
Set Low-stock threshold on any stock item — when a count crosses from at-or-above to below the threshold, an InventoryLowStock push notification fires to every manager and owner.
Push title: "Inventory low". Body: "{Item name} is at {qty} {unit} (threshold {threshold})".
Fires only on the crossing, not on every count below threshold. So a session of counting 3 shovels three times in a row doesn't spam three notifications. Once you re-stock above the threshold and the next count drops back below, the notification fires again.
Crossings back up above the threshold are silent — the amber Low pill on the Index list handles that visually, and re-notifying "we're OK now" adds noise without action.
Linking inventory to a project or maintenance item
The Show page's Used in card lets managers link an item to specific projects or maintenance tasks with a planned quantity. Empty state: "Not linked to any projects or maintenance tasks yet."
Form (manager only):
- Type — Project or Maintenance.
- Target — pick a project ("Pick a project" / "No projects yet") or an open task ("Pick a task" / "No open tasks").
- Planned qty — integer.
- Notes — optional.
Submit Add link (Linking… while in flight). Unlink asks Unlink "{target}" from this item?.
Reservation math applies when the linked target is a maintenance issue with status in progress:
- The link's
planned qty − consumed qtyis subtracted from the item's on-hand count. - The Show page renders a blue Reserved by card listing each in-progress reservation with an "In progress" pill and "X of Y already drawn" text.
- The Index page's On hand cell shows the available number first, with a blue Available chip and a subline "X reserved · Y on hand".
So a shovel item with 5 on hand, linked to an in-progress bridge-build maintenance issue with planned=2, consumed=0, reads as 3 available (2 reserved · 5 on hand) on the Index page. When the crew draws the shovels for the bridge build, they update consumed on the link and the reservation shrinks.
Project links never reserve. Only in-progress MaintenanceIssue links do. Project links are informational only — useful for reporting ("how much lumber is planned for the Spring Rehab project?") without holding stock.
The inventory Index page
Route: /inventory. Header title: Inventory. Header actions (right side):
- Manage categories — manager only.
- Locations — manager only, jumps to Settings → Storage locations.
- Export PDF — visible to any inventory viewer.
- + Add item — manager only.
Filter bar underneath:
- Search (placeholder "Search items…").
- Category select ("All categories" default).
- Lumber-type sub-select — only appears when Category = Lumber AND matching items exist ("All lumber types" default).
- Location select ("All locations" default).
- Low stock checkbox — filter to items below threshold.
- Archived checkbox — include archived rows.
Desktop table: Item (with a 40×40 photo thumbnail), Category, On hand, Locations. Row is clickable → jumps to the item's Show page. Mobile view is a stacked card list.
Row pills:
- Assets: green At home with the home-location name, or amber Out with the assignee.
- Multi-unit fleets: "3/5 at Main Shop" with a "2 out" chip.
- Stock rows: quantity + unit.
- Low-stock items: amber Low chip.
- Items with in-progress reservations: blue Available chip.
Empty state: "No items yet. Add the first one." — the CTA link only renders for managers; everyone else just sees the copy.
No bulk-select checkboxes. No bulk edit, no bulk move. Every edit is one row at a time. Fine for the typical org's 50–200 SKUs; larger fleets would want batch tools we haven't built yet.
Field-app inventory
The Field App has the full inventory surface — the home tab has an Inventory tile that opens a slide-in panel with three views:
- List — grouped by category, with the same search + category + location filters as the dashboard. Lumber-type filter appears when Lumber is selected.
- Item detail — same Stock by location / Take it out / Bring it back / Trips affordances as the dashboard.
- New item / Edit item — manager only, same form as the dashboard.
Big touch-friendly − / + buttons for adjusting stock, plus a manual qty input. Every stock row has a Move to another location button.
Managers with manage_inventory also get a + quick-add button labeled "New inventory item" in the panel header.
Share PDF — where the device supports it (iOS + Android native shells), the panel offers a Share button that opens the OS share sheet with the inventory PDF attached. Useful for firing off a stock snapshot to a partner or a grant funder from the trail.
Empty states: list empty and no filters — "Nothing matches. Tap + Add to create the first inventory item." Empty stocks on an item — "No stock recorded yet. Tap a location below to add some." Offline — "You're offline. Inventory will refresh once you're back online."
Working offline: almost everything in Inventory saves without a connection. Counts, the +/− buttons, moving stock between locations, editing an item, adding or removing an item photo, and editing a location all go into your queue and upload by themselves once you have signal. You get a green line confirming it on the screen you made the change from, the number you set shows straight away rather than the old one, and the pending badge in the header counts it — tap that to see everything waiting, item by item.
Two things need a connection and say so when you try: adding a new storage location, because stock cannot be assigned to a location that does not exist on the server yet, and deleting one, because that has to check whether stock is still assigned to it first.
Offline create: tapping + New inventory item while offline still works — the item is queued in the field-app outbox and lands on the server the next time the device gets signal. The row shows in the list with a blue Pending badge and is disabled for detail-tap until it syncs. A photo attached to the create rides along in the queue and uploads once the item exists, and the initial Add quantity (seed-stock) is folded into the same POST so a queued create → sync lands the item AND the starting count atomically.
Photos, cost tracking, barcodes
Photos — one photo per item, up to 5 MB, JPG / PNG / WebP. No gallery, no annotations. The photo shows as a 40×40 thumbnail on the Index list and full-size on the Show page.
Cost tracking — not built. No unit cost, no total value, no per-project spending rollup. If you need to answer "how much did we spend on lumber in Q2?", the closest surface today is the Expenses dashboard (Category = Supplies or Tools) rather than inventory.
Barcode / QR — not built. No barcode field, no QR generation for tagging shelves. If those matter for your ops, tell us.
Permissions
Two permissions in the catalog:
- View inventory — "See the inventory list, item details, stock counts and asset-checkout status. Required to use any of the inventory surfaces. Counting stock and checking assets in/out are allowed for anyone with this right."
- Manage inventory — "Create new items + storage locations, edit catalog rows (name, category, photo), delete items, manage the org's custom-category list. Counts and check-outs/-ins stay open to anyone who can see the inventory."
Defaults: Owner + Manager + Field worker get both TRUE. Volunteer gets both FALSE.
Counting and checking assets in/out are open to anyone with View inventory — not gated behind Manage. This is deliberate — the crew member at the shelf can update the count and the crew member with the chainsaw can log the checkout, without needing to bother a manager.
If you want volunteers helping with counts, grant them View inventory on their row (or in Settings → Roles & permissions if you want it default-on for the whole role).
Sidebar link only shows for viewers with the permission. Storage locations link (Settings → Storage locations) is gated by View inventory too.
Common gotchas
- Tracking mode is one-way — pick Stock or Asset at create time and it sticks. If you accidentally created an asset item that should have been stock (or vice versa), the fix is delete + re-create.
- Deleting a storage location is blocked while stock rows still reference it. Move or zero-out the stock first.
- Deleting an item cascades its stock rows. Confirm reads "Stock rows will be removed too." Loss of history — if you might need the audit trail, archive instead of delete.
- You can't shrink the number owned below the number currently checked out. API returns "Can't reduce total below N — that many are currently checked out." — wait for the trips to close (or record returns) before shrinking the fleet.
- Removing an activity-log entry does NOT undo the stock change. Confirm literally says "Remove this activity entry? This only forgets the log line — the stock change itself stays as it is." Adjust the count separately if you also want to reverse the number.
- Lumber measurements belong to the Lumber category. Move an item to a different category and they are removed on save — the edit page warns you before you save, so it is not a surprise.
- Low-stock alerts fire only on the crossing. Repeated counts below threshold are silent (no spam). Crossing back up is also silent — the amber Low pill on the Index list is the ongoing signal.
- Project links never reserve stock — only in-progress
MaintenanceIssuelinks do. Link an item to a project for reporting and to a specific maintenance task if you want the reservation math to kick in. - Field workers can count stock and check assets in/out by default. Only creating / editing / deleting the catalog row itself needs Manage inventory. That's a feature — the person at the shelf shouldn't need a manager to update a count.
- No cost tracking, no barcodes. If your ops needs either, work around: use the Expenses dashboard for spending totals, print labels externally and stick them on shelves.
What's next
- Set up your handful of real storage locations before creating items. Empty locations later is more work than getting them right upfront.
- If you'll be using the bridge calculator, tag Lumber items with the dimension fields on the create form — the calculator matches millimetre-for-millimetre against your stock.
- Grant View inventory to volunteers if you want them helping with counts on volunteer days — they can adjust counts without being able to touch the catalog.
- Read the Members, roles & permissions article for the per-user override workflow (grant / revoke Manage inventory on a specific person).
- Read the Projects and work planning article to see how linked inventory reservations show up on the Project's Show page.