# Access Policies

The access control system assigns permissions to resources such as modules,
forms and database tables. Resources are listed in the `resources` table and
typed via entries in `resource_types`.

Each row in `resources` references a `resource_type_id` which categorises the
record. Permissions are stored in the `permissions` table with the same
`resource_type_id` so queries can be grouped by resource type. The
Permissions Manager shows tabs for modules, forms and tables based on this
field. Existing records were updated by the
`20260133_add_resource_type_to_permissions.sql` migration which sets this value
automatically.

The Super Admin account (`user_id` 1) bypasses module permission checks and may access every module regardless of assigned roles.

Every table created in `TAFDB.pgsql` **must also** have a matching row in the
`resources` table using the `table` resource type. A helper migration
(`20251218_seed_table_resources.sql`) inserts any missing table names. Run this
migration after adding tables to the base schema.

`cli/pgsql_schema_sync.php` automatically loads `sql/defaults.sql` unless
`--no-seed` is used. Adding the table inserts there ensures new installations
include the same resource entries without needing the migration.

Any future table or modal definitions must also be inserted into the
`resources` table. Update `sql/defaults.sql` and create a matching migration
whenever new tables or modals are added so permission seeding stays up to date.

## Permissions Manager UI

Open the **Permissions** card on `FrontEnd/Dashboard.php` to launch the
Permissions Manager module. The interface lets administrators create or edit
access policies:

- **Subject selection** – choose the user or group that the policy applies to.
- **Scoping fields** – optionally restrict the rule by tenant, branch or other
  context.
- **Resource tabs** – switch between modules, forms and tables to assign
  permissions per resource type.
- **Action/effect toggles** – set the allowed actions and whether each rule
  grants or denies access. A **delegate** flag indicates the subject may further
  delegate that permission.
- The table of permissions refreshes automatically when you change the subject
  or tenant scope so existing rules are immediately reflected.

Currently only module permissions are enforced. Other resource types are
listed but marked TODO until backend support is completed.

## Helper API Endpoints

Two utility endpoints expose reference data used by the Permissions Manager.

`GET /api/access_scopes` returns the available scoping values as JSON:

```json
{
  "tenants": [...],
  "branches": [...],
  "departments": [...],
  "districts": [...],
  "groups": [...]
}
```

`GET /api/access_resources` groups all entries in the `resources` table by
their resource type code. The response object keys match the codes defined in
`resource_types` and each contains the list of corresponding resources.
For example the API responds with keys using the raw codes:

```json
{
  "module": [...],
  "form": [...],
  "table": [...],
  "table_column": [...]
}
```
User interface labels may display plural names (e.g. *Modules*, *Forms*), but the
JSON keys always match these singular codes.

`GET /api/subjects?type={user|group|role|tenant}` returns a simple list of available
subjects for building policies. The response is an array of objects with `id`
and `name` keys:

```json
[
  {"id": 1, "name": "Alice"},
  {"id": 2, "name": "Bob"}
]
```

## Bulk Permissions API

`POST /api/permissions` now supports creating multiple permission records in one request. Send a JSON payload with the following structure:

```json
{
  "subject_type": "tenant",
  "subject_ids": [1],
  "scopes": {
    "tenant": [1],
    "branch": [1]
  },
  "permissions": [
    {
      "resource_ids": [10, 11],
      "action": "view",
      "effect": "allow"
    }
  ]
}
```

A record is inserted for every combination of `subject_ids` and `resource_ids`. Existing single-record requests (without the `permissions` array) continue to work unchanged.
