← Back Blueprint ✕

LockVentory Blueprint

A full account of what we set out to build, what we built, where we had to get creative, and what still lies ahead. Written for the team, by the team — Cameron & Challon, June 2026.

Section 1 — The Idea

Where It Started

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.

The Core Problem

  • Locksmiths track parts mentally or on paper — neither scales when you have multiple techs.
  • When a job requires a specific part, nobody knows if it's on the truck or back at the shop.
  • Reordering is reactive. You run out, then you order. There's no early warning system.
  • Every supplier has a different website, a different login, and there's no unified shopping list.

The Multi-Company Design

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.

Why this matters
Cameron wanted LockVentory to work for any locksmith company — not just one shop. The multi-tenant architecture means we can add any number of companies later without rebuilding anything. Invite-only registration means we control exactly who gets in.

Section 2 — The Stack

Why Cloudflare

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 IsCode NameReal Role
CF PagestatooineFrontend — the app you use in your browser/phone
CF Workerkessel-runBackend API — handles all data requests
D1 DatabasecantinaSQLite database — all org/user/item/stock data
R2 StoragesarlaccFile storage — item photos, QR codes

Why a PWA, Not a Native App

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).

Invite-Only Registration

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.


Section 3 — Feature by Feature

Everything below came directly from Cameron's written feature requests. The outline follows the same structure he used — Global first, then Inventory, then Restock.

Global Features

Page State Persistence ✅ Done

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.

Admin Account + Permissions System ✅ Done

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."

  • Every org requires at least one admin — the last admin cannot be demoted.
  • Admins can toggle Can Add Folders and Can Add Items per member from the Team page.
  • The API enforces these permissions server-side — a member can't bypass them by calling the API directly.
  • The frontend hides or disables Add Folder / Add Item controls for members without the permission.

Team Stock Isolation ✅ Done

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.

Toast Notification System ✅ Done

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

Folder Navigation + Breadcrumbs ✅ Done

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.

My Stock / Team Stock Tabs ✅ Done

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.

Search & Filter ✅ Done

The search button opens a search box with:

  • Scope dropdown: search all folders or current folder only
  • Field filters: name, description, tags (any combination)
  • Results show the folder path so you know exactly where each item lives
  • Updates live as you type

Add Folder ✅ Done

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.

Add Item ✅ Done

Opens a multi-step sheet with:

  • Item name + optional description
  • Icon picker (preset icons or photo from camera/gallery)
  • Quantity type: use a numeric quantity + minimum reorder threshold, or use Low/Med/High stock indicators
  • Supplier URL field (link directly to the item on a supplier's website)
  • Name merge check: if another item in any folder has the same name, the app warns you and shows its unique ID so you can decide whether to merge
  • Auto-generates a unique ID in the format LV-XXXXXX (no ambiguous characters)
  • Auto-generates a QR code encoding that unique ID — with a print option

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.

Item Row Popup + Item Detail Sheet ✅ Done

Tapping an item in a folder opens a quick popup with:

  • View — opens the full item detail sheet
  • ⧉ — duplicates the item instantly into the same folder
  • + / − buttons for quantity items
  • Low / Med / High toggle for stock level items

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.

Run Inventory Mode ✅ Done

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.

Edit Mode — Reorder, Duplicate, Move, Delete ✅ Done

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."

  • ⠿ drag handle on the left of every row — press and hold to drag, placeholder shows where it will land, saves automatically on release
  • Checkboxes on every row for multi-select (mix of items and folders)
  • Action bar appears when items are selected:
    • Duplicate — copies all selected items/folders in place with "(Copy)" suffix and new unique IDs
    • Move — opens the full folder tree picker, moves everything at once
    • Delete — confirm prompt, removes items permanently, re-parents folder contents so nothing inside is lost

Inventory Changelog ✅ Done

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.

Restock

Low Stock Tab ✅ Done

Shows all items that are at or below their minimum reorder quantity, or at Low/Medium stock level. Each row has:

  • + button to add to the To Be Ordered list (with optional manual qty entry)
  • Inline quantity adjust
  • Checkmark indicator when the item has already been added to To Be Ordered

Manual refresh button and a Changelog button scoped to quantity changes.

To Be Ordered Tab ✅ Done

Your running order list. Items are grouped by supplier. Each supplier group shows:

  • Every item assigned to that supplier, with quantity and price (if set)
  • Out of stock badge when a supplier has marked the item OOS
  • 🛒 Add to Cart button (see workaround note in Section 4)
  • ✓ Ordered button — marks the group as placed, removes from list, saves to Order History

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.

Suppliers System ✅ Done ⚠️ Caveat

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."

  • Preset suppliers built in: IDN Hardware, HPC Inc, Major Lock, Medeco, Schlage, Kwikset, Corbin Russwin, Arrow Lock
  • Add custom suppliers (name + URL) any time
  • ↗ Open button slides up a full-screen in-app browser panel so you can log in and shop without leaving LockVentory
  • If a supplier's site blocks the in-app browser (a security header some sites use), a "Open in browser" fallback appears
  • Closing the panel returns you to exactly where you were
Caveat: The in-app browser is an iframe — a browser-inside-a-browser. Some suppliers (especially large brand sites) block this intentionally. See Section 4 for what a full solution would look like.

Optimize Order ✅ Done ⚠️ Caveat

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.

Caveat: Optimization runs on prices you've entered manually — not prices pulled live from supplier websites. Live price scraping is technically hard and legally gray (most suppliers block automated access). See Section 4 for the full picture.

Order History ✅ Done

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.

Infrastructure & Other Pages

Service Calls ✅ Done

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.

Parts Catalog ✅ Done

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.

Team Management ✅ Done

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.

Help Documentation ✅ Done

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.

PWA — Install, Offline, Pull-to-Refresh ✅ Done

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.


Section 4 — Where We Had to Get Creative

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.

Add to Cart — Automatic vs. Manual

What Cameron envisioned
"A 'add to cart' button is listed at the bottom of each supplier category, which will direct you to their site and add the items to the cart."

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:

  • Every supplier website is built differently. There is no universal "add to cart via URL" standard.
  • Some e-commerce platforms (Shopify, BigCommerce) support cart URLs like 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.
  • Larger distributors (Assa Abloy / Allegion dealer portals) offer actual order APIs — but you have to apply for dealer API access, and most small/mid-size locksmith suppliers don't have one at all.

What it would take to do it for real:

  1. Supplier SKU field — when you link an item to a supplier, also store the SKU from that supplier's catalog.
  2. Per-supplier cart URL template — for Shopify suppliers: https://{supplier}/cart/add?id={sku}&quantity={qty}. We'd need to research and hardcode the template for each supported supplier.
  3. Or: a dealer API account — if IDN Hardware or HPC Inc offers a B2B API to their dealer accounts, we'd connect LockVentory to it and submit orders directly. No clicking required.

In-App Supplier Login — Iframe vs. Native Browser

What Cameron envisioned
"Lets you add your suppliers and login to accounts with them, without closing the app, have it run it on top."

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:

  • A native iOS/Android app — native apps can open URLs in a proper in-app browser (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.
  • In the meantime: the iframe works fine for most smaller supplier sites. The ones that block it are typically the bigger brands that you'd probably rather have open in a full browser session anyway (persistent cookies, saved passwords, etc.).

Optimize Order — Manual Prices vs. Live Scraping

What Cameron envisioned
"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."

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:

  • Most supplier sites actively block automated access (bot detection, CAPTCHAs, JavaScript-only rendering).
  • Price scraping is legally murky — some supplier Terms of Service explicitly prohibit it.
  • Scraping is brittle. A supplier redesigns their site, the scraper breaks, and your order data becomes wrong without warning.
  • Running a headless browser to scrape prices would require a separate server and cost real money per query.

What it would take to do it for real:

  1. Supplier price feeds / EDI — the cleanest approach. If a supplier provides a pricing CSV, data feed, or EDI connection to dealer accounts, we'd ingest that on a schedule (nightly) and keep prices current automatically. No scraping, no terms of service issues.
  2. Supplier API access — same as the cart situation. If IDN or HPC has a dealer API that includes pricing endpoints, we connect to it.
  3. Manual is actually fine for now — locksmith part prices don't change daily. Updating prices a few times a year when you get a quote keeps Optimize accurate enough to be genuinely useful.

Section 5 — What Cameron Deferred (Future Features)

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.

FeatureWhat It IsWhat 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.

Section 6 — Status Summary

FeatureStatusNotes
Page state persistence✅ DoneSaves + restores on every navigation
Admin + permissions system✅ DonePer-member toggles, enforced server-side
Team stock isolation✅ DoneAPI rejects writes on other users' stock
Toast notifications✅ DoneBottom of screen, all write actions
Folder navigation + breadcrumbs✅ DoneNested folders, dropdown option, crumb nav
My Stock / Team Stock tabs✅ DoneTeam view is read-only for non-owners
Search & filter✅ DoneScoped + full-org, multi-field filter
Add Folder✅ DoneColor, icon, dropdown toggle
Add Item✅ DoneUnique ID, QR code, supplier URL, name merge
Item popup + detail sheet✅ DoneView, duplicate, qty adjust, add to order
Duplicate item/folder✅ DonePopup button + edit mode action
Run Inventory mode✅ DoneFull-screen rapid qty update
Edit mode — drag reorder✅ DoneTouch drag with ghost + placeholder
Edit mode — move selection✅ DoneFull folder tree picker
Edit mode — delete selection✅ DoneAdmin only, re-parents folder contents
Inventory changelog✅ DoneFull audit trail, filterable by user/type
Low Stock tab✅ DoneMin-qty and LMH thresholds, add to order
To Be Ordered tab✅ DoneGrouped by supplier, supplier picker per item
Suppliers system✅ DonePresets + custom, in-app webview
In-app supplier browser⚠️ PartialWorks for most suppliers; blocked by some large sites
Add to Cart⚠️ PartialOpens site + copies item list to clipboard
Optimize Order⚠️ PartialRuns on manually-entered prices, not live data
Order History✅ DonePaginated, per-supplier snapshots
Service Calls✅ DoneLog + parts used + status
Parts Catalog✅ DoneSearch/filter across all org items
Team management + invites✅ DoneInvite link, roles, permissions
Invite-only registration✅ DoneAPI + frontend gated, signup page redirects
PWA — install + offline + PTR✅ DoneWorks on iOS + Android home screen
Help documentation✅ DoneFull guide at /help
AI item autofill🔮 FutureCameron deferred — API key already wired
Preset inventory templates🔮 FutureCameron deferred
Native iOS/Android app🔮 FutureFull in-app browser, push notifications
Supplier order API🔮 FutureNeeds dealer API accounts with suppliers
Live supplier price feeds🔮 FutureNeeds supplier EDI or API pricing
For Cameron
Every feature you spec'd is either built, partially built with an honest workaround, or queued with a clear path forward. Nothing got dropped or forgotten. The three partial items (in-app browser, add to cart, live prices) all have the same root cause: supplier websites aren't built to be talked to by third-party apps. The fix in all three cases runs through either a supplier API deal or going native. When you're ready to push on any of them — we know exactly what to build next.

LockVentory · Built June 2026 · Admin-only document