- Overview
- Features
- Technical Pros
- Roles & Permissions
- Getting Started
- API Documentation
- Complaints & Feature Requests
InventoryFlow is a high-performance, asynchronous inventory management API built with Python using the FastAPI framework. It leverages SQLAlchemy for ORM-based database interactions and Alembic for managing database migrations. It supports role-based access, stock tracking, customer/supplier management, and automated email notifications – all wrapped in a sleek, testable REST API.
The system manages inventory by tracking products, stock levels, suppliers, and customers. Incoming and outgoing orders affect the stock accordingly. Admins can monitor stock flow, while customers and suppliers receive relevant email notifications.
Built with scalability, security, and developer experience in mind, InventoryFlow is ideal for small-to-medium businesses, dev demos, or as a base for more complex ERP systems.
- ✅ CRUD operations for Products, Categories, Customers, and Suppliers
- 📦 Track stock, incoming & outgoing orders
- 🔐 Authentication & Authorization with JWT and role-based access
- 📬 Email notifications to suppliers and customers
- 📊 Admin-friendly dashboard endpoints with analytics
- 🔍 **Filtering, and searching for large datasets
- 🔁 Automated unit/integration testing (Pytest)
- 📄 Interactive API docs with Swagger (OpenAPI)
- FastAPI: Provides a modern, high-performance web framework for building the API endpoints.
- SQLAlchemy (Asyncio): Implements an asynchronous Object-Relational Mapper (ORM) for efficient and non-blocking database communication.
- Alembic: Handles database schema migrations, ensuring database state is consistent with application models.
- Pydantic: Enforces strict data validation for request and response models.
- JWT Authentication: Secures endpoints using JSON Web Tokens (JWT) for user authentication and authorization.
- Role-Based Access Control: Implements user roles (e.g., admin, customer) to restrict access to sensitive operations.
- Structured Logging: Utilizes a custom JSON formatter and the Rich library for clear, structured, and easy-to-parse application logs.
| Role | Capabilities |
|---|---|
| Admin | Full access to all endpoints and data |
| Staff | Manage inventory, suppliers, customers, and view dashboards |
| Customer | Limited access: view products, place orders |
- Python 3.10+
- PostgreSQL/MySQL
- SMTP credentials
- UV (optional but recommended)
UV is the recommended way to install and manage InventoryFlow. It's faster and handles dependencies more efficiently.
-
Clone the repository:
git clone https://github.com/NewGenesis04/InventoryFlow.git cd InventoryFlow -
Install dependencies with UV:
uv sync
-
Clone the repository:
git clone https://github.com/NewGenesis04/InventoryFlow.git cd InventoryFlow -
Create a virtual environment:
python -m venv .venv source .venv/bin/activate # On Windows, use `venv\Scripts\activate`
-
Install dependencies:
pip install -r requirements.txt
-
Set up environment variables:
- Copy the example environment file:
cp .env.example .env
- Edit the
.envfile with your database URL and JWT credentials. See Environment Variables.
- Copy the example environment file:
-
Run database migrations:
alembic upgrade head
-
Run the application:
- With UV (No need to enable virtual environment, UV does that by default with "uv run"):
uv run uvicorn app.main:app --reload
- With pip (Ensure virtual environment is enabled first!):
uvicorn app.main:app --reload
The API will be available at
http://localhost:8000. - With UV (No need to enable virtual environment, UV does that by default with "uv run"):
Create a .env file in the root directory and add the following variables:
| Variable | Description | Example |
|---|---|---|
DB_URL |
Your database connection URL | postgresql+asyncpg://user:password@host:port/dbname |
JWT_SECRET_KEY |
Secret key for JWT encoding | your-super-secret-key-that-is-long-and-secure |
JWT_ALGORITHM |
Algorithm for JWT encoding | HS256 |
http://localhost:8000
Description: Checks the API status and database connectivity.
Request: No payload required.
Response:
{
"message": "This is the root endpoint of the InventoryFlow API",
"status": "healthy",
"database": "connected"
}Errors:
500 Internal Server Error: Database connection failed.
Description: Registers a new user.
Request:
{
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"password": "strongpassword123",
"role": "admin"
}Response:
{
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"role": "admin",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:00:00Z"
}Errors:
400 Bad Request: Email already registered.500 Internal Server Error: Error creating new user.
Description: Authenticates a user and returns JWT tokens.
Request:
{
"email": "[email protected]",
"password": "strongpassword123"
}Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}Errors:
400 Bad Request: Incorrect email or password.
Description: Retrieves the profile of the currently authenticated user. (Requires authentication)
Request: No payload required. Authorization header with bearer token is mandatory.
Response:
{
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"role": "admin",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:00:00Z"
}Errors:
401 Unauthorized: Invalid token or user not found.
Description: Creates a new product category. (Admin role required)
Request:
{
"name": "Electronics",
"description": "Gadgets and electronic devices"
}Response:
{
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:00:00Z"
}Errors:
401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.500 Internal Server Error: Failed to create the category.
Description: Retrieves a list of all product categories.
Request: No payload required.
Response:
[
{
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:00:00Z"
}
]Errors:
500 Internal Server Error: Failed to fetch categories.
Description: Retrieves a single category by its ID.
Request: No payload required.
Response:
{
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:00:00Z"
}Errors:
404 Not Found: Category not found.500 Internal Server Error: Failed to fetch the category.
Description: Updates an existing category. (Admin role required)
Request:
{
"name": "Consumer Electronics",
"description": "Updated description for gadgets"
}Response:
{
"id": 1,
"name": "Consumer Electronics",
"description": "Updated description for gadgets",
"created_at": "2023-10-27T10:00:00Z",
"updated_at": "2023-10-27T10:05:00Z"
}Errors:
401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.404 Not Found: Category not found.500 Internal Server Error: Failed to update the category.
Description: Deletes a category by its ID. (Admin role required)
Request: No payload required.
Response:
202 Accepted
{
"detail": "Category with ID (1) has been deleted successfully"
}Errors:
401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.404 Not Found: Category with the specified ID not found.500 Internal Server Error: Failed to delete the category.
Description: Creates a new product. (Admin role required)
Request:
{
"name": "Laptop Pro",
"description": "A high-end laptop",
"price": 1200,
"category_id": 1
}Response:
{
"id": 1,
"name": "Laptop Pro",
"description": "A high-end laptop",
"price": 1200,
"category_id": 1,
"created_at": "2023-10-27T10:10:00Z",
"updated_at": "2023-10-27T10:10:00Z",
"category": {
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices"
}
}Errors:
400 Bad Request: Product with the same name already exists.401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.500 Internal Server Error: Error in creating product.
Description: Retrieves a list of all products.
Request: No payload required.
Response:
[
{
"id": 1,
"name": "Laptop Pro",
"price": 1200,
"category_id": 1
}
]Errors:
400 Bad Request: No products found.500 Internal Server Error: Failed to fetch products.
Description: Retrieves a single product by its ID.
Request: No payload required.
Response:
{
"id": 1,
"name": "Laptop Pro",
"description": "A high-end laptop",
"price": 1200,
"category_id": 1,
"created_at": "2023-10-27T10:10:00Z",
"updated_at": "2023-10-27T10:10:00Z",
"category": {
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices"
}
}Errors:
400 Bad Request: No product with the specified ID found.500 Internal Server Error: Failed to fetch product.
Description: Updates an existing product. (Admin role required)
Request:
{
"price": 1150,
"description": "An updated high-end laptop"
}Response:
{
"id": 1,
"name": "Laptop Pro",
"description": "An updated high-end laptop",
"price": 1150,
"category_id": 1,
"created_at": "2023-10-27T10:10:00Z",
"updated_at": "2023-10-27T10:15:00Z",
"category": {
"id": 1,
"name": "Electronics",
"description": "Gadgets and electronic devices"
}
}Errors:
400 Bad Request: No product with the specified ID found.401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.500 Internal Server Error: Failed to update product.
Description: Deletes a product by its ID. (Admin role required)
Request: No payload required.
Response:
202 Accepted
{
"detail": "Product with ID (1) has been deleted successfully"
}Errors:
400 Bad Request: No product with the specified ID found.401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.500 Internal Server Error: Failed to delete product.
Description: Retrieves a list of all stock entries.
Request: No payload required.
Response:
[
{
"id": 1,
"product_id": 1,
"available_quantity": 50,
"batch_number": "BATCH001"
}
]Errors:
404 Not Found: No stock entries found.500 Internal Server Error: Failed to fetch stock entries.
Description: Retrieves a specific stock entry by its ID.
Request: No payload required.
Response:
{
"id": 1,
"product_id": 1,
"available_quantity": 50,
"batch_number": "BATCH001",
"expiry_date": "2025-12-31T00:00:00Z",
"created_at": "2023-10-27T10:20:00Z",
"updated_at": "2023-10-27T10:20:00Z",
"product": {
"id": 1,
"name": "Laptop Pro",
"price": 1200
}
}Errors:
404 Not Found: Stock with the specified ID not found.500 Internal Server Error: Failed to fetch stock entry.
Description: Manually updates the quantity of a stock entry. (Admin role required)
Request:
{
"available_quantity": 45
}Response:
{
"id": 1,
"product_id": 1,
"available_quantity": 45,
"batch_number": "BATCH001",
"expiry_date": "2025-12-31T00:00:00Z",
"created_at": "2023-10-27T10:20:00Z",
"updated_at": "2023-10-27T10:25:00Z",
"product": {
"id": 1,
"name": "Laptop Pro",
"price": 1200
}
}Errors:
401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.404 Not Found: Stock with the specified ID not found.500 Internal Server Error: Failed to update stock entry.
Description: Creates a new incoming order from a supplier and updates stock. (Admin role required)
Request:
{
"supplier_id": 1,
"product_id": 1,
"batch_number": "BATCH001",
"quantity": 50,
"unit_cost": 800,
"supply_date": "2023-10-27T10:20:00Z",
"expiry_date": "2025-12-31T00:00:00Z"
}Response:
{
"id": 1,
"supplier_id": 1,
"product_id": 1,
"batch_number": "BATCH001",
"quantity": 50,
"unit_cost": 800,
"total_cost": 40000,
"supply_date": "2023-10-27T10:20:00Z",
"status": "pending",
"supplier": { "id": 1, "name": "Supplier A" },
"product": { "id": 1, "name": "Laptop Pro" }
}Errors:
401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.404 Not Found: Product or Supplier not found.500 Internal Server Error: Failed to create incoming order.
Description: Retrieves a list of all incoming orders.
Request: No payload required.
Response:
[
{
"id": 1,
"supplier_id": 1,
"product_id": 1,
"quantity": 50,
"total_cost": 40000,
"status": "pending"
}
]Errors:
404 Not Found: No incoming orders found.500 Internal Server Error: Failed to fetch incoming orders.
Description: Retrieves a specific incoming order by its ID.
Request: No payload required.
Response:
{
"id": 1,
"supplier_id": 1,
"product_id": 1,
"batch_number": "BATCH001",
"quantity": 50,
"unit_cost": 800,
"total_cost": 40000,
"supply_date": "2023-10-27T10:20:00Z",
"status": "pending",
"supplier": { "id": 1, "name": "Supplier A" },
"product": { "id": 1, "name": "Laptop Pro" }
}Errors:
404 Not Found: Incoming order with the specified ID not found.500 Internal Server Error: Failed to fetch incoming order.
Description: Creates a new outgoing order for a customer and decreases stock. (Admin role required)
Request:
{
"customer_id": 1,
"product_id": 1,
"stock_id": 1,
"quantity": 2,
"order_date": "2023-10-27T11:00:00Z"
}Response:
{
"id": 1,
"customer_id": 1,
"product_id": 1,
"stock_id": 1,
"quantity": 2,
"unit_price": 1200,
"total_price": 2400,
"order_date": "2023-10-27T11:00:00Z",
"status": "pending",
"customer": { "id": 1, "first_name": "Jane", "last_name": "Smith" },
"product": { "id": 1, "name": "Laptop Pro" }
}Errors:
400 Bad Request: Insufficient stock.401 Unauthorized: Authentication required.403 Forbidden: Insufficient permissions.404 Not Found: Stock, Product, or Customer not found.500 Internal Server Error: Failed to create outgoing order.
Description: Retrieves a list of all outgoing orders.
Request: No payload required.
Response:
[
{
"id": 1,
"customer_id": 1,
"product_id": 1,
"quantity": 2,
"total_price": 2400,
"status": "pending"
}
]Errors:
404 Not Found: No outgoing orders found.500 Internal Server Error: Failed to fetch outgoing orders.
Description: Retrieves a specific outgoing order by its ID.
Request: No payload required.
Response:
{
"id": 1,
"customer_id": 1,
"product_id": 1,
"stock_id": 1,
"quantity": 2,
"unit_price": 1200,
"total_price": 2400,
"order_date": "2023-10-27T11:00:00Z",
"status": "pending",
"customer": { "id": 1, "first_name": "Jane", "last_name": "Smith" },
"product": { "id": 1, "name": "Laptop Pro" }
}Errors:
404 Not Found: Outgoing order with the specified ID not found.500 Internal Server Error: Failed to fetch outgoing order.
We welcome feedback, feature requests, and bug reports! To submit a complaint or request a new feature, please open a GitHub issue:
- Navigate to the Issues page
- Click on New Issue
- Use the appropriate tag:
- 🐛
bug- For reporting bugs or problems - ✨
feature- For suggesting new features or improvements - 📝
documentation- For documentation-related issues - ❓
question- For general questions
- 🐛
Please provide as much detail as possible to help us understand and address your request effectively.