feat: establish auth listing and image vertical slices

Includes MFA-capable authentication, session and CSRF security, password recovery, listing lifecycle and ownership rules, inventory image metadata, local ImageStorage, migrations, tests, and implementation status documentation. Verification: npm test (62 passing) and integration suite (14 passing).
This commit is contained in:
2026-09-08 17:32:03 -04:00
commit c728016dec
128 changed files with 9788 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
# Data Model
## Core relationship
```text
User → Seller → Product → Inventory Item → Listing
│
├── Images
├── Acquisition
├── Pricing Observations
├── Market Valuations
└── Activity
Sale → Sale Items → Inventory Items
```
## Product
Represents what the item is, independent of physical ownership.
Examples:
- Charizard ex — SV151 — #199/165
- Pokémon Center Worlds 2025 Pikachu Plush
Products persist after all inventory is sold.
## Inventory Item
Represents one physical copy.
Each copy has its own:
- condition
- images
- acquisition
- asking price/listing
- market valuation
- notes
- status
Do not model multiple physical copies as a quantity field on one Inventory Item.
## Listing
Represents how an Inventory Item is currently offered publicly.
A Product can have many physical Inventory Items with different conditions and asking prices.
## Sale
A manual external transaction. One Sale can contain multiple Sale Items.
## Provider Product Mapping
Provider mappings are Product-level relationships.
Recommended fields:
- id
- product_id
- provider_id
- mapping_type (`PRODUCT` or `SEARCH`)
- external_identifier
- search_query / search parameters
- source_url
- status
- metadata
- created_at
- updated_at
- disabled_at
A provider can support one or both mapping types.
eBay supports both:
- specific product/catalog mappings where appropriate
- search/query mappings where no canonical product is appropriate
Mappings can be replaced without destroying historical records.
Only one active/default mapping per provider should be used for normal pricing unless a provider integration explicitly supports multiple active sources.
## Suggested pricing tables
### pricing_providers
`id, name, code, is_enabled, priority, configuration, created_at, updated_at`
### product_pricing_providers
`product_id, provider_id, is_enabled`
### pricing_provider_mappings
As described above.
### pricing_observations
`id, product_id, inventory_item_id, provider_id, source_identifier, source_url, condition_id, price_minor, currency, observed_at, quality_score, is_outlier, outlier_reason, raw_reference`
### market_valuations
`id, inventory_item_id, value_minor, currency, strategy, confidence, source_count, calculated_at`
### market_value_overrides
`id, inventory_item_id, value_minor, currency, reason, created_by, created_at, removed_at`
### pricing_jobs
`id, job_type, status, requested_by, started_at, completed_at, total_items, processed_items, successful_items, failed_items, error_summary, created_at`
## Conditions
`condition_profiles`:
- id
- category_id
- name
- active
- sort
`conditions`:
- id
- condition_profile_id
- name
- code
- quality_rank
- description
- active
- sort
## Images
`inventory_images`:
- id
- inventory_item_id
- storage_key
- original_filename
- mime_type
- file_size
- width
- height
- alt_text
- sort_order
- is_primary
- processing_status
- created_at
- updated_at
## Acquisitions
`acquisitions`:
- id
- inventory_item_id
- method
- cost_minor
- currency
- date
- source
- location
- shipping_minor
- tax_minor
- other_fees_minor
- estimated_trade_value_minor
- notes
- created_at
- updated_at
## Sales
`sales`:
- id
- seller_id
- sale_date
- sale_location
- sold_price_minor
- currency
- platform_fees_minor
- payment_processing_fees_minor
- shipping_cost_minor
- taxes_minor
- other_fees_minor
- buyer_name
- buyer_contact
- notes
- created_by
- created_at
- updated_at
`sale_items`:
- id
- sale_id
- inventory_item_id
- sold_price_minor
- cost_basis_minor
## Activity
Activity records retain:
- affected Product/Inventory Item
- event
- previous value where applicable
- new value
- actor
- timestamp
Security events are stored separately.
## Money
Store money as integer minor units. Negative values are prohibited; zero is valid. USD is canonical for stored/calculated market values unless a documented external representation requires another currency.