Overview
ShelfWise uses a PostgreSQL database with a carefully designed schema that supports multi-tenancy, complex inventory management, payroll processing, and e-commerce operations. The schema follows Laravel conventions with additional patterns for tenant isolation and soft deletes.All tenant-scoped tables include a
tenant_id foreign key with cascade delete for automatic cleanup when a tenant is removed.Core Domain Model
Tenants Table
The root of multi-tenancy:Subscription Plans
Subscription Plans
trial- Free trial period (default 14 days)basic- Basic subscription tierpremium- Premium subscription tierenterprise- Enterprise custom pricing
Resource Limits
Resource Limits
Resource limits are enforced in the Tenant model:
Users Table
Staff members who operate the system:User-Shop Relationship
Users can be assigned to specific shops:Products & Inventory
Products Table
Products use a product-variant model. A product can have multiple variants (sizes, colors) or be a simple product with one default variant.
Product Variants Table
Inventory Locations Table
Tracks stock quantities at different locations:Stock Movements Table
Audit trail for all inventory changes:Orders & Sales
Orders Table
Order Items Table
Order items use polymorphic relationships to support both products and services. The
sellable_type and sellable_id columns point to either ProductVariant or ServiceVariant.Indexing Strategy
Composite Indexes
All tenant-scoped queries benefit from composite indexes withtenant_id first:
Performance Patterns
Tenant-First Indexing
Tenant-First Indexing
Always put
tenant_id first in composite indexes since every query filters by tenant:Foreign Key Indexes
Foreign Key Indexes
Laravel doesn’t automatically create indexes on foreign keys. Always add them:
Soft Delete Queries
Soft Delete Queries
Add
deleted_at IS NULL to frequently-used queries:Cascade Delete Strategy
When Tenant is Deleted
All tenant-scoped data is automatically deleted:- All users
- All shops
- All products and variants
- All orders and order items
- All inventory locations and stock movements
- All payroll data
When User is Deleted
UUID vs Auto-Increment
Soft Deletes vs is_active
Many models use BOTH soft deletes andis_active flags:
| State | is_active | deleted_at | Use Case |
|---|---|---|---|
| Active | true | null | Fully visible and operational |
| Inactive | false | null | Hidden from sales, visible in admin |
| Deleted | N/A | timestamp | Completely hidden, can be restored |
Related Documentation
- Multi-Tenancy - How tenant isolation is enforced
- Service Layer - Business logic that interacts with this schema
- Authorization - User roles and permissions