# Multi-tenancy and feature modules

## Tenancy model

```mermaid
erDiagram
  ORGANIZATIONS ||--o{ USERS : has
  ORGANIZATIONS ||--o{ GRANTS : owns
  ORGANIZATIONS ||--o{ ORGANISATION_MODULES : toggles

  ORGANIZATIONS {
    uuid uuid PK
    string name
    json settings
  }
  USERS {
    bigint id PK
    bigint organisation_id FK
    string email
  }
  ORGANISATION_MODULES {
    bigint organisation_id FK
    string module_key
    bool enabled
  }
```

Every authenticated **staff** API request resolves `organisation_id` from `users` and scopes queries accordingly (plus RBAC where enabled).

## Module keys (code)

Source: `config/modules.php`.

```mermaid
flowchart LR
  subgraph Core["Core grant stack"]
    G[grants]
    B[budgets]
    P[programmes]
    F[finance]
  end

  subgraph Spend["Spend chain"]
    PR[procurement]
  end

  subgraph People["People and workplace"]
    HR[hr]
    TR[travel]
    AC[attendance_core]
    AQ[attendance_qr]
    AF[attendance_face]
    AI[attendance_ip]
    AG[attendance_geo]
    WP[workplace]
    HI[hiring]
  end

  subgraph Cross["Cross-cutting"]
    AP[approvals]
    NO[notifications]
    MI[milestones]
    PA[partners]
    GS[global_search]
    IB[import_bulk]
  end

  G --> B
  G --> P
  B --> F
  G --> F
  F --> PR
  HR --> HI
  G --> HI
  AP --> HI
  AC --> AQ
  AC --> AF
  AC --> AI
  AC --> AG
```

## Module dependency graph (requires)

As defined in `config/modules.php` `requires` array:

```mermaid
flowchart TB
  grants[grants]

  budgets[budgets]
  programmes[programmes]
  finance[finance]
  procurement[procurement]

  hiring[hiring]
  hr[hr]
  approvals[approvals]

  attendance_core[attendance_core]
  attendance_qr[attendance_qr]

  grants --> budgets
  grants --> programmes
  grants --> finance
  budgets --> finance
  finance --> procurement

  hr --> hiring
  grants --> hiring
  approvals --> hiring

  attendance_core --> attendance_qr
```

## Enabling a module (conceptual)

```mermaid
stateDiagram-v2
  [*] --> DefaultFromConfig: no row in organisation_modules
  DefaultFromConfig --> Effective: use default_enabled
  RowExists --> Effective: use stored enabled flag
  Effective --> Gate: API middleware module:key
  Gate --> Allow: enabled and deps satisfied
  Gate --> Deny: 403 or redirect
  Allow --> [*]
  Deny --> [*]
```
