docs: migrate module documentation to single source of truth
Move 39 documentation files from top-level docs/ into each module's docs/ folder, accessible via symlinks from docs/modules/. Create data-model.md files for 10 modules with full schema documentation. Replace originals with redirect stubs. Remove empty guide stubs. Modules migrated: tenancy, billing, loyalty, marketplace, orders, messaging, cms, catalog, inventory, hosting, prospecting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
82
app/modules/inventory/docs/data-model.md
Normal file
82
app/modules/inventory/docs/data-model.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Inventory Data Model
|
||||
|
||||
Entity relationships and database schema for the inventory module.
|
||||
|
||||
## Entity Relationship Overview
|
||||
|
||||
```
|
||||
Store 1──* Inventory *──1 Product
|
||||
│
|
||||
└──* InventoryTransaction
|
||||
│
|
||||
└──? Order (for reserve/fulfill/release)
|
||||
```
|
||||
|
||||
## Models
|
||||
|
||||
### Inventory
|
||||
|
||||
Stock quantities at warehouse bin locations. Supports multi-location inventory with reservation tracking.
|
||||
|
||||
| Field | Type | Constraints | Description |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | Integer | PK | Primary key |
|
||||
| `product_id` | Integer | FK, not null, indexed | Product reference |
|
||||
| `store_id` | Integer | FK, not null, indexed | Store reference |
|
||||
| `warehouse` | String | not null, default "strassen", indexed | Warehouse identifier |
|
||||
| `bin_location` | String | not null, indexed | Bin code (e.g., "SA-10-02") |
|
||||
| `quantity` | Integer | not null, default 0 | Total quantity at bin |
|
||||
| `reserved_quantity` | Integer | default 0 | Reserved/allocated quantity |
|
||||
| `gtin` | String | indexed | GTIN reference (duplicated for reporting) |
|
||||
| `created_at` | DateTime | tz-aware | Record creation time |
|
||||
| `updated_at` | DateTime | tz-aware | Record update time |
|
||||
|
||||
**Unique Constraint**: `(product_id, warehouse, bin_location)`
|
||||
**Composite Indexes**: `(store_id, product_id)`, `(warehouse, bin_location)`
|
||||
|
||||
**Key Property**: `available_quantity` = max(0, quantity - reserved_quantity)
|
||||
|
||||
### InventoryTransaction
|
||||
|
||||
Complete audit trail for all stock movements with before/after snapshots.
|
||||
|
||||
| Field | Type | Constraints | Description |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | Integer | PK | Primary key |
|
||||
| `store_id` | Integer | FK, not null, indexed | Store reference |
|
||||
| `product_id` | Integer | FK, not null, indexed | Product reference |
|
||||
| `inventory_id` | Integer | FK, nullable, indexed | Inventory record reference |
|
||||
| `transaction_type` | Enum | not null, indexed | Type of stock movement |
|
||||
| `quantity_change` | Integer | not null | Change amount (+ add, - remove) |
|
||||
| `quantity_after` | Integer | not null | Quantity snapshot after transaction |
|
||||
| `reserved_after` | Integer | not null, default 0 | Reserved quantity snapshot |
|
||||
| `location` | String | nullable | Location context |
|
||||
| `warehouse` | String | nullable | Warehouse context |
|
||||
| `order_id` | Integer | FK, nullable, indexed | Related order |
|
||||
| `order_number` | String | nullable | Order number for display |
|
||||
| `reason` | Text | nullable | Human-readable reason |
|
||||
| `created_by` | String | nullable | User/system identifier |
|
||||
| `created_at` | DateTime | not null, indexed | Timestamp (UTC) |
|
||||
|
||||
**Composite Indexes**: `(store_id, product_id)`, `(store_id, created_at)`, `(transaction_type, created_at)`
|
||||
|
||||
## Enums
|
||||
|
||||
### TransactionType
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `reserve` | Stock reserved for order |
|
||||
| `fulfill` | Reserved stock consumed (shipped) |
|
||||
| `release` | Reserved stock released (cancelled) |
|
||||
| `adjust` | Manual adjustment (+/-) |
|
||||
| `set` | Set to exact quantity |
|
||||
| `import` | Initial import/sync |
|
||||
| `return` | Stock returned from customer |
|
||||
|
||||
## Design Patterns
|
||||
|
||||
- **Multi-location**: Inventory tracked per warehouse + bin location
|
||||
- **Reservation system**: Separate quantity and reserved_quantity for order holds
|
||||
- **Full audit trail**: Every stock change recorded with before/after snapshots
|
||||
- **Order integration**: Transactions linked to orders for reserve/fulfill/release cycle
|
||||
53
app/modules/inventory/docs/index.md
Normal file
53
app/modules/inventory/docs/index.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Inventory Management
|
||||
|
||||
Stock level tracking, inventory locations, low stock alerts, transaction history, and bulk imports.
|
||||
|
||||
## Overview
|
||||
|
||||
| Aspect | Detail |
|
||||
|--------|--------|
|
||||
| Code | `inventory` |
|
||||
| Classification | Optional |
|
||||
| Dependencies | `catalog`, `orders` |
|
||||
| Status | Active |
|
||||
|
||||
## Features
|
||||
|
||||
- `inventory_basic` — Basic stock tracking
|
||||
- `inventory_locations` — Multi-location inventory
|
||||
- `low_stock_alerts` — Low stock notifications
|
||||
- `inventory_purchase_orders` — Purchase order management
|
||||
- `product_management` — Product inventory management
|
||||
- `inventory_transactions` — Stock movement audit trail
|
||||
- `inventory_import` — Bulk stock import
|
||||
|
||||
## Permissions
|
||||
|
||||
| Permission | Description |
|
||||
|------------|-------------|
|
||||
| `stock.view` | View inventory data |
|
||||
| `stock.edit` | Edit stock levels |
|
||||
| `stock.transfer` | Transfer stock between locations |
|
||||
|
||||
## Data Model
|
||||
|
||||
See [Data Model](data-model.md) for full entity relationships and schema.
|
||||
|
||||
- **Inventory** — Stock quantities at warehouse bin locations
|
||||
- **InventoryTransaction** — Complete audit trail for stock movements
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `*` | `/api/v1/admin/inventory/*` | Admin inventory management |
|
||||
| `*` | `/api/v1/store/inventory/*` | Store inventory management |
|
||||
|
||||
## Configuration
|
||||
|
||||
No module-specific configuration.
|
||||
|
||||
## Additional Documentation
|
||||
|
||||
- [Data Model](data-model.md) — Entity relationships and database schema
|
||||
- [User Guide](user-guide.md) — Inventory management guide with API reference
|
||||
366
app/modules/inventory/docs/user-guide.md
Normal file
366
app/modules/inventory/docs/user-guide.md
Normal file
@@ -0,0 +1,366 @@
|
||||
# Inventory Management
|
||||
|
||||
## Overview
|
||||
|
||||
The Orion platform provides comprehensive inventory management with support for:
|
||||
|
||||
- **Multi-location tracking** - Track stock across warehouses, stores, and storage bins
|
||||
- **Reservation system** - Reserve items for pending orders
|
||||
- **Digital products** - Automatic unlimited inventory for digital goods
|
||||
- **Admin operations** - Manage inventory on behalf of stores
|
||||
|
||||
---
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Storage Locations
|
||||
|
||||
Inventory is tracked at the **storage location level**. Each product can have stock in multiple locations:
|
||||
|
||||
```
|
||||
Product: "Wireless Headphones"
|
||||
├── WAREHOUSE_MAIN: 100 units (10 reserved)
|
||||
├── WAREHOUSE_WEST: 50 units (0 reserved)
|
||||
└── STORE_FRONT: 25 units (5 reserved)
|
||||
|
||||
Total: 175 units | Reserved: 15 | Available: 160
|
||||
```
|
||||
|
||||
**Location naming:** Locations are text strings, normalized to UPPERCASE (e.g., `WAREHOUSE_A`, `STORE_01`).
|
||||
|
||||
### Inventory States
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `quantity` | Total physical stock at location |
|
||||
| `reserved_quantity` | Items reserved for pending orders |
|
||||
| `available_quantity` | `quantity - reserved_quantity` (can be sold) |
|
||||
|
||||
### Product Types & Inventory
|
||||
|
||||
| Product Type | Inventory Behavior |
|
||||
|--------------|-------------------|
|
||||
| **Physical** | Requires inventory tracking, orders check available stock |
|
||||
| **Digital** | **Unlimited inventory** - no stock constraints |
|
||||
| **Service** | Treated as digital (unlimited) |
|
||||
| **Subscription** | Treated as digital (unlimited) |
|
||||
|
||||
---
|
||||
|
||||
## Digital Products
|
||||
|
||||
Digital products have **unlimited inventory** by default. This means:
|
||||
|
||||
- Orders for digital products never fail due to "insufficient inventory"
|
||||
- No need to create inventory entries for digital products
|
||||
- The `available_inventory` property returns `999999` (effectively unlimited)
|
||||
|
||||
### How It Works
|
||||
|
||||
```python
|
||||
# In Product model
|
||||
@property
|
||||
def has_unlimited_inventory(self) -> bool:
|
||||
"""Digital products have unlimited inventory."""
|
||||
return self.is_digital
|
||||
|
||||
@property
|
||||
def available_inventory(self) -> int:
|
||||
"""Calculate available inventory."""
|
||||
if self.has_unlimited_inventory:
|
||||
return 999999 # Unlimited
|
||||
return sum(inv.available_quantity for inv in self.inventory_entries)
|
||||
```
|
||||
|
||||
### Setting a Product as Digital
|
||||
|
||||
Digital products are identified by the `is_digital` flag on the `MarketplaceProduct`:
|
||||
|
||||
```python
|
||||
marketplace_product.is_digital = True
|
||||
marketplace_product.product_type_enum = "digital"
|
||||
marketplace_product.digital_delivery_method = "license_key" # or "download", "email"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Inventory Operations
|
||||
|
||||
### Set Inventory
|
||||
|
||||
Replace the exact quantity at a location:
|
||||
|
||||
```http
|
||||
POST /api/v1/store/inventory/set
|
||||
{
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 100
|
||||
}
|
||||
```
|
||||
|
||||
### Adjust Inventory
|
||||
|
||||
Add or remove stock (positive = add, negative = remove):
|
||||
|
||||
```http
|
||||
POST /api/v1/store/inventory/adjust
|
||||
{
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": -10 // Remove 10 units
|
||||
}
|
||||
```
|
||||
|
||||
### Reserve Inventory
|
||||
|
||||
Mark items as reserved for an order:
|
||||
|
||||
```http
|
||||
POST /api/v1/store/inventory/reserve
|
||||
{
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 5
|
||||
}
|
||||
```
|
||||
|
||||
### Release Reservation
|
||||
|
||||
Cancel a reservation (order cancelled):
|
||||
|
||||
```http
|
||||
POST /api/v1/store/inventory/release
|
||||
{
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 5
|
||||
}
|
||||
```
|
||||
|
||||
### Fulfill Reservation
|
||||
|
||||
Complete an order (items shipped):
|
||||
|
||||
```http
|
||||
POST /api/v1/store/inventory/fulfill
|
||||
{
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 5
|
||||
}
|
||||
```
|
||||
|
||||
This decreases both `quantity` and `reserved_quantity`.
|
||||
|
||||
---
|
||||
|
||||
## Reservation Workflow
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Order Created │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Reserve Items │ reserved_quantity += order_qty
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────┴────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────┐ ┌──────────┐
|
||||
│Cancel │ │ Ship │
|
||||
└───┬───┘ └────┬─────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────┐ ┌──────────────┐
|
||||
│ Release │ │ Fulfill │
|
||||
│reserved │ │ quantity -= │
|
||||
│ -= qty │ │ reserved -= │
|
||||
└─────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Admin Inventory Management
|
||||
|
||||
Administrators can manage inventory on behalf of any store through the admin UI at `/admin/inventory` or via the API.
|
||||
|
||||
### Admin UI Features
|
||||
|
||||
The admin inventory page provides:
|
||||
|
||||
- **Overview Statistics** - Total entries, stock quantities, reserved items, and low stock alerts
|
||||
- **Filtering** - Filter by store, location, and low stock threshold
|
||||
- **Search** - Search by product title or SKU
|
||||
- **Stock Adjustment** - Add or remove stock with optional reason tracking
|
||||
- **Set Quantity** - Set exact stock quantity at any location
|
||||
- **Delete Entries** - Remove inventory entries
|
||||
|
||||
### Admin API Endpoints
|
||||
|
||||
### List All Inventory
|
||||
|
||||
```http
|
||||
GET /api/v1/admin/inventory
|
||||
GET /api/v1/admin/inventory?store_id=1
|
||||
GET /api/v1/admin/inventory?low_stock=10
|
||||
```
|
||||
|
||||
### Get Inventory Statistics
|
||||
|
||||
```http
|
||||
GET /api/v1/admin/inventory/stats
|
||||
|
||||
Response:
|
||||
{
|
||||
"total_entries": 150,
|
||||
"total_quantity": 5000,
|
||||
"total_reserved": 200,
|
||||
"total_available": 4800,
|
||||
"low_stock_count": 12,
|
||||
"stores_with_inventory": 5,
|
||||
"unique_locations": 8
|
||||
}
|
||||
```
|
||||
|
||||
### Low Stock Alerts
|
||||
|
||||
```http
|
||||
GET /api/v1/admin/inventory/low-stock?threshold=10
|
||||
|
||||
Response:
|
||||
[
|
||||
{
|
||||
"product_id": 123,
|
||||
"store_name": "TechStore",
|
||||
"product_title": "USB Cable",
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 3,
|
||||
"available_quantity": 2
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Set Inventory (Admin)
|
||||
|
||||
```http
|
||||
POST /api/v1/admin/inventory/set
|
||||
{
|
||||
"store_id": 1,
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 100
|
||||
}
|
||||
```
|
||||
|
||||
### Adjust Inventory (Admin)
|
||||
|
||||
```http
|
||||
POST /api/v1/admin/inventory/adjust
|
||||
{
|
||||
"store_id": 1,
|
||||
"product_id": 123,
|
||||
"location": "WAREHOUSE_A",
|
||||
"quantity": 25,
|
||||
"reason": "Restocking from supplier"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Schema
|
||||
|
||||
### Inventory Table
|
||||
|
||||
```sql
|
||||
CREATE TABLE inventory (
|
||||
id SERIAL PRIMARY KEY,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id),
|
||||
store_id INTEGER NOT NULL REFERENCES stores(id),
|
||||
location VARCHAR NOT NULL,
|
||||
quantity INTEGER NOT NULL DEFAULT 0,
|
||||
reserved_quantity INTEGER DEFAULT 0,
|
||||
gtin VARCHAR,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
|
||||
UNIQUE(product_id, location)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_inventory_store_product ON inventory(store_id, product_id);
|
||||
CREATE INDEX idx_inventory_product_location ON inventory(product_id, location);
|
||||
```
|
||||
|
||||
### Constraints
|
||||
|
||||
- **Unique constraint:** `(product_id, location)` - One entry per product/location
|
||||
- **Foreign keys:** References `products` and `stores` tables
|
||||
- **Non-negative:** `quantity` and `reserved_quantity` must be >= 0
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Physical Products
|
||||
|
||||
1. **Create inventory entries** before accepting orders
|
||||
2. **Use meaningful location names** (e.g., `WAREHOUSE_MAIN`, `STORE_NYC`)
|
||||
3. **Monitor low stock** using the admin dashboard or API
|
||||
4. **Reserve on order creation** to prevent overselling
|
||||
|
||||
### Digital Products
|
||||
|
||||
1. **No inventory setup needed** - unlimited by default
|
||||
2. **Optional:** Create entries for license key tracking
|
||||
3. **Focus on fulfillment** - digital delivery mechanism
|
||||
|
||||
### Multi-Location
|
||||
|
||||
1. **Aggregate queries** use `Product.total_inventory` and `Product.available_inventory`
|
||||
2. **Location-specific** operations use the Inventory model directly
|
||||
3. **Transfers** between locations: adjust down at source, adjust up at destination
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Store Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/api/v1/store/inventory/set` | Set exact quantity |
|
||||
| POST | `/api/v1/store/inventory/adjust` | Add/remove quantity |
|
||||
| POST | `/api/v1/store/inventory/reserve` | Reserve for order |
|
||||
| POST | `/api/v1/store/inventory/release` | Cancel reservation |
|
||||
| POST | `/api/v1/store/inventory/fulfill` | Complete order |
|
||||
| GET | `/api/v1/store/inventory/product/{id}` | Product summary |
|
||||
| GET | `/api/v1/store/inventory` | List with filters |
|
||||
| PUT | `/api/v1/store/inventory/{id}` | Update entry |
|
||||
| DELETE | `/api/v1/store/inventory/{id}` | Delete entry |
|
||||
|
||||
### Admin Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| GET | `/api/v1/admin/inventory` | List all (cross-store) |
|
||||
| GET | `/api/v1/admin/inventory/stats` | Platform statistics |
|
||||
| GET | `/api/v1/admin/inventory/low-stock` | Low stock alerts |
|
||||
| GET | `/api/v1/admin/inventory/stores` | Stores with inventory |
|
||||
| GET | `/api/v1/admin/inventory/locations` | Unique locations |
|
||||
| GET | `/api/v1/admin/inventory/stores/{id}` | Store inventory |
|
||||
| GET | `/api/v1/admin/inventory/products/{id}` | Product summary |
|
||||
| POST | `/api/v1/admin/inventory/set` | Set (requires store_id) |
|
||||
| POST | `/api/v1/admin/inventory/adjust` | Adjust (requires store_id) |
|
||||
| PUT | `/api/v1/admin/inventory/{id}` | Update entry |
|
||||
| DELETE | `/api/v1/admin/inventory/{id}` | Delete entry |
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Product Management](../catalog/architecture.md)
|
||||
- [Admin Inventory Migration Plan](../../implementation/inventory-admin-migration.md)
|
||||
- [Store Operations Expansion](../../development/migration/store-operations-expansion.md)
|
||||
Reference in New Issue
Block a user