Multi-Tenancy Design
Relevant source files
The following files were used as context for generating this wiki page:
The IT Management System is designed as a multi-tenant platform where data isolation is maintained across multiple companies within a single application instance. The architecture follows a shared-database approach where almost all entities are scoped by a unique company identifier, ensuring that users from one tenant cannot access or modify the data of another. This isolation extends from the database schema layer up through the session-based authentication and physical file storage.
Sources: AGENT_NOTES.md:10-12, wiki/Home.md:7-9, modules/companies/AGENT_NOTES.md:4-6
Core Tenant Architecture
The system's multi-tenancy is anchored by the companies module, which manages the top-level "Tenant" entities. Every other record in the system—ranging from employees and equipment to floor plans and tickets—is linked to a specific company record.
Tenant Resolution and Session Management
Tenants are resolved at login and the active company_id is stored in the PHP session. This session variable acts as the primary key for filtering all subsequent queries and operations.
The diagram above illustrates the request flow from login to data retrieval, highlighting the role of the session in enforcing tenant isolation.
Sources: wiki/Home.md:92-96, modules/companies/AGENT_NOTES.md:20-22, AGENT_NOTES.md:10-12
The Companies Module
As the root of all relationships, the companies module is the only part of the system where data is not filtered by a company_id in its primary list, as it defines the tenants themselves.
| Field | Purpose | Constraints |
|---|---|---|
company | Full name of the tenant | Must be unique |
incode | Short code for the tenant | Must be unique, 6 characters max |
active | Tenant status | Inactivation blocks system access |
Sources: modules/companies/AGENT_NOTES.md:4-16, modules/companies/AGENT_NOTES.md:36-38
Data Isolation Mechanisms
1. Database Level Isolation
Strict tenant isolation is enforced through two primary methods:
- Scoped Queries: All
SELECT,UPDATE, andDELETEstatements must include aWHERE company_id = ?clause using prepared statements. - Foreign Key Constraints: Most tables utilize foreign keys pointing to the
companiestable. Deleting a company record is highly destructive and will cascade delete all associated tenant data.
// Standard pattern for tenant-safe data retrieval
$stmt = $conn->prepare("SELECT * FROM employees WHERE company_id = ? AND id = ?");
$stmt->bind_param("ii", $companyId, $id);
$stmt->execute();
Sources: AGENT_NOTES.md:10-12, modules/companies/AGENT_NOTES.md:32-34, modules/employees/AGENT_NOTES.md:46-50
2. API Security and Tenant Context
The API layer (scripts/api.php) explicitly prohibits passing a company_id in request payloads for security reasons. Instead, the server-side session context is used to resolve the tenant.
- Authentication: Requires an authenticated PHP session cookie and a valid CSRF token.
- Implicit Scoping: The API resolves the
company_idfrom the session, preventing "Tenant ID Injection" attacks where a user might try to access another company's data by modifying a POST parameter.
Sources: scripts/api.php:127-133, scripts/api.php:164-168
Physical Resource Isolation
Physical files, such as floor plans and document uploads, are stored in a company-specific directory structure to ensure physical as well as logical separation.
Directory Structure
The system uses the following path convention for file storage:
ROOT_PATH . 'files/' . $company_id
| Module | Storage Directory | Usage |
|---|---|---|
| Explorer | files/{company_id}/ | Private, department, and common files |
| Floor Plans | floor_plans/{company_id}/ | Images, PDFs, and CAD files |
Explorer Module Scoping
The Explorer module provides an additional layer of isolation within a single tenant:
- Common: Accessible to all company users.
- Department: Restricted to users within a specific department.
- Private: Restricted to the individual owner.
Sources: modules/explorer/AGENT_NOTES.md:12-20, modules/floor_plans/AGENT_NOTES.md:16-18, modules/explorer/AGENT_NOTES.md:40-42
Multi-Tenancy Rules for Developers
To maintain system integrity, developers must adhere to specific multi-tenant business rules:
- Mandatory Filtering: Every query must filter by
company_idfrom the session. - No Cross-Tenant Transfers: Records (e.g., workstations or employees) cannot be moved between different companies.
- Unique Constraints: Many unique keys (like department names or employee codes) are scoped per company, not globally.
- Audit Logs: Audit logs are generated per tenant to track changes specifically within that company's context.
Sources: AGENT_NOTES.md:14-16, modules/companies/AGENT_NOTES.md:40-42, modules/departments/AGENT_NOTES.md:16-18
Conclusion
The multi-tenancy design of the IT Management System provides robust isolation by combining session-based identity resolution with strict SQL prepared statement filtering and physical directory partitioning. By centralizing tenant management in the companies module and enforcing implicit scoping in the API, the system ensures that data privacy is maintained across all functional modules.