# Users, projects and tokens

## Organisations

An organisation is a tenant. It owns its projects, quality profiles, quality gates, webhooks and
GitLab/GitHub connections. The first start creates the organisation `default`. The community edition
allows up to **3** organisations and has no limit on users, projects or lines of code. Most companies
need only `default`.

An instance admin creates more organisations through the API (`POST /api/v0/organizations`).

## Users and roles

| Role | Can |
|---|---|
| **Instance admin** | everything, including users and organisations |
| **Org admin** | manage the organisation: projects, project tokens, quality profiles, gates, webhooks, GitLab/GitHub connections and members |
| **Org member** | read every project of the organisation and triage its issues: change a status, override a severity |

Instance admins manage users in **Settings → Users**: create users, reset passwords, deactivate
users, and make or remove instance admins. A new user and a user whose password was reset must
choose a new password at their next sign-in. Passwords have at least 12 characters, and sign-in is
rate-limited.

Organisation membership and roles are managed through the API:

```sh
# role: "admin" or "member"
curl -fsS -X PUT -H "Authorization: Bearer $QUALOR_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"role":"member"}' "$QUALOR_URL/api/v0/organizations/<org id>/members/<user id>"
```

SSO (SAML/OIDC), SCIM and fine-grained roles belong to the enterprise edition.

## Projects

A project is one analysed codebase, usually one repository. A monorepo can hold several projects,
each with its own key and its own `sources.include`.

- **Create one** in **Projects → New project**, with a key and a name. Or let the first upload create
  it: this happens when the scan uses a personal token of an org admin with the **Upload analyses**
  scope.
- **The key** is what the scanner reports. It defaults to the CI project path (`CI_PROJECT_PATH`,
  `GITHUB_REPOSITORY`). You can set it with `project.key` in `qualor.yml`, `QUALOR_PROJECT_KEY` or
  `--project-key`. Keys are unique on the instance. They may contain letters, digits, `.`, `_`, `-`,
  `/` and `:`.
- **The main branch** is `main` by default. Every other branch and every merge request is compared
  with it.
- **Deleting** a project needs its key as confirmation. The API call is
  `DELETE /api/v0/projects/<id>?confirm=<key>`.

Some project settings have no screen in the UI yet. Set them with `PATCH /api/v0/projects/<id>` (the
project id is in the project's URL), using a personal token with the **Admin** scope:

```sh
curl -fsS -X PATCH -H "Authorization: Bearer $QUALOR_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"mainBranchName":"master","newCodeDefinition":{"type":"days","value":30}}' \
  "$QUALOR_URL/api/v0/projects/<project id>"
```

| Field | Meaning |
|---|---|
| `name` | display name |
| `mainBranchName` | the default branch |
| `newCodeDefinition` | how new code is defined on the main branch; see [Quality gates](https://qualor.dev/docs/quality-gates.md#new-code) |
| `qualityGateId` | a gate for this project, or `null` for the organisation's default gate |
| `scmConnectionId`, `scmProjectRef` | the GitLab/GitHub mapping. **Settings → GitLab** also sets it |

To assign a quality profile to one project, use `PUT /api/v0/projects/<id>/quality-profiles/<language>`
with the body `{"profileId": "..."}`. Send `null` to return that language to the organisation's
default profile.

## Tokens

Every token is shown **once**, when it is created. The server stores only a hash. Tokens look like
`qlr_pat_…` (personal) or `qlr_prj_…` (project). Qualor's own Gitleaks configuration knows the `qlr_`
prefix, so a leaked token is reported as a secret.

### Personal tokens

**Settings → Access tokens → New token.** You choose the scopes and, optionally, an expiry. Only a
signed-in browser session can create a personal token, so a token can never create another one.

| Scope (UI) | API name | Allows |
|---|---|---|
| Read | `read` | read the organisations you belong to |
| Write (triage issues) | `write` | also change issues, profiles and gates, as far as your role allows |
| Admin | `admin` | also everything your role allows administratively |
| Upload analyses | `analysis:write` | upload analyses (what CI needs) |

A token has the rights that both its scopes and its user's role allow.

### Project analysis tokens

A project token can **only upload analyses to its one project**. It is the best token for CI. Create
one with a personal token that has the Admin scope:

```sh
curl -fsS -X POST -H "Authorization: Bearer $QUALOR_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"gitlab-ci"}' "$QUALOR_URL/api/v0/projects/<project id>/tokens"
# → {"token":"qlr_prj_…", ...}   store it as the masked CI variable QUALOR_TOKEN
```

List and revoke project tokens with `GET` and `DELETE /api/v0/projects/<id>/tokens[/<token id>]`.

### Which token where

| Use | Token |
|---|---|
| CI of one repository | a project analysis token |
| One CI token for many repositories, with projects created on first scan | a personal token (**Upload analyses**) of a dedicated bot user who is org admin |
| Scripts and automation (onboarding, reports) | a personal token with **Read**, **Write** or **Admin**, as needed |
| `qualor import sonarqube` | a personal token with **Admin**, of an org admin |

Keep `QUALOR_TOKEN` in the CI's secret store: a masked GitLab variable, or a GitHub Actions secret.
Never put it in `qualor.yml`: the CLI refuses a config file that has a `token` key.