Everything in the system is built from three kinds of record. Understand these and nothing will ever feel like magic:
| Record | What it is | Example |
|---|---|---|
| Item | One entry in the catalog — the definition of a thing we handle. Holds SKU, UPC, name, size, case pack, unit of measure, shelf life, allergens. An item has no quantity of its own. | JS14H-WC — Wild Sockeye Jerky, Original, 70g |
| Lot | A real batch of that item sitting somewhere: quantity + location + lot number + pack date + best-by. One item can have many lots. | Lot 260901-A · 48 units · Main Freezer · best-by 2027-03-01 |
| Movement | One line in the permanent diary: what changed, by how much, why, who, when. Receiving writes a +, shipping writes a −, a count writes the correction. | +48 · received · JS14H-WC · lot 260901-A · from Ocean Fisheries · ryder |
"On hand" is never typed anywhere. The number you see beside an item is simply the sum of its lots — and every lot got its quantity from movements. That's why the system can always answer "why does it say 48?": open Activity and read the diary.
products, lots, and movements tables in our own Supabase (Postgres) database. Movements are append-only — nothing is ever edited or deleted, corrections are new entries. Every row carries the email of the person who made it. That's the entire trust model.| SKU | UPC | |
|---|---|---|
| What | Our internal code for the item. We invent it. Every item must have one, and it must be unique. | The manufacturer's barcode number printed on retail packaging — usually 12 digits under the bars. |
| Where it comes from | You (or the suggest one link). Existing items keep their Shopify-era SKUs like JS14H-WC. | The package itself. Read the digits under the barcode, or scan it straight into the field. |
| Required? | Yes, always. | No. Raw fish, bulk cases and packaging usually have none — that's fine (see §10). |
| What the scanner does with it | Scans our own printed labels (the SKU rendered as a Code 128 barcode). | Scans the retail barcode directly. |
Products page → + Item (admin). Field by field, top to bottom:
| Field | What to enter | Why it matters |
|---|---|---|
| Section | Product / Packaging / Fish | Which page it lives on. Fish = raw seafood tracked by weight; Packaging = boxes, sleeves, labels; Product = everything finished. |
| Name | What a person would call it — "Wild Sockeye Jerky Original 70g" | Shows on every screen, label and report. |
| SKU | Your code, or click suggest one for the next free number in the category | The item's permanent identity. Saved uppercase. |
| UPC | The 12 digits under the retail barcode; blank if there isn't one | Makes the camera scanner find it instantly. |
| Category | Short group code — JERKY, SMOKED, CANDY, CANS, FRESH… | Filters, count sheets, and the SKU-suggester all group by it. |
| Size | "70g", "1kg", "50 lb case"… | Appears on labels and pick lists so nobody grabs the wrong format. |
| Case pack | Units per case (e.g. 12) | Purchase suggestions round to whole cases; exports show case counts. |
| Unit of measure | units for things you count by the piece; lb or kg for things you weigh | Units round to whole numbers; weights keep one decimal. Fish defaults to lb. |
| Reorder point | Leave 0 for now | Once real demand flows, Admin's Apply suggested ROPs sets these from actual math. |
| Lead time (days) | How long a resupply takes, if you know it | Feeds safety-stock math. Blank = 14-day default. |
| Shelf life (days) | e.g. 365 for jerky, 730 for cans | The best time-saver in the app: receiving auto-fills every best-by date as pack date + shelf life. |
| Allergens | Tick what it contains (fish, soy, sesame…) | Powers the allergen matrix and the production-run carry-over warnings. |
| Photo URL | Optional — a web image link | Shows on the phone count card; Shopify-linked items already have theirs. |
| Custom fields | Whatever Ryder has defined in Settings (e.g. Country of origin) | Appear automatically on every item. |
Press Save. The item now exists — with zero on hand, because quantity only ever comes from counts and receipts (§6–8).
products. Any later edit to the important fields (SKU, UPC, size, case pack…) is recorded in product_audit — who changed what, from what, to what.For a list that already exists in a spreadsheet (Sage item lists, a supplier's product sheet), skip the typing entirely. Import page (admin):
| Column | Also accepted as |
|---|---|
sku | Item, Item No, Item Number, Item Code, Part Number, Number |
name | Description, Item Description, Product |
section | type — product / packaging / fish |
category, size, upc | barcode → upc |
case_pack | casepack |
uom | unit, units — values: units / lb / kg |
shelf_life | shelflife, shelf life days |
reorder | reorderpoint |
qty + location + lot + best_by | see §8 — these book opening stock |
Quantities enter the system as counts. A count says: "I physically looked, and there are X." Here is the whole loop, tap by tap:
412.5).COUNT-260907). If the case shows a real lot number, type that instead — real lots make recalls sharper. If not, the dated one is exactly right.lots row is created (or updated if that item+lot+location already exists) with your quantity; (2) a movements row records the difference between what the system believed and what you counted — reason count, your name, timestamp. If the system said 0 and you counted 48, the movement is +48. If it said 50 and you counted 48, the movement is −2. Zero-difference counts are logged too — they're the proof of accuracy on the Count-variance report.The Import page books opening stock in the same pass that creates items. Add these columns to your §5 sheet:
qty — the counted quantity. Any row with a positive qty books stock; rows without qty just create/update the item.location — optional; matches your location names loosely ("main" finds "Main Freezer"). Blank = your first location.lot — optional; blank gets the dated COUNT- lot.best_by — optional; takes 2027-03-01 or most spreadsheet date formats.count movement noted "Opening balance import". The audit trail never has gaps, no matter which door the data came in through.One 📷 Scan button, three behaviors depending on where you are:
| Where you scan | What happens |
|---|---|
| Products | Jumps to that item's section, opens its row with all its lots showing. "What is this and how much do we have?" |
| Count | Jumps the count card straight to that item — the freezer-walk loop of §6. |
| Receiving sheet (📷 Scan cases) | Continuous mode — the camera stays on and every case scanned adds 1 to that item's line. Unload the truck scanning as you go, then fill in lots and dates. |
| Ship sheet (📷 Scan cases) | Same continuous mode going the other way — scan each case as it's loaded and the outgoing lines build themselves, with live availability beside each. |
| Trace | Runs a trace on the code — scan a lot label here and you get the lot's full history, mass balance, and hold button. |
Three label printers, all built-in, no special hardware — any office printer works:
| Label | Where | Use for |
|---|---|---|
| Shelf & bin labels | Reports → Shelf & bin labels | One per item, whole catalog, 3-across grid. Barcode = UPC if the item has one, otherwise the SKU as Code 128. Tape to shelves/bins — this makes packaging and no-UPC items scannable. |
| Case / lot labels | 🏷 Labels on the receiving sheet | One per received line: item, SKU, LOT number as a barcode, packed & best-by dates. Tape to each case as it comes off the truck. |
| Reprints | 🏷 on any lot row (Products) | Label got wet/torn, case repacked — two clicks reprints it. |
The exact order that gets an empty system to a running one, fastest:
JS14H-WC…). For new packaging/fish, let suggest one build CATEGORY-001 style codes — consistent and sortable.Companion: the complete Manual (every screen), WCS-Opening-Stock-Template.csv, HOW-TO-load-your-Sage-data, WCS-Cheat-Sheet. Questions → Ryder.