# Buckets and Management membership

A Document bucket contains conversion jobs and document-operation records.
Select one bucket for an operation and retain its `bucket_id` when polling,
reading, cancelling or deleting jobs. Jobs are shared within the authorized
bucket; a job identifier alone grants no access.

## Authentication and capabilities

All routes use `POST` with an admitted Bearer access token and JSON body.
Membership is evaluated through the bucket's active pinned Management group,
active membership and active association. Other groups confer no authority.
Use the returned context's `capabilities` to enable actions rather than inferring
access from a token or a service role.

| Bucket role | Default bucket actions |
| --- | --- |
| `owner` | Read, conversion/document/job operations, rename, membership changes, privileged role assignments, and bucket deletion. |
| `admin` | Read, conversion/document/job operations, rename, and manage ordinary member memberships. |
| `member` | Read and conversion/document/job operations, including cancelling or deleting jobs within the bucket. |

Every role can leave. The final active owner cannot leave, be removed, disabled
or demoted. Organization workspaces additionally intersect these capabilities
with live organization Management grants. Context is a current decision;
membership and capability changes affect subsequent requests.

## Routes and fields

`bucket_id`, `principal_id` and `member_id` are non-nil dashed UUIDs. `name`
is trimmed text of 1–191 bytes. Caller-supplied ownership overrides are rejected
on creation. Optional [organization transport](https://m7.org/docs/api/api.document.m7.org/workspaces.md) is separate
from bucket fields.

| Route | Required fields | Result and conditions |
| --- | --- | --- |
| `/v1/bucket/list` | None | `data.items` contains accessible bucket contexts, with `principal_capabilities` (`bucket.list`, `bucket.create`). No pagination fields apply. |
| `/v1/bucket/create` | `name` | Creates a bucket and returns context. Requires an admitted user or authorized organization with `bucket.create`. |
| `/v1/bucket/get` | `bucket_id` | Returns context for an accessible bucket. |
| `/v1/bucket/save` | `bucket_id`, `name` | Requires `bucket.save`; returns the saved bucket record. |
| `/v1/bucket/delete` | `bucket_id`, `confirmed: true` | Requires `bucket.delete`; returns `bucket_id`, `deleted: true`, and `children_deleted` counts. |
| `/v1/bucket/member/list` | `bucket_id` | Requires `member.list`; returns `items` plus bucket `context`. |
| `/v1/bucket/member/save` | `bucket_id`, `principal_id` | Optional `member_id`, `role`, `status`; requires `member.save`. |
| `/v1/bucket/member/remove` | `bucket_id`, `principal_id`, `member_id` | Requires `member.remove`; removes the exact membership and returns its prior summary. |
| `/v1/bucket/member/leave` | `bucket_id` | Requires `member.leave`; removes only the caller's membership and returns its prior summary. |

For `member/save`, omit `member_id` to add a new active membership (default
role `member`); supply the existing member ID to edit. An existing membership
without its ID is a conflict. Roles are `owner`, `admin`, and `member`; editable
statuses are `active` and `disabled`. New or reactivated members must reference
an existing active Document receiving principal. Role changes, privileged
membership creation, and changes/removal affecting owner/admin memberships
require `member.assign_roles`. Admins can manage only ordinary members and
cannot promote them. Removal deletes the membership; add it again to establish
a new membership. Departure rejects target/member/role/status overrides.

## Create and select a bucket

```bash
curl -sS https://api.document.service.m7.org/v1/bucket/create \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Example documents"}'
```

`data` contains the bucket context:

```json
{
  "bucket": {"id":"BUCKET_UUID","name":"Example documents","created_by":"ACTOR_UUID"},
  "member": {"id":"MEMBER_UUID","principal":"PRINCIPAL_UUID","role":"owner","status":"active"},
  "capabilities": ["bucket.get", "convert.async", "job.result", "bucket.delete"],
  "principal_id": "PRINCIPAL_UUID",
  "actor_principal_id": "ACTOR_UUID",
  "workspace": null
}
```

The example abbreviates bucket fields and action lists. Bucket records also
have `created` and `modified` timestamps. Member summaries contain `id`,
`principal`, `role`, `status`, `created`, and `modified`. For an organization,
`workspace` is `{ "org_id": "ORG_UUID", "org_name": "Example organization" }`,
`principal_id` is its receiving principal, and `actor_principal_id` remains the
authenticated caller.

Use the returned `bucket.id` in a conversion request:

```json
{"bucket_id":"BUCKET_UUID","source":"# Example","input_format":"markdown","output_format":"html"}
```

## Deletion and errors

Bucket deletion removes all its jobs and retained inputs, source metadata,
results and pickup payloads as one cascade, including pending and running jobs.
Processing and deletion share the bucket lock; partial child deletion is not a
successful result. Explicit `confirmed: true` is required and cannot be supplied
as a string. Fetch current context before offering deletion.

Invalid input returns `400`, unavailable admission `401`, denied membership or
capability `403`, missing bucket `404`, and concurrent/busy membership changes
`409`. On `409`, reload membership/context before retrying. A missing or invalid
capability catalogue can return `503`; do not substitute broad client-side
defaults. See [Authorization](https://m7.org/docs/api/api.document.m7.org/authorization.md).
