CoreConduit Inventory System
The production inventory system powering CoreConduit operations. Full-featured stock management with order tracking, customer CRM, and automated reporting. Evolved from years of OSWA-Inv customization.
The production inventory system powering CoreConduit operations. Full-featured stock management with order tracking, customer CRM, and automated reporting. Evolved from years of OSWA-Inv customization.
The CoreConduit Inventory System is what happened when OSWA-Inv met real-world nonprofit operations. After running OSWA-Inv for several years, I identified gaps that required custom development:
All sales must belong to an order. Delete an order and stock auto-restores. View order totals, print invoices, and manage by order number.
Every quantity change is logged with reason. No more "where did those 50 units go?" — full audit trail for compliance.
Customer database with contact info, order history, and notes. Search by customer when adding orders.
Products can have physical locations ("Warehouse A", "Shelf 3B"). Pick lists generated by order location.
Admin-editable currency selection covering 91+ ISO 4217 codes. Change from User Management → Settings — no config file editing required.
Admin, Supervisor, and User roles. Users can add sales but not delete. Supervisors can adjust stock with full audit trail. Role names match the codebase constants.
Multiple organizations per installation, each with full data isolation. Topbar org switcher appears when a user belongs to two or more orgs. Full org management UI for admins — create, rename, add members, soft-delete, and restore.
Users, customers, orders, sales, and stock records are soft-deleted rather than hard-purged. Admins can browse a trash view, restore records, or permanently purge — no data loss from accidental deletes.
# Update system
sudo apt update && sudo apt full-upgrade -y
# Install Apache, PHP, MySQL
sudo apt install -y apache2 php php-mysql php-gd php-mbstring php-json \
php-curl php-zip php-xml mariadb-server
# Enable mod_rewrite for pretty URLs
sudo a2enmod rewrite
sudo systemctl restart apache2
# Secure MySQL
sudo mysql_secure_installation
# Create database and user sudo mysql -u root CREATE DATABASE coreconduit_inventory CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'inv_user'@'localhost' IDENTIFIED BY 'your_strong_password_here'; GRANT ALL PRIVILEGES ON coreconduit_inventory.* TO 'inv_user'@'localhost'; FLUSH PRIVILEGES; EXIT;
# Clone repository (or extract from backup) cd /var/www/html sudo git clone https://github.com/coreconduit/inventory-system.git inventory # Or: sudo tar -xzf inventory-v3.5.tar.gz # Set permissions sudo chown -R www-data:www-data inventory/ sudo chmod -R 755 inventory/ sudo chmod -R 775 inventory/uploads/ sudo chmod -R 775 inventory/logs/ # Import database schema (schema.sql is at the project root) cd inventory sudo mysql -u inv_user -p coreconduit_inventory < schema.sql
# Copy the example env file and edit it cd /var/www/html/inventory sudo cp .env.example .env sudo nano .env # Set these values: DB_HOST=localhost DB_USER=inv_user DB_PASS=your_strong_password_here DB_NAME=coreconduit_inventory APP_SECRET=generate_a_long_random_string_here APP_LANG=en
.env at the project root, loaded by includes/config.php at runtime. Never commit your .env — it's in .gitignore. Currency symbol and formatting are managed through the admin panel (User Management → Settings) — no file editing required after first login.
# Create Apache config sudo nano /etc/apache2/sites-available/inventory.confServerName inventory.yourdomain.com DocumentRoot /var/www/html/inventory # Enable site and reload sudo a2ensite inventory sudo systemctl reload apache2Options -Indexes +FollowSymLinks AllowOverride All Require all granted ErrorLog ${APACHE_LOG_DIR}/inventory-error.log CustomLog ${APACHE_LOG_DIR}/inventory-access.log combined
AllowOverride All directive allows the included .htaccess file to enforce additional security rules (IP restrictions, XSS protection headers). Review .htaccess before deploying to production.
After installation, access the system and complete initial setup:
The system supports multiple organizations per installation with full row-level data isolation — each org sees only its own products, customers, orders, and sales. This is designed for consulting firms, fiscal sponsors, or any operator managing inventory across multiple departments or client organizations.
When a user belongs to two or more organizations, a switcher appears in the topbar. Clicking it shows all orgs with a checkmark on the active one. Switching takes effect immediately — all subsequent queries are scoped to the selected org.
Your answers shape what we write next.
The system includes backup.php at the project root. Run it directly or schedule via cron:
# Run a manual backup (as web user to match file permissions) sudo -u www-data php /var/www/html/inventory/backup.php # Schedule daily at 2 AM sudo crontab -e # Add: 0 2 * * * sudo -u www-data php /var/www/html/inventory/backup.php
Every form in the system includes a hidden CSRF token generated per-session. On POST, the server calls verify_csrf() before processing any data — requests that fail the check are rejected immediately. This is built in and requires no additional configuration.
# Verify CSRF is active by checking any edit form response # The token appears as a hidden input in every form: # <input type="hidden" name="csrf_token" value="...">
The Apache virtual host enforces a Content Security Policy header that restricts script and style sources to 'self' only. No inline styles, no external CDN scripts. This blocks a significant class of XSS attacks at the browser level.
# Add to your Apache VirtualHost (or .htaccess): Header always set Content-Security-Policy \ "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:"
# Set restrictive permissions on the .env file sudo chmod 640 /var/www/html/inventory/.env sudo chown root:www-data /var/www/html/inventory/.env # Disable PHP execution in uploads directory echo "\n Require all denied\n " | \ sudo tee /var/www/html/inventory/uploads/.htaccess
# Remove remote access for database user sudo mysql -u root REVOKE ALL PRIVILEGES ON *.* FROM 'inv_user'@'%'; FLUSH PRIVILEGES; # Enable query logging for audit (optional) SET GLOBAL general_log = 'ON'; SET GLOBAL general_log_file = '/var/log/mysql/inventory-queries.log'; EXIT;
# Install certbot sudo apt install certbot python3-certbot-apache # Obtain certificate sudo certbot --apache -d inventory.yourdomain.com # Auto-renewal is configured automatically sudo certbot renew --dry-run # Test renewal
sudo systemctl status mysql.env at the project rootmysql -u inv_user -p coreconduit_inventorysudo tail /var/log/mysql/error.logsudo tail /var/log/apache2/inventory-error.logphp -m | grep -E "mysqli|gd|mbstring"sudo ls -la /var/www/html/inventory/Edit php.ini:
sudo nano /etc/php/8.2/apache2/php.ini # Set session lifetime (in seconds) session.gc_maxlifetime = 3600 # 1 hour session.cookie_lifetime = 3600
If you're currently running OSWA-Inv and want to migrate:
The CoreConduit Inventory System is MIT licensed and available on GitHub:
Updates are released as features stabilize. To update your installation:
# Put system in maintenance mode (optional) sudo touch /var/www/html/inventory/.maintenance # Backup first (backup.php is at the project root, run as web user) sudo -u www-data php /var/www/html/inventory/backup.php # Pull updates (if using git) cd /var/www/html/inventory git pull origin main # Or extract new version over existing (keeping config) sudo tar -xzf inventory-v3.5.tar.gz --strip-components=1 # Run any new database migrations (numbered sequentially, apply in order) ls migrations/ sudo mysql -u inv_user -p coreconduit_inventory < migrations/005_users_soft_delete.up.sql # Clear cache sudo rm -rf /var/www/html/inventory/cache/* sudo touch /var/www/html/inventory/.updated # Remove maintenance mode sudo rm /var/www/html/inventory/.maintenance
Questions, experiences, or ideas — we're listening.