Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/InnoDev69/StockManager/llms.txt

Use this file to discover all available pages before exploring further.

StockManager stores all application data in a single SQLite file. The database is created and initialized automatically on first run by bd/bdInstance.py — no manual setup or migration command is required. The connection layer (bd/bdConector.py) applies a fixed set of PRAGMAs on every new connection and uses a thread-local pool to keep SQLite thread-safe inside Waitress’s multi-threaded environment.

Database File Location

The file path is resolved differently depending on how the application is running:
ModePath
DevelopmentValue of DB_PATH env var, or ./data/stock.db relative to the project root
Executable (Windows)%APPDATA%\StockManager\data\database.db
Executable (Linux / macOS)~/.stock_manager/data/database.db
In both modes, bd/bdInstance.py creates the parent directory with os.makedirs(exist_ok=True) before opening the file, so the path never needs to exist beforehand.

SQLite PRAGMA Settings

Every new connection applies these PRAGMAs immediately after sqlite3.connect():
PRAGMAValueEffect
foreign_keysONEnforces foreign-key constraints, which are disabled by default in SQLite.
journal_modeWALEnables Write-Ahead Logging for improved concurrency.
synchronousNORMALBalances durability and write performance; safe with WAL.
cache_size-8000Allocates approximately 8 MB of page cache per connection.
temp_storeMEMORYKeeps temporary tables and indices in memory rather than on disk.
WAL mode allows multiple readers to access the database simultaneously with a single writer, without blocking each other. This is important in Waitress’s multi-threaded context where several HTTP requests may query the database at the same time.

Thread-Safety and Connection Pool

StockManager does not share a single sqlite3.Connection object across threads. Instead, bdConector.py maintains a thread-local store (_thread_local = threading.local()) so that each Waitress worker thread gets its own independent connection:
  • db._get_conn() — returns the connection for the current thread, creating and configuring it on first access.
  • db.close_conn() — closes and discards the current thread’s connection. Should be called in a Flask teardown_appcontext hook if the application is run outside the PyWebView wrapper.

Write Operations — db.transaction()

with db.transaction() as cur:
    cur.execute("INSERT INTO sells (item_id, vendor_id, date, payment_method) VALUES (?, ?, ?, ?)", (...))
    cur.execute("UPDATE items SET quantity = quantity - ? WHERE id = ?", (...))
Use db.transaction() whenever a business operation requires multiple INSERT/UPDATE statements to succeed atomically. It commits on success and rolls back on any exception.

Read Operations — db._cursor()

with db._cursor() as cur:
    cur.execute("SELECT id, name, quantity FROM items WHERE status = 1")
    rows = cur.fetchall()
db._cursor() is the lower-level context manager used by most mixin methods. It also calls commit() after the block, making it suitable for single-statement writes as well.

Schema Overview

All tables are created in a single init_db() transaction on startup. Incremental column migrations are applied afterward via ALTER TABLE … ADD COLUMN (idempotent — duplicate-column errors are silently skipped).

items

Stores the product inventory.
ColumnTypeNotes
idINTEGER PRIMARY KEY
barrs_codeTEXT UNIQUEBarcode string; nullable
nameTEXT NOT NULL
descriptionTEXT
quantityINTEGERCurrent stock level; default 0
min_quantityINTEGERLow-stock threshold; default 5
priceREAL NOT NULL
expiration_dateTEXTISO date string; nullable
statusINTEGER1 = active, 0 = inactive; default 1
notified_low_stockINTEGERFlag to avoid duplicate low-stock alerts; default 0
created_atTEXT
updated_atTEXT

sells

Sales header — one row per transaction.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
item_idINTEGER NOT NULLReferences items(id)
dateTEXT NOT NULL
vendor_idINTEGER NOT NULLReferences users(id)
payment_methodTEXTDefault 'Efectivo'

details

Line items belonging to a sale.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
sell_idINTEGER NOT NULLReferences sells(id)
item_idINTEGER NOT NULLReferences items(id)
quantityINTEGER NOT NULL
priceREAL NOT NULLUnit price at time of sale
vendor_idINTEGER NOT NULLReferences users(id); denormalized for query convenience
payment_methodTEXTDefault 'Efectivo'

users

Application user accounts.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT UNIQUE
usernameTEXT NOT NULL
emailTEXT NOT NULL UNIQUE
passwordTEXT NOT NULLWerkzeug pbkdf2 hash
roleTEXT NOT NULLControlled by data/roles.py
statusINTEGER1 = active; default 1
applicationTEXTApproval state; default 'pending'
created_atTIMESTAMP
historyTEXT

notifications

Per-user in-app notification feed.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
user_idINTEGER NOT NULLReferences users(id) ON DELETE CASCADE
titleTEXT NOT NULL
messageTEXT
typeTEXT'info', 'warning', 'success', or 'error'; default 'info'
action_urlTEXTOptional deep-link
is_readINTEGER0 = unread; default 0
created_atTEXT

audit_log

Append-only record of user actions on entities.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
user_idINTEGER NOT NULLReferences users(id)
actionTEXT NOT NULLe.g. 'create', 'update', 'delete'
entity_typeTEXT NOT NULLe.g. 'item', 'user'
entity_idINTEGER
old_valueTEXTJSON snapshot before change
new_valueTEXTJSON snapshot after change
descriptionTEXT
ip_addressTEXT
timestampTEXTDefault CURRENT_TIMESTAMP
statusTEXTDefault 'success'

password_resets

Short-lived codes sent to users during the password-reset flow.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
emailTEXT NOT NULL
codeTEXT NOT NULLRandom reset code
created_atTIMESTAMPDefault CURRENT_TIMESTAMP

item_attributes

User-defined custom attribute definitions that can be attached to inventory items.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
nameTEXT NOT NULL UNIQUEDisplay name of the attribute
codeTEXT NOT NULL UNIQUEProgrammatic identifier
data_typeTEXT NOT NULLe.g. 'text', 'number', 'date'
requiredINTEGER1 = mandatory on items; default 0
statusINTEGER1 = active; default 1

item_attribute_values

Stores the per-item values for each custom attribute defined in item_attributes.
ColumnTypeNotes
idINTEGER PRIMARY KEY AUTOINCREMENT
item_idINTEGER NOT NULLReferences items(id)
attribute_idINTEGER NOT NULLReferences item_attributes(id)
valueTEXTStored as text regardless of data_type
updated_atTIMESTAMPDefault CURRENT_TIMESTAMP
The combination (item_id, attribute_id) is unique, ensuring each item holds at most one value per attribute.

Database Indexes

Several indexes are created at initialization to speed up common query patterns:
IndexTableColumns
idx_sells_date_vendor_idsells(date, vendor_id)
idx_sells_datesells(date)
idx_sells_vendor_idsells(vendor_id)
idx_details_sell_iddetails(sell_id)
idx_details_item_iddetails(item_id)
idx_items_nameitems(name)
idx_notifications_user_readnotifications(user_id, is_read)
idx_notifications_creatednotifications(created_at DESC)

Scheduled Maintenance

The background scheduler calls db._check_unique_root_user() every 30 minutes. This method counts users with the ROOT role; if more than one is found it logs a critical error and raises a DatabaseError to alert operators of a data-integrity problem. On first run, init_db() also calls __create_default_root_user() to seed an initial administrator account (username: root, email: root@root.com, password: root1234) if no ROOT user exists yet. Change this password immediately after the first login.

DB Viewer Utility

The repository ships with bdViewer.py, a standalone dark-mode SQLite browser built with customtkinter. It opens any .db file and lets you browse tables, run arbitrary SQL, inspect schemas, edit rows, and export data to CSV. Run it directly from the project root:
pip install customtkinter
python bdViewer.py
The viewer connects read/write to whichever file you open via its file dialog and does not depend on the rest of the StockManager application being running.

Build docs developers (and LLMs) love