# S3 object storage with `aral`

    aral s3 regions                   # slug, name, flag, default_quota_gb, free_gb
    aral s3 create --name my-bucket --region hel1                  # region's default quota
    aral s3 create --name my-bucket --region hel1 --quota-gb 250
    aral s3 quota my-bucket --quota-gb 500                         # change it any time
    aral s3 list                      # id, name, zone, endpoint, quota_gb, object_count, size_bytes, usage_at
    aral s3 list --live               # count every bucket now, straight from the node
    aral s3 credentials my-bucket     # endpoint + access_key + secret_key
    aral s3 rotate my-bucket          # new key pair; the old one stops at once
    aral s3 delete my-bucket

`object_count` / `size_bytes` in the plain list are the storage node's last
scan and trail uploads by up to hours — `usage_at` says how old they are. A
fresh bucket showing 0 objects may simply not have been scanned yet; use
`--live` (or `GET /api/v1/s3/buckets/{id}/usage`) for the real answer.

New buckets always get a size quota: omit `--quota-gb` and the bucket gets
the region's `default_quota_gb` (`quota_gb` 0 in a listing = an older bucket
with no limit); writes beyond the quota are refused by the
storage node. `aral s3 quota` raises or lowers it in place (minimum 1 GB):
a quota below what the bucket already holds is refused (InvalidArgument), and
one larger than the region's free capacity is refused (ResourceExhausted) —
pick a smaller quota or another region.

Buckets speak the standard S3 API — point any S3 SDK/CLI at the `endpoint`
with the keys from `aral s3 credentials` (region can be any value; path-style
addressing). Keys are per bucket. Data is served directly from the storage
nodes, not proxied through the control plane.

Same thing over REST, with the session JWT a `nex_` token exchanges into:

    GET  /api/v1/s3/buckets
    GET  /api/v1/s3/buckets/{id}/credentials
    POST /api/v1/s3/buckets/{id}/rotate
    POST /api/v1/s3/buckets/{id}/quota   {"quota_gb": 500}
