# AASAND — Inventory, Billing & Ledger Portal Core PHP + MySQL + Bootstrap 5. No framework, no Composer, no Node.js. Runs on standard shared hosting. ## Requirements - PHP **7.0+** (tested on 8.1) with `pdo_mysql`, `openssl`; `gd` and `fileinfo` recommended (logo upload) - MySQL 5.6+ / MariaDB 10.1+ (InnoDB) - Apache with `.htaccess` (or equivalent rules on nginx — see *Deployment*) > **About PHP 4:** the code uses PHP‑4‑style syntax where it's safe to (procedural functions, `array()`, no namespaces/closures/short-array syntax/`??`). > Real PHP 4 can't be supported securely: it has no PDO prepared statements, `password_hash`, CSPRNG (`random_bytes`), AES‑GCM, or `hash_equals`. > The bootstrap refuses to run below PHP 7.0 instead of falling back to insecure code. ## Installation 1. Upload the folder to your web root (e.g. `public_html/aasand`). 2. Make `config/` and `storage/` writable by PHP. 3. Open `https://your-domain/aasand/install/` and enter DB credentials plus the Super Admin account. - Or from the CLI: `php install/index.php --db-name=aasand --db-user=root --db-pass= --admin-user=superadmin --admin-pass='YourStr0ngPass' --company="AASAND Traders"` 4. **Delete the `install/` directory**, then make `config/config.local.php` read-only. 5. **Back up `config/config.local.php`.** Its `app_key` encrypts CNIC numbers, and if you lose it they can't be recovered. ## Architecture ``` index.php Front controller (routing, CSRF, auth, permission gate) config/ config.php (defaults) + config.local.php (generated secrets) app/routes.php Route whitelist: route → controller function + required permission app/core/ db, security (CSRF/headers/escaping), session, auth, acl, crypto, validator, audit, view, helpers app/models/ Business logic: inventory (stock_change), ledger, sale, purchase, party, report app/controllers/ One file per module (thin: validate → call model → render) app/views/ Templates per module + layout (all output escaped with e()) app/pdf/ Dependency-free PDF engine + invoice/statement/report layouts assets/css, assets/js Styles and CSP-safe external scripts (no inline JS) storage/ logs, sessions, uploads (web access denied) install/ Installer + schema.sql (delete after install) ``` **Adding a module:** add the permission rows to `permissions`, add routes in `app/routes.php`, then add a controller, views and (if needed) a model file. Model files load automatically, and there's a nav entry in `app/views/layout/header.php`. ## Roles & access | Role | Scope | |---|---| | **Super Admin** | Everything, including settings and creating Admins. Bypasses permission checks. | | **Admin** | Role defaults (all modules except Settings) plus per-user grants. All godowns. Can create Users. | | **User / Godown Manager** | Role defaults (dashboard, view products/customers/stock, create & view sales) plus grants. **Restricted to assigned godowns.** | - Everything is enforced server-side. Routes need a permission, and records are checked against godown scope (stock, movements, transfers, adjustments, sale allocations, purchases). Bills and purchases outside a user's godowns return 403 and are logged as `idor_blocked`. - Users can only manage users of a **lower** level, and can only grant permissions they hold themselves. - Without `sales.override_price`, the server ignores submitted rates and discounts and uses the customer-specific or default price. ## Key business rules - **Stock** is kept per godown (`godown_stock`). Every change goes through `stock_change()`, which locks the row (`SELECT … FOR UPDATE`), blocks negative stock, and writes an `inventory_movements` row (opening / in / out / closing / reference). - **Sales:** one bill can hold many products, and each line can be split across godowns (`sale_item_allocations`). The allocation total must equal the line quantity. The server recomputes everything: `Amount = Qty × Rate − line discount`, `Total = Subtotal − bill discount`, `Credit = Total − Paid`. The type (Cash / Credit / Cash + Credit) comes from the paid amount. The bill stores Previous Outstanding and Total Outstanding. - **Customer-specific prices** are in `customer_prices` (edit them on the customer page). Authorised users can override the rate per bill, and the standard rate is kept for audit. - **Vendor purchases** add stock to the chosen godown and update the vendor ledger (credit = purchase, debit = cash paid). No PDF is needed. - **Payments** record customer receipts and vendor payments against outstanding balances. - **Ledgers** are running balances (`balance_before` / `balance_after` on every entry). Statements work for daily, weekly, monthly or custom ranges, can filter by product (multi-select), and export to PDF. - **Duplicate-submit protection:** financial forms carry a one-time token. ## Security summary - PDO native prepared statements everywhere. Table and column names are never taken from user input. - Argon2id password hashing (bcrypt cost 12 as fallback) with automatic rehash, a strong password policy, and timing-safe login. - Brute-force throttling: 5 failures per username or 20 per IP in 15 minutes. All attempts are logged. - Sessions: strict mode, HttpOnly + SameSite cookie (Secure over HTTPS), ID regenerated on login and every 15 minutes, User-Agent binding, idle and absolute timeouts, and users re-checked against the DB on every request. - CSRF tokens on every POST plus an Origin/Referer check. State changes are POST-only. - XSS: all output goes through `htmlspecialchars`. Strict CSP with no inline scripts; data reaches JS through non-executable JSON blocks. - Headers: CSP, X-Frame-Options DENY, nosniff, Referrer-Policy, HSTS (on HTTPS). - CNICs are encrypted with AES-256-GCM and masked in lists and PDFs. - Uploads (logo): size and dimension limits, MIME checked with finfo + getimagesize, re-encoded through GD, random filename, stored outside the web root, and served via a controller. - `app/`, `config/`, `storage/` are denied by `.htaccess`. Errors are logged, not shown (`debug => false`). - Audit trail covers logins, users, permissions, products, price changes, stock adjustments and transfers, sales, purchases, payments, customers and vendors, settings, and denied access. ## Deployment checklist - Serve over **HTTPS**. - nginx: deny `/app`, `/config`, `/storage`, `/install` and dotfiles, e.g. `location ~ ^/(app|config|storage|install)/ { deny all; }`. - Set `display_errors=Off`. Keep `debug => false`. - Back up the database and `config/config.local.php` regularly.