# 대기열, Vault, GraphQL, 접속 제한

모두 **전용 데이터베이스**(`p_<ref>`)에 있는 프로젝트에서 써요. 새 프로젝트는 처음부터 전용 데이터베이스예요.

## 대기열 (pgmq)

pgmq와 같은 SQL 함수예요. `create_queue`가 처음이면 `pgmq` 스키마를 설치해요.

```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');
```

도구: `list_queues`, `create_queue`, `send_queue_message`, `peek_queue`(가져가지 않고 보기), `purge_queue`,
`delete_queue`, `set_queues_api`. 대기열 표 `pgmq.q_<이름>`은 서비스 역할의 것이고 접근 규칙이 켜져 있어요.
`set_queues_api { exposed: true }`면 데이터 API에서 부를 수 있어요.

```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 })
```

공개 키·로그인 사용자가 쓰려면 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

비밀을 암호화해 프로젝트 데이터베이스의 `vault.secrets`에 저장해요. 키는 플랫폼이 갖고 있고 데이터베이스에
저장되지 않아서 덤프·백업·브랜치에는 암호문만 남아요. 비밀 키(서비스 역할)로 읽을 때만 풀려요.

```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');
```

도구: `list_vault_secrets`(이름만), `create_vault_secret`, `update_vault_secret`, `delete_vault_secret`.
공개 키와 로그인 사용자는 `vault` 스키마를 볼 수 없고, 직접 연결(`<ref>_db`)에서는 `decrypted_secret`이 null이에요.

## 전용 데이터베이스로 옮기기

Vault와 큰 데이터베이스는 전용 데이터베이스에서만 쓸 수 있어요(Pro 요금제부터). `get_database_move`가 지금 어디에 있는지와
옮기기 상태를 보여 주고, `move_to_dedicated_database`가 콘솔의 "지금 옮기기"처럼 옮기기를 요청해요(소유자·관리자).
차례가 오면 옮기고, 옮기는 동안 쓰기는 멈추고 읽기는 돼요. REST: `GET`·`POST /projects/<ref>/database/move`,
CLI: `oneend db move`, `oneend db move now`.

## 전용 디스크

데이터베이스가 커진 유료 프로젝트는 함께 쓰는 디스크에서 이 프로젝트 전용 디스크와 Postgres로 옮겨요(Supabase의
프로젝트별 서버와 볼륨처럼). 데이터베이스가 20GB를 넘으면 자동으로 옮기고(지출 상한이 꺼진 조직 또는 Enterprise), Enterprise는
크기와 관계없이 요청할 수 있어요. 디스크는 `max(1.2 × 데이터베이스, 20GB)`로 시작해 75% 넘게 차면 1.5배로 늘어나고(4시간에 한 번까지),
만든 크기만큼 GB당 월 ₩1,200(75¢)로 청구돼요. 옮기는 동안 쓰기가 실패하고 읽기는 돼요(`expected_downtime_seconds`). 연결 주소와
비밀번호는 그대로예요. 옮긴 뒤에는 특정 시각으로 복원할 수 없고, 매일 받는 백업으로 복원해요.

`get_dedicated_disk`가 디스크 크기, 쓴 공간, 한 달 비용, 30일 기록, 줄이기 제안을 보여 주고, `request_dedicated_disk`가 옮기기를,
`shrink_dedicated_disk`가 줄이기를 요청해요(소유자·관리자). 디스크는 저절로 줄지 않아요: 7일 동안 25% 아래로 쓰면 줄이기를 제안하고,
확인하면 더 작은 디스크를 만들어 옮긴 뒤 원래 디스크를 지워요. 프로젝트를 지우면 30일 뒤 디스크도 지워져 비용이 0이 돼요.
REST: `GET`·`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`.

## 전용 서버

Pro부터 프로젝트 하나만 쓰는 서버를 빌릴 수 있어요(앱과 데이터베이스가 함께 쓰고, 데이터베이스가 메모리의 25%). 크기와 위치별 월 금액은
`list_server_sizes`가 보여 주고, 여기에는 적지 않아요. `get_server`가 지금 서버·대기 서버·작업을, `request_server`(tier, region)가 빌리기를,
`resize_server`(tier, when=now|tonight)가 크기 바꾸기를(대기 서버가 없으면 3~5분 응답 없음), `set_standby`(standby, auto_failover)가 대기
서버와 자동 전환(60초 응답 없음)을, `move_server`(region)가 위치 옮기기를(무료, 한 달에 한 번, 옛 서버 7일 보관), `release_server`(confirm=ref)가
반납을, `set_restore_days`(7|28)가 되돌리기 기간을 정해요. 결제가 실패하면 7일 동안 읽기 전용이 되고, 그 뒤 마지막 백업을 받고 서버를 지워요.
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

`enable_extension { ref, name: "pg_graphql" }`로 켜면 `/graphql/v1`이 열려요. 키와 접근 규칙은 `/rest/v1`과 같아요.

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

## 직접 연결의 접속 제한과 TLS

`get_network_restrictions`, `update_network_restrictions { ref, allowed_cidrs: ["203.0.113.0/24"], enforce_ssl: true }`.
기본값은 모든 주소 허용, TLS 필수예요. 요청을 보낸 주소가 목록에 없으면 `confirm: true` 없이는 저장되지 않아요.
콘솔·API·`run_sql`은 연결 풀러를 거치지 않아서 제한을 잘못 걸어도 여기서 되돌릴 수 있어요.

## 읽기 전용 복제본

아직 없어요. 운영 대기 서버는 장애 대비용이라 고객 연결을 받지 않아요.

HTTP로는 `GET /queues`, `POST /queues`, `POST /queues/<이름>/messages`, `GET /queues/<이름>/messages`,
`POST /queues/<이름>/purge`, `DELETE /queues/<이름>`, `PUT /queues/api`, `GET /vault`, `POST /vault`,
`PATCH /vault/<이름>`, `DELETE /vault/<이름>`, `GET /network-restrictions`, `PUT /network-restrictions`이에요.

---

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