LockVentory started with Cameron's frustration: locksmiths carry hundreds of parts in their trucks, and there is no clean way to know what anyone has, what needs to be ordered, or what's running low without calling each tech individually. Cameron designed this app from scratch — every feature request in this document came directly from his field experience running Pop-A-Lock Louisville.
Challon built it. This document is a record of that collaboration.
LockVentory is built for multiple independent locksmith companies to share the same platform without
ever seeing each other's data. Every piece of data — folders, items, stock levels, service calls, orders —
is tagged to an org_id at the database level. Two orgs are active right now:
🔑 Holt's Lock & Key 🔒 Pop-A-Lock Louisville
Each company manages its own inventory, its own team, and its own suppliers. Cameron's data never touches Challon's, and vice versa — by design, forever.
The entire app runs on Cloudflare's edge network — no servers to maintain, no monthly compute bill, global availability. Every piece has a Star Wars code name so the real product name never appears in Cloudflare's dashboard (a naming convention we use across all projects):
| What It Is | Code Name | Real Role |
|---|---|---|
| CF Pages | tatooine | Frontend — the app you use in your browser/phone |
| CF Worker | kessel-run | Backend API — handles all data requests |
| D1 Database | cantina | SQLite database — all org/user/item/stock data |
| R2 Storage | sarlacc | File storage — item photos, QR codes |
A Progressive Web App (PWA) runs in the browser but installs and behaves like a real app — it lives on your home screen, works offline, and doesn't require an App Store submission. We chose this route because it ships fast, works on every phone (iOS and Android), and costs nothing to distribute.
The trade-off: a PWA can't do everything a native app can. This matters in one place — the in-app supplier browser (more on that in Section 4).
Public registration is closed. The signup page redirects to login and the API rejects any registration attempt. New users join via a unique invite link that an admin generates from the Team page. This keeps the platform clean — no random accounts, no test data from strangers.
Everything below came directly from Cameron's written feature requests. The outline follows the same structure he used — Global first, then Inventory, then Restock.
Cameron's words: "First and foremost, this app should not drop the page that you are on when you leave the app and come back to it a minute later."
Every navigation saves the current page to sessionStorage. When you re-open the app
(or switch back from another app), it restores exactly where you were. Works in both browser and
PWA standalone mode.
Cameron's words: "If several team members are linked to one company, there should be at least 1 admin account. The admin account should be able to set their permissions for if individual team members should be able to add folders and items to the inventory."
Cameron's words: "Team members should not be able to edit the stock of other team members."
All quantity write operations verify the requesting user owns that stock row. The API returns a 403 if the user_id on the record doesn't match the authenticated user. The frontend never shows +/− controls on another member's stock — Team Stock view is read-only for everyone else.
Cameron's words: "A small notification should show up at the bottom of the screen that confirms most changes."
Every write action (qty change, item add/edit/delete, folder change, order action, invite sent) fires a toast at the bottom of the screen. Auto-dismisses in ~2.5 seconds. Multiple toasts stack cleanly. Orange for success, red for error.
Inventory is organized in a folder tree. You navigate into folders the same way you'd browse files on a phone. The breadcrumb bar at the top always shows HOME › Folder › Subfolder — tap any crumb to jump back up. Folders with the dropdown option set render as collapsible sections instead of a new page.
Checkboxes let you toggle Show Item Count and Show Quantities on folder rows.
Two tabs on the Inventory toolbar. My Stock shows your personal quantities. Team Stock shows every team member's quantity for every item in the current folder — the killer feature Cameron designed the whole app around.
The search button opens a search box with:
Opens a sheet with: folder name (required), optional description, color picker (preset palette), icon picker (preset icons or photo from camera/gallery), and a toggle to show this folder's subfolders as dropdowns instead of navigating to a new page.
Opens a multi-step sheet with:
LV-XXXXXX (no ambiguous characters)Note: "Recommended autofill" (AI that fills in item details from the name) was deferred by Cameron — "we'll get into that later." The field is stubbed in the UI.
Tapping an item in a folder opens a quick popup with:
The item detail sheet shows all data about the item (name, ID, QR code, description, icon/photo, supplier link, your quantity, team quantities) with options to edit or change qty via manual entry or +/−. There's also an "Add to To Be Ordered" button that sends the item straight to the Restock tab.
Cameron's words: "This shows your entire inventory as a series of dropdown folders, and + or − or low/med/high — which allows you to manually adjust quickly your entire inventory."
Tapping Run Inventory opens a full-screen mode showing every folder and item in the org. Folders are collapsible. Each item shows its current quantity or stock level with inline +/− or L/M/H controls. Changes save immediately (debounced). A toast confirms each save. Exit button returns to normal view.
Cameron's words: "Edit mode button — allows reorganizing of folder (3 dots on the left), allows selection of items or folder — delete selection, move selection."
The Changelog button on the Inventory toolbar opens a live audit log of every quantity change, item creation, and deletion — showing who made the change, what changed, old value → new value, and when. Filterable by team member and entity type. Paginated.
Shows all items that are at or below their minimum reorder quantity, or at Low/Medium stock level. Each row has:
Manual refresh button and a Changelog button scoped to quantity changes.
Your running order list. Items are grouped by supplier. Each supplier group shows:
Clicking an item opens a supplier dropdown showing all linked suppliers for that item with their prices. Clicking a supplier moves the item under that supplier's group in the Order List.
Cameron's words: "Shows a list of preset suppliers — lets you add your suppliers and login to accounts with them, without closing the app, have it run it on top."
Cameron's words: "AI reads the prices on the sites, does the math, and then moves all items to the Order List with recommended sites to order from based on the items."
The ✨ Optimize button automatically assigns the cheapest in-stock supplier to every item in the order list and groups them accordingly. A toast shows how many items were matched and how many had no supplier linked.
Every time you mark a supplier group as Ordered, a snapshot is saved — which items, which supplier, what qty, who placed it, and when. Order History button shows a paginated log of all past orders.
Log service calls with job type, status, notes, and the parts used on each call. Part usage deducts from your personal stock. Calls are listed with filter and sort; each call has a full detail view.
A searchable, filterable view of all parts in the org — separate from the folder-based inventory. Useful for looking something up quickly without navigating the folder tree.
Admin-only Team page shows all members with their role, join date, and permission toggles. Invite new members via a unique link. Remove members. Enforce minimum 1 admin rule.
Full in-app help guide at /help. Covers every feature with step-by-step instructions, callout boxes, a glossary of locksmith terms, and a permissions reference table. Sticky sidebar navigation on desktop, scrollable on mobile.
LockVentory installs to your home screen on iOS and Android. A service worker caches the shell so the app opens even without signal. Pull down on any page to refresh (the only way to refresh in standalone mode — there's no browser toolbar). App icon: orange lock on dark background.
Three features in Cameron's original spec ran into technical walls. Here's what we built instead, and what a full solution would actually require.
What we built: The Add to Cart button opens the supplier's website in a new tab and simultaneously copies your item list for that supplier to the clipboard — formatted and ready to paste. One tap, supplier site opens, you paste the list and work from there.
Why true auto-cart isn't possible yet:
site.com/cart/add?id=SKU&qty=2 — but only if you know the exact SKU on their platform for each item you carry. We'd need to store a per-item, per-supplier SKU alongside the price.What it would take to do it for real:
https://{supplier}/cart/add?id={sku}&quantity={qty}. We'd need to research and hardcode the template for each supported supplier.What we built: The ↗ Open button on any supplier slides up a full-screen panel with the supplier's website loaded inside it. You stay in LockVentory — the panel sits on top. Log in, browse, shop, then close it.
The limitation: This uses an <iframe> — technically a browser window embedded inside another browser window. Many supplier sites (and most large brand websites) intentionally block this using a security header called X-Frame-Options: DENY. It's an anti-phishing measure — they don't want their login page embedded inside someone else's site. We can't override it from our side. When it's blocked, LockVentory shows an "Open in browser" fallback button.
What a full solution requires:
WKWebView on iOS, Custom Tabs on Android) that behaves like Safari or Chrome but stays inside the app. These aren't blocked by X-Frame-Options. This is how apps like Amazon, DoorDash, and most shopping apps handle external payment pages. It's the right long-term answer if LockVentory goes native.What we built: The Optimize button runs the math on prices you've entered manually in the item-supplier links. It finds the cheapest in-stock supplier per item and groups the order list accordingly instantly.
Why live AI price reading isn't built yet:
What it would take to do it for real:
Cameron explicitly flagged two features as "we'll get into that later" in his original spec. They're not forgotten — they're just waiting for the right time.
| Feature | What It Is | What It Needs |
|---|---|---|
| AI Autofill 🔮 Future | When adding an item, type the name and AI pre-fills description, common icon, typical min reorder qty, and known suppliers. | A product knowledge base + Claude API call on the add-item sheet. The API key is already wired in — this is a few hours of work when Cameron says go. |
| Preset Templates 🔮 Future | New orgs can preview and apply a starter folder structure with common locksmith item categories pre-loaded instead of building from scratch. | A template library (JSON definitions of folder trees + common items) and an import flow on the Inventory page. The hardest part is curating good templates. |
| Native App 🔮 Future | True iOS/Android app instead of a PWA. Unlocks: real in-app browser, push notifications, barcode scanner integration, offline sync with conflict resolution. | React Native or a native build. All the backend API stays the same — the app just talks to the same Cloudflare Worker it does now. Front-end only rebuild. |
| Supplier API Integration 🔮 Future | Direct ordering through LockVentory — no browser, no cart. Place the order from the app and get a confirmation number back. | Dealer API accounts with IDN Hardware, HPC, or whichever suppliers Cameron uses most. Then backend order submission endpoints. Most of the order-list data model is already in place. |
| Live Price Feeds 🔮 Future | Prices in the item-supplier links update automatically instead of being entered manually. | Supplier EDI/data feeds or API pricing endpoints. Same dependency as full ordering. The Optimize engine is already built — it just needs live data piped in. |
| Feature | Status | Notes |
|---|---|---|
| Page state persistence | ✅ Done | Saves + restores on every navigation |
| Admin + permissions system | ✅ Done | Per-member toggles, enforced server-side |
| Team stock isolation | ✅ Done | API rejects writes on other users' stock |
| Toast notifications | ✅ Done | Bottom of screen, all write actions |
| Folder navigation + breadcrumbs | ✅ Done | Nested folders, dropdown option, crumb nav |
| My Stock / Team Stock tabs | ✅ Done | Team view is read-only for non-owners |
| Search & filter | ✅ Done | Scoped + full-org, multi-field filter |
| Add Folder | ✅ Done | Color, icon, dropdown toggle |
| Add Item | ✅ Done | Unique ID, QR code, supplier URL, name merge |
| Item popup + detail sheet | ✅ Done | View, duplicate, qty adjust, add to order |
| Duplicate item/folder | ✅ Done | Popup button + edit mode action |
| Run Inventory mode | ✅ Done | Full-screen rapid qty update |
| Edit mode — drag reorder | ✅ Done | Touch drag with ghost + placeholder |
| Edit mode — move selection | ✅ Done | Full folder tree picker |
| Edit mode — delete selection | ✅ Done | Admin only, re-parents folder contents |
| Inventory changelog | ✅ Done | Full audit trail, filterable by user/type |
| Low Stock tab | ✅ Done | Min-qty and LMH thresholds, add to order |
| To Be Ordered tab | ✅ Done | Grouped by supplier, supplier picker per item |
| Suppliers system | ✅ Done | Presets + custom, in-app webview |
| In-app supplier browser | ⚠️ Partial | Works for most suppliers; blocked by some large sites |
| Add to Cart | ⚠️ Partial | Opens site + copies item list to clipboard |
| Optimize Order | ⚠️ Partial | Runs on manually-entered prices, not live data |
| Order History | ✅ Done | Paginated, per-supplier snapshots |
| Service Calls | ✅ Done | Log + parts used + status |
| Parts Catalog | ✅ Done | Search/filter across all org items |
| Team management + invites | ✅ Done | Invite link, roles, permissions |
| Invite-only registration | ✅ Done | API + frontend gated, signup page redirects |
| PWA — install + offline + PTR | ✅ Done | Works on iOS + Android home screen |
| Help documentation | ✅ Done | Full guide at /help |
| AI item autofill | 🔮 Future | Cameron deferred — API key already wired |
| Preset inventory templates | 🔮 Future | Cameron deferred |
| Native iOS/Android app | 🔮 Future | Full in-app browser, push notifications |
| Supplier order API | 🔮 Future | Needs dealer API accounts with suppliers |
| Live supplier price feeds | 🔮 Future | Needs supplier EDI or API pricing |
LockVentory · Built June 2026 · Admin-only document