This project is a simple sales and inventory API system designed to manage products, orders, and user authentication. It serves as a lightweight solution for small-scale operations, providing essential features for inventory tracking and order processing.
The system is built with a modern Python stack, featuring FastAPI for the web framework, Tortoise ORM for asynchronous database interaction, and uv for dependency management.
- Inventory Management: Includes support for product categories, allowing for better organization and filtering of items. Full CRUD operations for items and categories.
- Order Management: Facilitates creating and managing orders with real-time stock control. When an order is placed, stock is automatically decremented. Stock is replenished if an order is cancelled (under certain conditions). Order lifecycle events are tracked.
- User Accounts & Authentication: Provides a system for user registration and login (admins and customers). Role-based access control is implemented to protect administrative functions and associate orders with customers.
To run the development API server, use the following command:
uv run fastapi dev src/app/main.pyThe API will be accessible at http://127.0.0.1:8000.
This project uses Aerich for database migrations, which works with Tortoise ORM.
Before running migrations for the first time, you need to initialize the database and the Aerich migration environment.
Create initial database migration:
uv run aerich init-dbThis command creates the database file (if it doesn't exist) and the migration directory.
Create a new database migration
uv run aerich migrate --name <migration_name>Upgrade the database to the latest version
uv run aerich upgradeList all migrations
uv run aerich historyYou can test the database connection with the CLI command:
uv run src/app/cli/main.py test-db-connectionIt will report if the connection is successful and how many users are in the database.
│ * --username TEXT Username for the new admin. [default: None] [required] │ │ * --email TEXT Email for the new admin. [default: None] [required] │ │ * --password TEXT Password for the new admin. [default: None] [required]
You can create an admin user with the CLI command:
uv run src/app/cli/main.py create-admin --username admin --email [email protected] --password admin123- uv
- FastAPI
- TortoiseORM
- Aerich
- SQLite
- Svix-KSUID
- python-jose
- bcrypt
- pytest (for testing)
The application uses Python's standard logging module. Logging is configured in src/app/main.py.
Loggers are named hierarchically based on their module path (e.g., app.main, app.features.orders.router, app.features.inventory.service). This allows for fine-grained control over log output.
The root logger for this application is named app.
You can control the verbosity of different parts of the application by setting log levels.
-
Default Application Log Level: In
src/app/main.py, the default level for theapplogger is set:app_logger = logging.getLogger("app") app_logger.setLevel(logging.INFO) # Default is INFO
You can change
logging.INFOtologging.DEBUG,logging.WARNING, etc. -
Namespace-Specific Log Levels: You can override the default level for specific namespaces. For example, to get more detailed logs from the
ordersfeature, add or modify the following insrc/app/main.py:logging.getLogger("app.features.orders").setLevel(logging.DEBUG)
This will show
DEBUGmessages fromapp.features.ordersand its submodules (likeapp.features.orders.router), while other parts of the app might still be atINFO.
For more precise control, a NamespaceFilter is available. This filter allows you to specify exactly which namespaces should produce log output, effectively silencing others.
To use it, uncomment and configure the following lines in src/app/main.py:
# --- Namespace-based Filter (Optional) ---
# To only allow logs from specific top-level namespaces.
# For example, to only see logs from "app.features" and "app.main":
#
# allowed_log_namespaces = ["app.features.orders", "app.main"] # Example: only orders and main
# namespace_filter = NamespaceFilter(allowed_log_namespaces)
# console_handler.addFilter(namespace_filter)- Modify the
allowed_log_namespaceslist to include the namespaces you want to see. - If
allowed_log_namespacesis empty or not set, the filter will allow all log messages that otherwise meet the level requirements.