Workflow Review

VaultedTCG Workflows

Every user-facing flow in the app, written out so you can review, mark what's wrong, and send edits back.

How to give feedback

Each workflow has an ID like W1 in the top-left corner of its card. To request a change, just write me a list:

W3 step 4 — wrong, should be ___
W7 — remove this flow entirely
W12 — add option for ___

You don't need to rewrite a whole section. Quick notes are best.

Send feedback

Table of contents

  1. W1 — First launch
  2. W2 — Dashboard
  3. W3 — Add item (manual)
  4. W4 — Add item with photo (camera)
  5. W5 — Add item with photo (library)
  6. W6 — Add a pulled card
  7. W7 — Browse inventory
  8. W8 — Filter / sort inventory
  9. W9 — Item detail view
  10. W10 — Edit an item
  11. W11 — Duplicate / archive an item
  12. W12 — Log a sale (from Dashboard)
  13. W13 — Log a sale (from item)
  14. W14 — Browse sales history
  15. W15 — Edit / delete a sale
  16. W16 — Analytics
  17. W17 — Export CSV
  18. W18 — Import CSV
  19. W19 — Erase all data
  20. W20 — Sample data
W1

First launch

First time the app is opened after install

What happens

  1. App boots, creates a local SwiftData database on the iPhone.
  2. If the database is empty, sample data auto-seeds: ~15 inventory items (Pokémon, One Piece TCG, sealed product, accessories) + ~25 sales spread across the last 90 days.
  3. Lands on the Dashboard tab.
Sample data exists so the Dashboard and Analytics tabs aren't empty when a tester first opens the app. They can erase it via Settings → Erase all data.
Possible change: add a first-launch sheet asking "Start fresh" vs "Try with sample data" instead of auto-seeding.
W2

Dashboard

Tab 1 (chart.pie.fill icon)

What's shown

W3

Add item — manual entry

Inventory tab → "+" toolbar button, or Dashboard → "Add item" button

Steps

  1. User taps "+" or "Add item." A modal sheet slides up titled "Add item."
  2. Item section: name (required), Game picker (One Piece, Pokémon, Magic, Yu-Gi-Oh!, Lorcana, Other), Category picker (Single, Sealed, Graded, Lot, Accessory), Condition picker (full-screen: NM, LP, MP, HP, DMG, Sealed, Graded — each with a description blurb).
  3. Details section: set / expansion (optional), card number (optional), grade (only shown when category = Graded).
  4. Acquisition section: purchase date, cost per unit, quantity (default 1), source (e.g. LCS, eBay).
  5. Photo section: tap to add. Confirmation dialog with two options: "Take Photo" or "Choose from Library."
  6. Notes section: free text.
  7. Validation on Save: name required, quantity ≥ 1, price ≥ 0. If any fail, error shows in red at the bottom.
  8. On successful save, sheet closes. Item appears at the top of the inventory list (sorted newest by default).
W4

Add photo — Take Photo (camera)

Inside Add Item form → Photo row

Steps

  1. User taps the Photo row in the form.
  2. Action sheet appears: "Take Photo" / "Choose from Library" / "Cancel."
  3. User taps "Take Photo." First time only: iOS prompts for camera permission. Granted = continue; denied = sheet closes.
  4. Full-screen camera UI opens (Apple's standard camera). User takes a shot.
  5. After capture, user can crop / rotate / use. Tap "Use Photo."
  6. Image is saved to the form (JPEG @ 0.85 quality). Form's Photo row now shows a thumbnail with "Change photo."
Camera button only appears on physical iPhones. On Simulator it's hidden because the Simulator has no camera.
W5

Add photo — Choose from Library

Inside Add Item form → Photo row

Steps

  1. User taps the Photo row.
  2. Action sheet appears: "Take Photo" / "Choose from Library" / "Cancel."
  3. User taps "Choose from Library." iOS PhotosPicker opens (Apple's modern photo picker — no full-library permission needed, only the chosen photo is shared).
  4. User selects a photo and taps Done.
  5. Image loads asynchronously. Form's Photo row now shows the thumbnail.
W6

Add a pulled card

Inside Add Item form → Acquisition section

Steps

  1. User sets Category to Single. Only then does a "Pulled from pack" toggle appear.
  2. User flips the toggle on. The cost label changes to "Pack cost (optional)" and a hint appears: "Leave 0 to count as zero-cost, or enter the amortized pack price."
  3. The "Source" placeholder also changes to "Source (e.g. set name / event)" instead of "LCS, eBay."
  4. User can leave cost as 0 (treats as $0 cost basis), or enter a number (treats as amortized).
  5. On save, the item is flagged isPulled = true.
  6. In inventory list and detail view, a yellow "Pulled" badge appears next to the item name.
W7

Browse inventory

Tab 2 (shippingbox.fill icon)

What's shown

W8

Filter and sort inventory

Inventory tab → funnel icon in toolbar

Filters and sorts available

W9

Item detail view

Tap any inventory item

What's shown

  1. Photo (large) at top, if attached.
  2. Game / category row + condition badge with full name (e.g. "NM — Near Mint").
  3. 4 stat cards: Stock left, Sell-through %, Revenue, Profit + margin %.
  4. Acquisition info block: cost per unit (or "Pack cost (amortized)" if pulled), total cost basis, purchase date, days in inventory, source. Shows red "Dead stock" warning if 60+ days old with zero sales.
  5. Notes block (if any).
  6. Sales history: every sale logged for this item, sorted newest first. Tap a sale → Sale Detail.

Toolbar menu (••• icon)

W10

Edit an item

Item detail → ••• menu → Edit

Steps

  1. Same form as Add Item, prefilled with existing values.
  2. User edits any fields. Cost basis edits flow through retroactively to historical profit/margin (since cost is read live, not snapshotted).
  3. If user lowers quantity below the number already sold, app clamps to the sold count.
  4. Tap Save → return to detail view with updates applied.
W11

Duplicate or archive an item

Inventory list (swipe a row) or Item detail (••• menu)

Duplicate

  1. Creates a new item with the same name, game, category, condition, set, card number, grade, cost, quantity, source, notes, and photo.
  2. quantitySold resets to 0 (it's a new copy, no sales yet).
  3. purchaseDate is reset to today.

Archive

W12

Log a sale (from Dashboard)

Dashboard → "Log sale" button

Steps

  1. Modal sheet opens. Item picker at top — search by name with autocomplete; only in-stock items are shown.
  2. User picks an item. Picker collapses to show: name, "X in stock — cost $Y/unit." A "Change" button lets them re-pick.
  3. User enters: date (default today), sale price per unit, quantity (capped at stock remaining), platform (eBay / TCGplayer / In-Person / Discord / Facebook / Other), fees, optional buyer, optional notes.
  4. Live preview: as the user types, a Preview block updates with Gross, Fees, Net revenue, Cost basis, Profit, Margin %.
  5. Validation on Save: must have an item selected, sale price > 0, quantity 1–stock remaining.
  6. On Save: a Sale row is inserted, and the item's quantitySold increments. Inventory remaining count drops accordingly.
W13

Log a sale (from item detail)

Item detail → ••• menu → Log sale

Steps

  1. Same Log Sale form as W12, but with the item already pre-selected.
  2. User just enters price, quantity, platform, fees, buyer, notes.
  3. Save → returns to item detail with the new sale appearing in Sales history.
W14

Browse sales history

Tab 3 (tag.fill icon)

What's shown

Filters (funnel icon)

W15

Edit or delete a sale

Tap any sale → Sale Detail

Edit

  1. Tap ••• menu → Edit.
  2. Fields become editable: date, sale price, quantity, platform, fees, buyer, notes.
  3. Result section shows Gross, Net, Cost basis, Profit, Margin live.
  4. If quantity changes, the linked item's quantitySold is adjusted by the delta.
  5. Tap Done → changes save.

Delete

  1. ••• menu → Delete (red).
  2. Confirmation dialog: "Stock count will be restored."
  3. On confirm: item.quantitySold decrements by this sale's quantity, the Sale row is removed.
W16

Analytics

Tab 4 (chart.bar.xaxis icon)

Sections (top to bottom)

  1. Revenue trend — line chart, range picker (30 d / 90 d / 1 yr / All). Auto-buckets by day or week depending on range.
  2. Top movers — top 5 items by sell-through %.
  3. Best margin items — top 5 items by margin %.
  4. Dead stock — all items 60+ days old with 0 sales, sorted by oldest first.
  5. Profit by game — donut chart + per-game breakdown list.
  6. Profit by platform — bar chart by sales platform.
  7. Capital tied up — bar chart, segmented control to switch between "By game" and "By category."
W17

Export data as CSV

Settings tab → Data section

Steps

  1. Tap "Export inventory CSV" or "Export sales CSV."
  2. iOS share sheet appears with the file ready to save.
  3. User picks a destination (Files app, AirDrop, Mail, etc.).
  4. File saves with name vaultedtcg-inventory.csv or vaultedtcg-sales.csv.

Inventory CSV columns

id, name, game, category, condition, setName, cardNumber, grade, purchaseDate, purchasePrice, quantity, quantitySold, source, notes, isArchived, isPulled

Sales CSV columns

id, itemID, itemName, saleDate, salePrice, quantitySold, platform, fees, buyer, notes, grossRevenue, netRevenue, profit, marginPercent

W18

Import inventory CSV

Settings tab → Import inventory CSV

Steps

  1. Tap "Import inventory CSV." iOS file picker opens.
  2. User selects a CSV file (any source — exported from VaultedTCG, Excel, Google Sheets, etc.).
  3. Importer reads the file, parses RFC4180 CSV (handles quoted fields, escaped quotes, embedded commas/newlines).
  4. For each row, creates an InventoryItem. Missing optional columns get sensible defaults.
  5. Reports: inserted count, skipped count, any error messages.
Designed so a vendor can migrate from a spreadsheet on day one. Header names are case-insensitive.
W19

Erase all data

Settings tab → Sample data section → "Erase all data"

Steps

  1. Tap "Erase all data" (red, destructive).
  2. Confirmation dialog: "Erase ALL items and sales? This cannot be undone. Consider exporting CSV first."
  3. On confirm: all Sale rows deleted, all InventoryItem rows deleted. SwiftData store is empty.
W20

Sample data

Settings tab → Sample data section → "Load sample data"

Steps

  1. Tap "Load sample data."
  2. Adds the same ~15 items + ~26 sales used on first launch — does NOT erase existing data first.
  3. Useful if a user wiped data and wants to repopulate, or wants to mix sample data into their real records (probably not a great idea — easy to confuse later).
Possible change: have "Load sample data" wipe first, or warn the user it'll mix with their existing data.