# Queues, Vault, GraphQL, network restrictions

All of these are for a project in **a database of its own** (`p_<ref>`). New projects have one from the start.

## Queues (pgmq)

The same SQL functions as pgmq. The first `create_queue` installs the `pgmq` schema.

```sql
select pgmq.create('jobs');
select * from pgmq.send('jobs', '{"to": "a@example.com"}');
select * from pgmq.read('jobs', 30, 10);
select pgmq.archive('jobs', 1);
select pgmq.delete('jobs', 2);
select * from pgmq.pop('jobs');
select * from pgmq.metrics('jobs');
```

Tools: `list_queues`, `create_queue`, `send_queue_message`, `peek_queue` (look without taking), `purge_queue`,
`delete_queue`, `set_queues_api`. A queue's table `pgmq.q_<name>` belongs to the service role and has access rules on.
With `set_queues_api { exposed: true }`, the data API can call it.

```js
await supabase.schema('pgmq_public').rpc('send', { queue_name: 'jobs', message: { hello: 'world' } })
await supabase.schema('pgmq_public').rpc('read', { queue_name: 'jobs', sleep_seconds: 30, n: 5 })
```

For the publishable key or signed-in users to use it, grant privileges and rules in SQL.

```sql
grant insert, select, update on pgmq.q_jobs to authenticated;
create policy "own jobs" on pgmq.q_jobs for all to authenticated using (true) with check (true);
```

## Vault

Encrypts secrets and stores them in `vault.secrets` in the project's database. The platform holds the key and it is never
stored in the database, so dumps, backups and branches hold only ciphertext. A secret opens only when read with the secret key (the service role).

```sql
select vault.create_secret('sk_live_...', 'stripe_key', 'Stripe');
select decrypted_secret from vault.decrypted_secrets where name = 'stripe_key';
select vault.update_secret('<id>', 'sk_live_new');
```

Tools: `list_vault_secrets` (names only), `create_vault_secret`, `update_vault_secret`, `delete_vault_secret`.
The publishable key and signed-in users cannot see the `vault` schema, and over a direct connection (`<ref>_db`) `decrypted_secret` is null.

## Move to a dedicated database

Vault and large databases need a dedicated database (from the Pro plan). `get_database_move` shows where the project is and how
its move stands, and `move_to_dedicated_database` requests the move, as the console's "Move now" does (owners and admins).
It moves when its turn comes; writes pause during the move and reads carry on. REST: `GET` and `POST /projects/<ref>/database/move`,
CLI: `oneend db move`, `oneend db move now`.

## Dedicated disk

A paid project whose database has grown moves from the disk it shares with other projects to a disk and a Postgres of its own (as Supabase
gives each project an instance and a volume). Past 20 GB it moves on its own (an organization without a spend cap, or Enterprise), and
Enterprise may ask at any size. The disk starts at `max(1.2 x the database, 20 GB)`, grows by half once it is over 75% full (at most once in
4 hours), and is billed on its provisioned size at KRW 1,200 (75 cents) per GB a month. While it moves writes fail and reads work
(`expected_downtime_seconds`). Connection strings and passwords do not change. Once moved it is restored from its daily backups, not to a
point in time.

`get_dedicated_disk` shows the disk's size, what is used, the monthly cost, 30 days of history and the suggestion to make it smaller;
`request_dedicated_disk` requests the move and `shrink_dedicated_disk` a smaller disk (owners and admins). A disk is never made smaller on its
own: under 25% used for 7 days, a smaller one is suggested, and once confirmed a smaller disk is made, the data moves onto it and the old disk
is deleted. When the project is deleted, its disk is deleted 30 days later and costs nothing.
REST: `GET` and `POST /projects/<ref>/database/dedicated-disk`, `POST /projects/<ref>/database/dedicated-disk/shrink`,
CLI: `oneend db disk`, `oneend db disk request`, `oneend db disk shrink`.

## Dedicated server

From Pro, a project can rent a server of its own (the app and the database share it; the database gets 25% of its memory). Sizes and monthly
prices per location are `list_server_sizes`'s and are not written here. `get_server` shows the server, its standby and jobs;
`request_server` (tier, region) rents one; `resize_server` (tier, when=now|tonight) changes its size (3 to 5 minutes without answers unless
there is a standby); `set_standby` (standby, auto_failover) keeps a standby and fails over after 60 seconds without an answer;
`move_server` (region) moves it (free, once a month, the old server kept 7 days); `release_server` (confirm=ref) gives it back;
`set_restore_days` (7|28) sets the restore days. After a failed payment it is read-only for 7 days, then backed up and deleted.
REST: `GET`, `POST`, `PATCH`, `DELETE /projects/<ref>/server`, `PUT /projects/<ref>/server/standby`, `POST /projects/<ref>/server/move`,
`PUT /projects/<ref>/server/restore-days`. CLI: `oneend server`, `oneend server request|resize|standby|move|release|restore-days`.

## GraphQL

Turn it on with `enable_extension { ref, name: "pg_graphql" }` and `/graphql/v1` opens. Keys and access rules are the same as `/rest/v1`.

```
POST https://<ref>.<zone>/graphql/v1
apikey: <publishable key>
{"query": "{ todosCollection { edges { node { id title } } } }"}
```

## Network restrictions and TLS for direct connections

`get_network_restrictions`, `update_network_restrictions { ref, allowed_cidrs: ["203.0.113.0/24"], enforce_ssl: true }`.
By default every address is allowed and TLS is required. When the address the request came from is not on the list, it is not saved without `confirm: true`.
The console, the API and `run_sql` do not go through the connection pooler, so a restriction set by mistake can be undone from there.

## Read replicas

Not yet. The standby database (stage 3) is for failover and does not take customer connections.

Over HTTP: `GET /queues`, `POST /queues`, `POST /queues/<name>/messages`, `GET /queues/<name>/messages`,
`POST /queues/<name>/purge`, `DELETE /queues/<name>`, `PUT /queues/api`, `GET /vault`, `POST /vault`,
`PATCH /vault/<name>`, `DELETE /vault/<name>`, `GET /network-restrictions`, `PUT /network-restrictions`.

---

https://end.blackall.ai/docs/database-features?lang=en
