# Architecture

Stack: **Laravel 13 + Blade**, MySQL, Bootstrap 5 "Valex" theme. Single codebase,
single database. Architecture mirrors the live **VMS** system.

## 1. Multi-tenancy (single DB, `company_id` scoping)

Every tenant table carries a `company_id`. There is **no** separate database per
company — rows are filtered by the active company.

- `companies` — the tenants. `company_settings` — per-company key-value options
  (includes module on/off flags).
- **`App\Models\Concerns\BelongsToCompany`** trait — add to any tenant model. It:
  - adds a global scope filtering `company_id = company_id()`, and
  - auto-fills `company_id` on create.
  - `Model::withoutCompanyScope()` bypasses (for the SaaS admin / cross-tenant ops).

```php
class Customer extends Model {
    use BelongsToCompany;   // now every query is tenant-scoped automatically
}
```

## 2. User types & access

`users.user_type`:
- `admin` — SaaS owner (superadmin), **not** tied to a company. Sees `/admin`.
- `user` — company owner / main admin. Full access within their company.
- `staff` — employee. Access governed by `role_id` → role permissions.

Middleware aliases (registered in `bootstrap/app.php`):
| Alias | Class | Purpose |
|-------|-------|---------|
| `company` | SetActiveCompany | resolve tenant, suspend gate, timezone, share `$activeCompany` |
| `module` | EnsureModuleEnabled | gate a route group by a company's module flag |
| `superadmin` | EnsureSuperAdmin | restrict to `user_type = admin` |
| `permission` | EnsurePermission | gate a route by a permission key |
| `SetUserLocale` | (web group) | set app locale from session/company option |

## 3. Module system

- Registry: **`config/modules.php`** (`key => {title, icon, default, permission, route}`).
- Enabled state per company = a `company_settings` row (`name = module key`,
  `value = yes|no`). Read with `company_module_enabled($key, $companyId)`.
- Route gating: `Route::middleware('module:asset_module')->group(...)`.
- The sidebar (`resources/views/partials/sidebar.blade.php`) is driven by this registry,
  filtered by `company_module_enabled()` + `user_can()`.

## 4. Self-update engine (no migrations going forward)

See [DEV_NOTES.md](DEV_NOTES.md#adding-a-schema-change). Schema changes ship as numbered
functions in `App\Services\UpdateHelper`, declared in `app/Helpers/update.json`. Version
lives in the global `settings` table. Apply via `php artisan app:update` or
`/admin/system/update`.

> The original Laravel migrations (`companies`, `users`, `roles`, `customers`,
> `company_settings`) form the **base install**. Everything after v1.0.0 goes through
> the updater — do not add new migration files.

## 5. Helpers (auto-loaded via composer `files`)

| File | Provides |
|------|----------|
| `app/Helpers/tenancy.php` | `company_id`, `current_company`, `get/set_company_option`, `company_module_enabled`, `user_can`, `has_permission`, `permission_catalog`, `all_permission_keys` |
| `app/Helpers/options.php` | `get_option`, `update_option`, `current_version` (global settings) |
| `app/Helpers/lang.php` | `_lang`, `active_language`, `available_languages` |

## 6. Views

- Master layout: `resources/views/layouts/app.blade.php` → partials `head`, `header`,
  `sidebar`, `footer`, `scripts`, `switcher`, `alerts`.
- Theme assets: `public/theme/assets/*` (paths rewritten from `../assets/` → `/theme/assets/`).
- SuperAdmin views: `resources/views/admin/*`. Auth: `resources/views/auth/login.blade.php`.

## 7. Directory map (key paths)

```
app/
  Models/                 Company, CompanySetting, Role, Customer, User
    Concerns/BelongsToCompany.php
  Http/
    Controllers/Auth/LoginController.php
    Controllers/Admin/   AdminDashboardController, CompanyController, SystemUpdateController
    Middleware/          SetActiveCompany, EnsureModuleEnabled, EnsureSuperAdmin,
                         EnsurePermission, SetUserLocale
  Services/UpdateHelper.php
  Console/Commands/AppUpdate.php
  Helpers/               tenancy.php, options.php, lang.php, update.json
config/                  modules.php, roles.php, permissions.php
resources/
  views/                 layouts/, partials/, admin/, auth/, dashboard/
  language/              en.php, bn.php
routes/                  web.php, admin.php
```
