Overview
The Inventory Management System uses SQLite (development) with SQLAlchemy ORM for database operations. The schema is organized around core business entities with well-defined relationships.Database Technology
- Database: SQLite (file:
inventory.db) - ORM: SQLAlchemy 2.x with declarative base
- Migrations: Manual schema evolution (no Alembic)
- Initialization: Automatic table creation via
Base.metadata.create_all()
backend/Database/config.py:1 for configuration.
Entity Relationship Diagram
Core Entities
1. Product
Central entity representing inventory items. Table:products
Location: backend/Product/Domain/product.py:6
id: UUID primary keysku: Stock Keeping Unit (unique identifier)name: Product namedescription: Detailed description (optional)category: Product category for groupingunit_measure: Measurement unit (kg, liters, units, etc.)unit_value: Base value for measurementis_perishable: Whether product has expirationexpiration_date: Expected expiration (if perishable)suggested_price: Recommended selling pricecreated_at,created_by,updated_at,updated_by: Audit fields (fromAuditableEntity)
- Primary key on
id - Unique index on
sku - Index on
name(for search) - Index on
category(for filtering)
- One-to-many with
Batch(product can have multiple batches) - One-to-many with
Movement(product has movement history) - One-to-many with
PriceHistory(tracks price changes)
2. Batch
Represents a specific lot/batch of products received. Table:batches
Location: backend/Product/Domain/batch.py:6
id: UUID primary keyproduct_id: Foreign key toproducts.idinitial_quantity: Original quantity receivedavailable_quantity: Current available quantity (decreases with sales)unit_cost: Cost per unit at purchase time (for FIFO costing)purchase_date: When batch was receivedexpiration_date: Batch-specific expiration (if applicable)supplier_id: Reference to supplier (optional)entry_transaction_ref: Reference to entry movement
- Used for FIFO (First-In-First-Out) inventory costing
available_quantityis updated when products are sold- Oldest batches are depleted first
3. Movement
Tracks all inventory movements (entries, exits, adjustments). Table:movements
Location: backend/Product/Domain/movement.py:12
id: UUID primary keyproduct_id: Foreign key to productsupplier_id: Foreign key to supplier (for ENTRY movements)customer_id: Foreign key to customer (for EXIT movements)type: Movement type (ENTRY, EXIT, ADJUSTMENT)quantity: Number of units moved (positive or negative)unit_price: Price per unit in this transactiontotal_price: Total transaction value (quantity × unit_price)total_cost: FIFO-calculated cost (important for profit calculation)reference_id: Link to external document (order, invoice)notes: Additional information
- ENTRY: Stock received (purchase, production, return)
- Creates or updates batches
- Links to supplier
- EXIT: Stock sold or consumed
- Depletes batches using FIFO
- Links to customer
- Calculates
total_costfrom batch costs
- ADJUSTMENT: Manual correction (damage, loss, count adjustment)
- Can be positive or negative
- Used for inventory reconciliation
4. Supplier
Represents vendors/suppliers of products. Table:suppliers
Location: backend/Stakeholder/Domain/supplier.py:7
id: UUID primary keynombre: Supplier nametipo_documento: Document type (RUC, DNI, etc.)numero_documento: Document number (unique identifier)direccion: Addresstelefono: Phone numberemail: Email (unique)plazo_entrega_dias: Delivery time in dayscondiciones_compra: Purchase terms and conditions
5. Customer
Represents buyers/customers. Table:customers
Location: backend/Stakeholder/Domain/customer.py:19
id: UUID primary keynombre: Customer nametipo_documento: Document type (RUC, DNI, OTRO)numero_documento: Document number (unique)direccion: Addresstelefono: Phone numberemail: Email (unique)condicion_pago: Payment condition (cash or credit)
6. User
System users with authentication. Table:users
Location: backend/User/Domain/user.py:6
id: UUID primary keyusername: Unique usernameemail: Unique email addresspassword_hash: Hashed password (never plain text)active: Account status (can be deactivated)role_id: Foreign key to role
- Passwords are hashed using Werkzeug security helpers
- Never stores plain text passwords
- Email can be used for password reset
7. Role
User roles for authorization. Table:roles
Location: backend/User/Domain/role.py:5
id: Auto-increment integer primary keyname: Role name (unique)description: Role description
- admin: Full system access
- gestor: Manager (can create/edit, not delete)
- consultor: Read-only access
backend/User/Domain/user_service.py for role seeding logic.
8. PriceHistory
Tracks product price changes over time. Table:price_history
Location: backend/Product/Domain/price_history.py
id: UUID primary keyproduct_id: Foreign key to productold_price: Previous pricenew_price: New pricereason: Reason for price changecreated_at: When price was changed (fromAuditableEntity)
9. AuditLog
Complete audit trail of all system operations. Table:audit_logs
Location: backend/Audit/Domain/audit_log.py:7
id: UUID primary keyuser_id: Who performed the actionuser_name: Username (denormalized for reporting)action: Type of action (CREATE, UPDATE, DELETE, READ)table_name: Which table was affectedrecord_id: ID of the affected recordold_values: JSON snapshot before changenew_values: JSON snapshot after changedescription: Human-readable descriptionip_address: User’s IP addresstimestamp: When action occurred
- Index on
user_id(find all actions by user) - Index on
table_name(find all actions on a table) - Index on
record_id(find all actions on a record) - Index on
timestamp(time-based queries)
Auditable Entity Mixin
All domain entities (exceptUser and Role) inherit from AuditableEntity.
Location: backend/CommonLayer/domain/autitable_entity.py:5
created_at: Set once on INSERT (UTC timestamp)created_by: User ID who created the recordupdated_at: Auto-updated on every UPDATEupdated_by: User ID who last modified the record
Relationships Summary
One-to-Many Relationships
| Parent | Child | Cascade | Description |
|---|---|---|---|
| Product | Batch | delete-orphan | Deleting product removes all batches |
| Product | Movement | delete-orphan | Deleting product removes history |
| Product | PriceHistory | delete-orphan | Deleting product removes price history |
| Supplier | Movement | none | Supplier can have many purchases |
| Customer | Movement | none | Customer can have many sales |
| Role | User | none | One role, many users |
Foreign Key Constraints
All foreign keys are enforced at the database level:Indexes
Strategic indexes for query performance:Primary Keys
All tables have indexed primary keys (automatic).Unique Indexes
products.sku: Prevent duplicate SKUssuppliers.numero_documento: Unique supplier identificationcustomers.numero_documento: Unique customer identificationusers.username: Unique usernamesusers.email: Unique email addressesroles.name: Unique role names
Lookup Indexes
products.name: Fast product searchproducts.category: Category filteringsuppliers.nombre: Supplier searchcustomers.nombre: Customer searchaudit_logs.user_id: Find actions by useraudit_logs.table_name: Find actions on tableaudit_logs.record_id: Find actions on recordaudit_logs.timestamp: Time-based queries
Database Configuration
Location:backend/Database/config.py:1
- StaticPool: Keeps single connection for SQLite
- check_same_thread: Disabled for multi-threaded Flask
- pool_pre_ping: Tests connections before use
- Scoped Sessions: Thread-safe session management
Initialization
Tables are created automatically on application startup: Location:backend/main.py:27
Data Types
SQLAlchemy to SQLite Mapping
| SQLAlchemy Type | SQLite Type | Example Usage |
|---|---|---|
String(N) | TEXT | Names, SKUs, emails |
Text | TEXT | Long descriptions |
Integer | INTEGER | Quantities, IDs |
Float | REAL | Prices, costs |
Boolean | INTEGER (0/1) | Flags (active, perishable) |
DateTime | TEXT (ISO 8601) | Timestamps |
Enum | TEXT | Movement types |
Common Patterns
UUIDs as Primary Keys:Migration Strategy
Current Approach
Manual schema evolution:- Modify domain model classes
- Delete
inventory.db(development only) - Restart application
- Tables recreated automatically
Production Recommendation
For production, implement proper migrations:- Alembic: SQLAlchemy migration tool
- Version control: Track schema changes
- Rollback support: Safe schema evolution
Query Examples
Get Product with Relationships
Calculate Total Stock
Movement History with Stakeholders
Audit Trail for Record
Performance Considerations
Indexes
- All foreign keys are indexed automatically
- Add indexes on frequently queried fields (name, SKU, category)
- Composite indexes for common filter combinations
Eager Loading
Usejoinedload to avoid N+1 query problems:
Connection Pooling
SQLite usesStaticPool (single connection). For PostgreSQL/MySQL in production, configure proper pool size:
Security Considerations
- SQL Injection Protection: SQLAlchemy parameterizes all queries automatically
- Password Storage: Never store plain text passwords (use
password_hash) - Audit Trail: All changes tracked with user ID and timestamp
- Soft Deletes: Consider adding
deleted_atcolumn instead of hard deletes - Data Validation: Validate at application layer before database insertion
Related Documentation
- Architecture Overview - Full system architecture
- Hexagonal Design - How domain models fit into the architecture
- API Reference - HTTP endpoints that interact with these entities