QuickMart IOMS is a server-rendered inventory and order-management system for retail operations. It is implemented with PHP, MariaDB, PDO, vanilla JavaScript, CSS, and Apache.
This document describes the system as it exists in the repository. It is an engineering handoff document, not a product brochure. The backend is the authority for authentication, authorization, inventory, prices, totals, order history, and role policy. The browser is responsible for presentation and user interaction only.
- Preserve backend authority. The client must not derive or override prices, totals, stock, order IDs, roles, or account state.
- Keep business rules in application services, repositories, and the database; PHP views compose presentation only.
- Prefer explicit validation, transactions, prepared statements, and clear failure handling over implicit framework behavior.
- Keep the current procedural/global PHP architecture compatible. Composer is a small bootstrap aid, not a reason to perform an unreviewed namespace migration.
- Use isolated databases for destructive verification. Do not use the runtime database as a test fixture.
The UI is an RTL-first operations console with Arabic-friendly typography, explicit inventory states, and responsive layouts. Visual design is subordinate to operational clarity and accessibility.
- Product catalog and inventory tracking with normal, low-stock, and out-of-stock states.
- Sell orders with transactional stock deduction and insufficient-stock protection.
- Purchase orders with transactional stock replenishment.
- Historical order details using the price stored at the time of the order.
- Role-based access for
Admin,Manager, andStaff. - Admin-only staff management and reporting.
- Authenticated user profile and password management.
- Dashboard inventory health, recent orders, order details, and report summaries.
- CSRF protection, password hashing, prepared SQL statements, foreign-key integrity, and session revalidation.
Admin-only staff creation is available through the Staff Create API. The staff-management contract also supports listing, viewing, updating, deleting, profile updates, and password changes.
- PHP 8.0+
- MariaDB 10.4+ with InnoDB transactions
- PDO for database access
- Vanilla JavaScript and CSS
- Apache through XAMPP or an equivalent PHP web-server setup
- Composer 2 for generating the production autoload metadata
- Node.js/npm for reproducible production CSS and JavaScript builds; runtime Bootstrap and Poppins assets are self-hosted
The application has three deliberate boundaries:
- PHP views render protected screens and load the shared shell.
- JSON API entry points authenticate and validate requests before invoking application services.
- Repositories are the database boundary. MariaDB constraints and transactions protect inventory and historical order data.
flowchart LR
browser["Browser<br/>RTL UI + local dist assets"]
views["PHP views<br/>shared shell + partials"]
api["API entry points<br/>JSON + security headers"]
bootstrap["Bootstrap<br/>config + helpers + PDO"]
guards["Session / CSRF / role guards"]
services["Application services<br/>business operations"]
repos["Repositories<br/>parameterized SQL"]
db[("MariaDB<br/>InnoDB")]
browser -->|HTML navigation| views
browser -->|same-origin JSON| api
views -->|protected-page guard| guards
api --> bootstrap
views --> bootstrap
bootstrap --> guards
guards --> services
services --> repos
repos --> db
db --> repos
repos --> services
services --> api
api -->|JSON response| browser
backend/bootstrap.php loads the optional Composer autoloader and then the
legacy configuration and helper files in deterministic order. API entry points
continue through backend/api/bootstrap.php, which adds the database handle,
JSON content type, and baseline security headers. Existing view entry points
retain their protected-view include conventions.
The frontend uses the shared apiFetch boundary and server-authoritative
session probing. sessionStorage can cache display hints after a successful
probe, but it never grants authentication or role access.
QuickMart-IOMS-main/
├── assets/
│ ├── common.css # Shared design tokens and application shell
│ ├── common.js # Shared frontend utilities and apiFetch
│ ├── dashboard/ # Dashboard styles and behavior
│ ├── products/ # Product page styles and behavior
│ ├── orders/ # Order list and creation behavior
│ ├── create-order/ # Order creation assets
│ ├── order-details/ # Order detail assets
│ ├── reports/ # Reporting assets
│ ├── staff/ # Staff management assets
│ ├── profile/ # Profile assets
│ ├── fonts/ # Self-hosted Poppins subsets and license
│ ├── vendor/bootstrap/ # Bootstrap 5.3.0 local CSS/JS bundle
│ └── login-signup/ # Login assets
├── dist/css/ # Generated production CSS
├── dist/js/ # Generated production JavaScript
├── scripts/build-css.js # Reproducible CSS minification entrypoint
├── scripts/build-js.js # Reproducible JavaScript minification entrypoint
├── backend/
│ ├── bootstrap.php # Composer-aware application bootstrap with local fallback
│ ├── api/ # JSON API endpoints
│ ├── application/ # Application services
│ ├── core/ # Configuration, database, auth, and helpers
│ ├── infrastructure/ # Repository implementations
│ └── views/ # Protected PHP views and shared shell partials
├── database/
│ ├── schema.sql # Current baseline schema
│ ├── data.sql # Optional disposable demo data
│ └── migrations/ # Incremental migrations 001 through 006
├── .env.example # Environment variable names only
├── composer.json # PHP requirement and narrow legacy classmap
├── package.json # Pinned frontend build tool
├── package-lock.json # npm dependency lockfile
├── index.php # Application entry point
└── README.md
- XAMPP or an equivalent Apache/PHP/MariaDB environment.
- PHP 8.0 or newer.
- MariaDB 10.4 or newer.
- A modern browser.
git clone https://github.com/mohammad-emad-dev/QuickMart-IOMS.gitFor the default Windows XAMPP layout, place the project at:
C:\xampp\htdocs\QuickMart-IOMS-main
The application has no third-party Composer dependency. For staging and production, generate the optimized autoloader from the repository root and do not commit the generated vendor/ directory:
composer install --no-dev --optimize-autoloaderAll PHP entrypoints converge on backend/bootstrap.php. It loads vendor/autoload.php when present and otherwise uses the verified procedural fallback, which keeps local XAMPP development working without Composer. The current codebase remains global/procedural; no PSR-4 namespace migration is implied.
From the repository root, install the pinned build tools and regenerate the production CSS and JavaScript before serving the application:
npm ci
npm run build
Readable CSS and JavaScript remain under assets/; the PHP views and login
page load generated dist/css/*.min.css and dist/js/*.min.js files.
Bootstrap 5.3.0, the Poppins Latin weights used by Create Order, and the
project JavaScript outputs are local, so reviewed pages do not depend on a CDN
at runtime. See
docs/FRONTEND-BUILD.md for asset ownership and font
license details.
The application does not read a .env file. Configure these variables through Apache SetEnv, Windows environment variables, or the PHP runtime. Use .env.example as the variable-name reference:
QUICKMART_DB_HOST
QUICKMART_DB_NAME
QUICKMART_DB_USER
QUICKMART_DB_PASSWORD
QUICKMART_ALLOWED_ORIGIN
QUICKMART_RATE_LIMIT_SECRET
QUICKMART_RATE_LIMIT_SECRET is optional for local development and should be a high-entropy deployment secret in production. It protects the one-way login limiter keys from offline correlation. Never commit a real password or other secret. QUICKMART_ALLOWED_ORIGIN may remain empty for a same-origin local deployment.
Import the current baseline schema into a disposable local database:
SOURCE /path/to/QuickMart-IOMS-main/database/schema.sql;Optional demo data can be imported afterward:
SOURCE /path/to/QuickMart-IOMS-main/database/data.sql;The demo data is for local testing only. Rotate or replace seeded credentials before using the application in any shared environment.
For an existing database that predates the current baseline, review and apply migrations 001 through 006 in order using the project’s migration process. Migration 006 creates the persistent login-attempt limiter table. Do not apply migrations blindly to a production database.
Create a logical backup before applying migrations or deploying. Use a least-privilege database account for shared or production environments and keep the dump outside the repository:
mysqldump -u <database_user> -p quickmart_db > quickmart_db_backup.sqlRestore only to a verified target, preferably a disposable database first:
mysql -u <database_user> -p quickmart_db < quickmart_db_backup.sqlPause writes during a production restore, verify foreign keys and row counts afterward, and never commit backup files or database credentials. The tracked .htaccess database fallback is for local XAMPP review only; production deployments must provide the QUICKMART_* values through server environment configuration.
Start Apache and MariaDB from the XAMPP Control Panel, then open:
http://localhost/QuickMart-IOMS-main/
Useful direct review pages include:
http://localhost/QuickMart-IOMS-main/assets/login-signup/login.html
http://localhost/QuickMart-IOMS-main/backend/views/dashboard.php
Default account credentials are intentionally not documented. Use disposable local seed data or provision accounts through an approved administrative process.
For the complete staging and production handoff runbook, see docs/PRODUCTION-HANDOFF.md.
The database accepts exactly these roles:
| Role | Access summary |
|---|---|
Admin |
Full administrative access, staff management, all orders, and reports. |
Manager |
Authenticated operational access permitted by each endpoint; no Admin-only staff or report access. |
Staff |
Authenticated operational access permitted by each endpoint, including own profile/password and owned orders; no Admin-only staff or report access. |
The backend is authoritative for authorization. Client-side role hints are used only to shape the interface and never grant access.
All API responses use the project’s JSON response helpers and the existing { "success": true, "data": ... } success shape where applicable.
| Method | Endpoint | Purpose |
|---|---|---|
POST |
backend/api/auth/login.php |
Authenticate a staff member. |
POST |
backend/api/auth/logout.php |
End the current session. |
GET |
backend/api/auth/csrf.php |
Return the authenticated session CSRF token. |
GET |
backend/api/auth/session.php |
Revalidate the server-side session and return safe UI identity data. |
POST |
backend/api/auth/forgot_password.php |
Intentionally disabled with HTTP 503 until secure delivery is available. |
| Method | Endpoint | Purpose |
|---|---|---|
GET |
backend/api/products/list.php |
List products. |
GET |
backend/api/products/get.php?id=... |
Read one product. |
POST |
backend/api/products/create.php |
Create a product where authorized. |
PUT |
backend/api/products/update.php |
Update a product where authorized. |
DELETE |
backend/api/products/delete.php |
Delete a product where authorized. |
| Method | Endpoint | Purpose |
|---|---|---|
GET |
backend/api/orders/list.php |
List authorized orders with existing filters. |
GET |
backend/api/orders/get.php?id=... |
Read an authorized order and its stored detail prices. |
POST |
backend/api/orders/create.php |
Create a sell or purchase order transactionally. |
| Method | Endpoint | Purpose |
|---|---|---|
GET |
backend/api/staff/list.php |
Admin-only staff list. |
GET |
backend/api/staff/get.php?id=... |
Read a permitted staff record. |
POST |
backend/api/staff/create.php |
Admin-only creation of a staff account with an initial password. |
POST |
backend/api/staff/update.php |
Admin-only staff update. |
POST |
backend/api/staff/delete.php |
Admin-only staff deletion with order-history protection. |
POST |
backend/api/staff/update-profile.php |
Update the authenticated user’s profile. |
POST |
backend/api/staff/change-password.php |
Change the authenticated user’s password. |
| Method | Endpoint | Purpose |
|---|---|---|
GET |
backend/api/reports/stats.php |
Admin-only dashboard and reporting metrics. |
The database is MariaDB using InnoDB. Referential integrity, check constraints, unique keys, row locks, and transactions are part of the application contract.
erDiagram
STAFF ||--o{ ORDERS : creates
STAFF ||--o{ PASSWORD_RESET_TOKENS : owns
ORDERS ||--|{ ORDER_DETAILS : contains
PRODUCTS ||--o{ ORDER_DETAILS : referenced_by
STAFF {
varchar Staff_ID PK
varchar Full_Name
varchar Email UK
varchar Password
varchar Phone_Number
varchar Role
int Auth_Revision
}
PRODUCTS {
varchar Product_ID PK
varchar Name
varchar Category
int Quantity
decimal Price
varchar Status
int Threshold
}
ORDERS {
varchar Order_ID PK
varchar Staff_ID FK
datetime Order_Date
varchar Order_Type
varchar Party_Name
}
ORDER_DETAILS {
int Detail_ID PK
varchar Order_ID FK
varchar Product_ID FK
int Ordered_Qty
decimal Sold_Price
}
PASSWORD_RESET_TOKENS {
bigint Reset_ID PK
varchar Staff_ID FK
char Token_Hash UK
datetime Expires_At
datetime Used_At
datetime Revoked_At
datetime Created_At
}
LOGIN_RATE_LIMITS {
char Rate_Key PK
datetime Window_Started_At
smallint Attempt_Count
datetime Last_Attempt_At
}
LOGIN_RATE_LIMITS is intentionally independent of STAFF: it must also
handle unknown identifiers without exposing account existence.
The current schema includes:
Staffwith canonical roles andAuth_Revisionfor future session invalidation.Productswith stock, price, threshold, and status constraints.OrdersandOrder_Detailswith restricted history-preserving foreign keys.Login_Rate_Limitswith bounded, one-way identifier/client buckets for concurrent login throttling.Password_Reset_Tokensstoring only case-sensitive SHA-256 token hashes, with expiry, use, revocation, and cleanup indexes.
Data integrity rules that should not be moved into the browser:
Order_Details.Sold_Priceis the historical unit price. Order history does not recalculate from the current product price.- Sell and Purchase operations update stock inside a transaction. Insufficient stock, missing products, duplicate order IDs, and transaction failures must leave no partial order or stock mutation.
- Foreign keys use restrictive deletion for products, orders, and order staff references so historical records remain valid.
Staff.Emailis unique. Roles are constrained toAdmin,Manager, andStaff;Auth_Revisionstarts at 1 and invalidates stale sessions.- Product quantity, price, status, and threshold constraints are enforced in the schema as well as at the application boundary.
database/schema.sqlis a fresh-install baseline and drops existing tables. Use it only for an empty or disposable database. Existing databases require migrations001through006in order.
The public password-reset request remains disabled because no secure email or
token-delivery provider is configured. The internal token lifecycle must not be
treated as a user-facing recovery flow until delivery and global session
invalidation requirements are completed. Login attempts are limited to five
valid-shaped attempts per identifier/client bucket in a 15-minute window; the
sixth receives HTTP 429 with Retry-After, and a successful login clears the
bucket.
Security is enforced in layers. The browser can improve usability and explain state, but it cannot make an unauthorized request valid. Each API boundary repeats the checks needed for its operation, and database constraints provide the final integrity boundary.
- Passwords are stored as password hashes and are never returned by the APIs.
- Reset-token records contain hashes only; raw tokens, reset URLs, and credentials are not persisted or logged.
- PDO prepared statements and repository boundaries protect database operations from SQL injection.
- CSRF validation protects authenticated mutations.
- Session cookies use the project’s secure session settings, and protected requests revalidate the current staff record and role.
Auth_Revisioninvalidates stale sessions after password-sensitive changes without deleting arbitrary PHP session files.- The authenticated session probe is server-authoritative; sessionStorage is only a UI cache and never grants access.
- HTML authorization failures use a styled shared page, while API authorization failures remain JSON.
- Login rate-limit keys use normalized identifiers plus
REMOTE_ADDR; forwarded proxy headers are not trusted by default. - Orders use transactions and row locking for stock changes.
- Foreign keys preserve order history and protect referenced products and staff records.
composer.json requires PHP >=8.0 and intentionally declares no third-party packages. Its narrow classmap covers the one global OrderIdConflictException class in backend/application/orders/order-service.php; no unsafe PSR-4 mapping is used for the procedural function files. backend/bootstrap.php optionally loads Composer's generated vendor/autoload.php, then loads the legacy config/helpers in deterministic order. Future namespaced code may add a PSR-4 mapping only after the relevant files are migrated and reviewed.
The repository intentionally uses a transitional procedural PHP architecture. It is not a framework application and does not claim a complete PSR-4 namespace migration.
Quality rules for changes:
- Keep SQL out of views and keep authorization decisions on the server.
- Keep request validation separate from output encoding.
- Use explicit service/repository boundaries and parameterized SQL.
- Preserve existing API status codes and response shapes unless a security change explicitly documents a new status such as 429.
- Use
textContentand DOM APIs for dynamic browser rendering; do not introduce unsafe API-data interpolation intoinnerHTML. - Preserve numeric and currency values as LTR content inside the RTL interface.
- Keep shared shell markup in partials and preserve JavaScript IDs, data attributes, ARIA relationships, and script order.
- Do not put passwords, reset tokens, database credentials, or session secrets into logs, fixtures, screenshots, URLs, or browser storage.
- Test failure paths, not only successful requests: 401, 403, 409, 422, 429, 503, database failure, stale session, empty data, rollback, and retry.
Readable CSS and JavaScript under assets/ are the source of truth. Runtime
pages load generated files under dist/. The build is reproducible and is not
an excuse to edit generated output by hand:
npm ci
npm run buildThe build uses pinned clean-css and terser development tools. Terser keeps
top-level names stable because shared helpers and callbacks cross page-script
boundaries. Bootstrap 5.3.0 and the Poppins font files are self-hosted. See
docs/FRONTEND-BUILD.md for ownership and licensing.
For a non-trivial change, review the actual diff and verify:
- API payloads, response envelopes, authorization, and session behavior are unchanged unless the change explicitly requires otherwise.
- Database writes are transactional and recover cleanly on validation, conflict, deadlock, and unexpected database errors.
- Dynamic HTML output is contextually escaped or rendered with safe DOM APIs.
- Existing selectors, partial include paths, print rules, and responsive states remain compatible.
- Temporary databases, rows, users, sessions, browser profiles, screenshots, and scripts are removed after verification.
Run PHP lint with the project PHP executable:
C:\xampp\php\php.exe -l backend\views\dashboard.phpRun JavaScript syntax checks with Node.js:
node --check assets\dashboard\dashboard.jsFor broader changes, lint all affected PHP and JavaScript files and perform browser smoke testing against an isolated database. Do not use the live runtime database for destructive verification.
- Public password reset is intentionally disabled because no approved email or SMS delivery provider is configured. Enabling it requires a real provider, deployment secrets, HTTPS, request throttling, audit behavior, and session invalidation verification.
- Actual domain and HTTPS deployment are outside the local XAMPP workspace.
- Production credentials and the least-privilege database account must be supplied by the deployment owner.
- Composer remains a transitional bootstrap layer; the PHP codebase is still primarily procedural/global and is not a full PSR-4 application.
- The repository currently relies on lint, build, isolated-database, API, and Edge/CDP smoke verification rather than a dedicated unit/integration test framework.
STATUS.mdrecords a pre-existing local runtime-data provenance discrepancy. Reconcile the runtime database with an authoritative backup before treating the project as production-ready.
Mohammad Emad — GitHub
No license file is currently included in the repository. Confirm licensing before redistributing or deploying the project outside its intended environment.