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
W1
First launch
First time the app is opened after install
What happens
- App boots, creates a local SwiftData database on the iPhone.
- 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.
- 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
- Toggle: This month vs All time
- 4 stat cards: Inventory at cost, Revenue, Profit, Avg margin
- Quick action buttons: Add item and Log sale
- 6-month revenue line chart (area chart, monotone interpolation)
- 4 more stat cards: In stock, Sold this month, Dead stock, Capital tied up
W3
Add item — manual entry
Inventory tab → "+" toolbar button, or Dashboard → "Add item" button
Steps
- User taps "+" or "Add item." A modal sheet slides up titled "Add item."
- 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).
- Details section: set / expansion (optional), card number (optional), grade (only shown when category = Graded).
- Acquisition section: purchase date, cost per unit, quantity (default 1), source (e.g. LCS, eBay).
- Photo section: tap to add. Confirmation dialog with two options: "Take Photo" or "Choose from Library."
- Notes section: free text.
- Validation on Save: name required, quantity ≥ 1, price ≥ 0. If any fail, error shows in red at the bottom.
- 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
- User taps the Photo row in the form.
- Action sheet appears: "Take Photo" / "Choose from Library" / "Cancel."
- User taps "Take Photo." First time only: iOS prompts for camera permission. Granted = continue; denied = sheet closes.
- Full-screen camera UI opens (Apple's standard camera). User takes a shot.
- After capture, user can crop / rotate / use. Tap "Use Photo."
- 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
- User taps the Photo row.
- Action sheet appears: "Take Photo" / "Choose from Library" / "Cancel."
- User taps "Choose from Library." iOS PhotosPicker opens (Apple's modern photo picker — no full-library permission needed, only the chosen photo is shared).
- User selects a photo and taps Done.
- Image loads asynchronously. Form's Photo row now shows the thumbnail.
W6
Add a pulled card
Inside Add Item form → Acquisition section
Steps
- User sets Category to Single. Only then does a "Pulled from pack" toggle appear.
- 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."
- The "Source" placeholder also changes to "Source (e.g. set name / event)" instead of "LCS, eBay."
- User can leave cost as 0 (treats as $0 cost basis), or enter a number (treats as amortized).
- On save, the item is flagged isPulled = true.
- 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
- Searchable list of all items, newest first by default.
- Each row: thumbnail, name + condition badge + grade badge + Pulled badge (if any), game/category/set, remaining inventory value, in-stock indicator.
- Search bar at top: matches name, set, notes, card number.
- Two toolbar buttons: filter menu (funnel icon), and "+" to add.
W8
Filter and sort inventory
Inventory tab → funnel icon in toolbar
Filters and sorts available
- Sort: Newest, Oldest, Highest value, Lowest stock, A → Z
- Stock: All, In stock, Sold out
- Show archived toggle
- Game: All, or one of the 6 games
- Category: All, or one of the 5 categories
- Condition: All, or one of the 7 conditions
W9
Item detail view
Tap any inventory item
What's shown
- Photo (large) at top, if attached.
- Game / category row + condition badge with full name (e.g. "NM — Near Mint").
- 4 stat cards: Stock left, Sell-through %, Revenue, Profit + margin %.
- 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.
- Notes block (if any).
- Sales history: every sale logged for this item, sorted newest first. Tap a sale → Sale Detail.
Toolbar menu (••• icon)
- Log sale
- Edit
- Archive / Restore
- Duplicate
- Delete (red, with confirmation)
W10
Edit an item
Item detail → ••• menu → Edit
Steps
- Same form as Add Item, prefilled with existing values.
- User edits any fields. Cost basis edits flow through retroactively to historical profit/margin (since cost is read live, not snapshotted).
- If user lowers quantity below the number already sold, app clamps to the sold count.
- 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
- Creates a new item with the same name, game, category, condition, set, card number, grade, cost, quantity, source, notes, and photo.
- quantitySold resets to 0 (it's a new copy, no sales yet).
- purchaseDate is reset to today.
Archive
- Sets isArchived = true. The item disappears from the default inventory list view.
- To see it again: filter menu → toggle "Show archived" on.
- Restore = swipe again or tap Restore in detail view.
W12
Log a sale (from Dashboard)
Dashboard → "Log sale" button
Steps
- Modal sheet opens. Item picker at top — search by name with autocomplete; only in-stock items are shown.
- User picks an item. Picker collapses to show: name, "X in stock — cost $Y/unit." A "Change" button lets them re-pick.
- 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.
- Live preview: as the user types, a Preview block updates with Gross, Fees, Net revenue, Cost basis, Profit, Margin %.
- Validation on Save: must have an item selected, sale price > 0, quantity 1–stock remaining.
- 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
- Same Log Sale form as W12, but with the item already pre-selected.
- User just enters price, quantity, platform, fees, buyer, notes.
- 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
- Header section: filtered totals — Revenue, Profit, sales count, units count.
- Section: chronological list of sales, newest first.
- Each row: item name, date, platform, quantity, net revenue, profit (green if positive, red if negative).
Filters (funnel icon)
- Date range: 30 d, 90 d, 1 yr, All
- Platform filter
- Game filter
W15
Edit or delete a sale
Tap any sale → Sale Detail
Edit
- Tap ••• menu → Edit.
- Fields become editable: date, sale price, quantity, platform, fees, buyer, notes.
- Result section shows Gross, Net, Cost basis, Profit, Margin live.
- If quantity changes, the linked item's quantitySold is adjusted by the delta.
- Tap Done → changes save.
Delete
- ••• menu → Delete (red).
- Confirmation dialog: "Stock count will be restored."
- 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)
- Revenue trend — line chart, range picker (30 d / 90 d / 1 yr / All). Auto-buckets by day or week depending on range.
- Top movers — top 5 items by sell-through %.
- Best margin items — top 5 items by margin %.
- Dead stock — all items 60+ days old with 0 sales, sorted by oldest first.
- Profit by game — donut chart + per-game breakdown list.
- Profit by platform — bar chart by sales platform.
- 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
- Tap "Export inventory CSV" or "Export sales CSV."
- iOS share sheet appears with the file ready to save.
- User picks a destination (Files app, AirDrop, Mail, etc.).
- 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
- Tap "Import inventory CSV." iOS file picker opens.
- User selects a CSV file (any source — exported from VaultedTCG, Excel, Google Sheets, etc.).
- Importer reads the file, parses RFC4180 CSV (handles quoted fields, escaped quotes, embedded commas/newlines).
- For each row, creates an InventoryItem. Missing optional columns get sensible defaults.
- 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
- Tap "Erase all data" (red, destructive).
- Confirmation dialog: "Erase ALL items and sales? This cannot be undone. Consider exporting CSV first."
- 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
- Tap "Load sample data."
- Adds the same ~15 items + ~26 sales used on first launch — does NOT erase existing data first.
- 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.