# 데이터베이스

> 셀프 호스팅 Nodaro를 번들된 Supabase 스택이나 관리형 Supabase 프로젝트에서 실행하고, 마이그레이션을 적용하고, 데이터베이스 키와 비밀번호를 보호하세요.

Source: https://nodaro.ai/ko/docs/self-hosting/database

Nodaro는 **데이터베이스**를 Supabase에 둡니다. 데이터는 Postgres, 로그인은 GoTrue, 편집기가 읽고 쓰는 데이터 API는 PostgREST가 맡습니다. Compose 스택에 세 가지가 모두 번들되어 있으며 데이터베이스 마이그레이션도 대신 적용합니다. 대신 Nodaro가 관리형 Supabase 프로젝트를 가리키게 하고 마이그레이션을 직접 적용할 수도 있습니다.

## 번들된 스택
| 서비스 | 이미지 | 역할 |
| --- | --- | --- |
| `db` | Supabase Postgres | `db-data` 볼륨에 있는 데이터베이스 |
| `auth` | GoTrue | 이메일과 비밀번호로 가입 및 로그인 |
| `rest` | PostgREST | 데이터 API |

브라우저와 API는 앱 자체의 오리진인 `PUBLIC_URL/supabase`를 통해 로그인과 데이터 API에 접근합니다. Nodaro 컨테이너의 웹 서버가 `/supabase/auth/v1`은 GoTrue로, `/supabase/rest/v1`은 PostgREST로 전달하므로 추가 포트나 도메인이 필요하지 않습니다.

번들된 스택은 이메일을 보내지 않습니다. 계정은 가입하는 즉시 작동합니다.

### 번들된 스택의 마이그레이션
앱 컨테이너는 API가 시작되기 전에 `supabase/migrations/`의 모든 파일을 적용합니다. 이를 위해 `RUN_MIGRATIONS_ON_BOOT=true`와 `DATABASE_URL`이 필요하며, Compose 파일이 대신 설정합니다.

- **적용한 파일은 기억되어** 다음 부팅 때 건너뜁니다.
- **마이그레이션이 반쯤 끝난 데이터베이스로는 절대 실행되지 않습니다.** 마이그레이션이 실패하면 API가 시작을 거부하고, 컨테이너 로그에 해당 파일 이름이 나옵니다.
- **고친 뒤 다시 시작하세요.** 원인을 고친 뒤 `docker compose -f docker-compose.community.yml up`을 다시 실행하세요. 이미 적용된 파일은 건너뜁니다.

### 번들된 데이터베이스 보호
기본 키와 비밀번호는 공개되어 있습니다. 스택을 네트워크에 노출하기 전에 다음을 하세요.

1. `node tools/generate-selfhost-keys.mjs >> .env`로 **새 인증 키를 발급하세요**. 이 명령은 `SUPABASE_JWT_SECRET`, `SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY`를 출력합니다. 키가 시크릿으로 서명되므로 세 값 모두 같은 실행에서 나온 것이어야 합니다.
2. **`POSTGRES_PASSWORD`와 이에 맞는 `DATABASE_URL`을 설정하세요.** 예: `postgres://postgres:<new-password>@db:5432/postgres`.
3. `docker compose -f docker-compose.community.yml up -d`로 **적용하세요**.

데이터베이스는 **첫** 시작 때만 `supabase_auth_admin`, `authenticator` 같은 내부 역할의 비밀번호를 `POSTGRES_PASSWORD`에 맞춥니다. `db-data` 볼륨이 이미 있다면 볼륨을 삭제하거나(데이터도 삭제됩니다) `supabase_admin`으로 역할 비밀번호를 직접 바꾸세요. 그렇지 않으면 로그인이 `password authentication failed for user "supabase_auth_admin"`으로 실패합니다.

## 관리형 Supabase 프로젝트 사용
supabase.com의 프로젝트가 번들된 `db`, `auth`, `rest` 서비스를 대신합니다. 무료 등급으로 충분합니다. `.env`에 다음을 설정하세요.

```bash
SUPABASE_URL=https://YOUR-PROJECT.supabase.co
SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
FRONTEND_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
RUN_MIGRATIONS_ON_BOOT=false
NODARO_ENCRYPTION_KEY=<64-character hex>
```

- **`FRONTEND_SUPABASE_URL`** 변수는 브라우저가 쓰는 프로젝트 URL입니다. 공개된 이미지는 번들된 스택용으로 빌드되어 있어서, 다른 URL은 부팅할 때 이 변수로만 알 수 있습니다.
- **`RUN_MIGRATIONS_ON_BOOT=false`** 설정은 마이그레이션 실행기를 끕니다. 아래 설명대로 마이그레이션을 직접 적용하세요.
- **`NODARO_ENCRYPTION_KEY`** 변수는 반드시 설정해야 합니다. 예를 들어 `openssl rand -hex 32`로 만드세요. 스택은 마이그레이션 실행기가 켜져 있을 때만 키를 대신 생성합니다. 키가 없으면 공급자 키 붙여 넣기와 Nodaro Cloud 연결이 `EncryptionKeyMissingError`로 실패합니다.

설치가 이미 번들된 스택에서 실행된 적이 있다면 그 키를 재사용하세요. 키는 `app-data` 볼륨의 `/data/nodaro/encryption-key`에 있습니다. 새 키로는 이전 키로 암호화한 내용을 읽을 수 없습니다.

### 관리형 프로젝트에 마이그레이션 적용
`supabase/migrations/`의 모든 파일을 **파일 이름 순서대로** 적용하세요. `001_`, `002_`처럼 0으로 채운 접두사가 순서를 정합니다.

- **SQL 편집기로.** Supabase 대시보드에서 **SQL editor**를 열고 각 파일을 차례로 실행하세요.
- **Supabase CLI로.** 더 빠릅니다.

```bash
supabase link --project-ref YOUR-REF
supabase db push
```

마이그레이션은 이미 마이그레이션된 데이터베이스에서 다시 실행해도 됩니다. 다만 시드 데이터처럼 파일에 따로 적혀 있는 경우는 예외입니다. 새 데이터베이스에서 실행하는 것은 언제나 괜찮습니다.

업데이트할 때마다 새 이미지로 재시작하기 **전에** 새 파일을 파일 이름 순서대로 적용하세요. 마이그레이션이 빠져도 API가 멈추는 경우는 드물지만, 그 마이그레이션이 필요한 기능은 테이블이 생길 때까지 `500`으로 응답합니다.

## 내 오리진을 통해 관리형 프로젝트 제공
일부 네트워크는 모든 브라우저 요청을 호스트 이름으로 걸러 Supabase 도메인을 차단합니다. 이런 네트워크를 위해 Nodaro 컨테이너의 웹 서버가 관리형 프로젝트를 앱 자체의 오리진을 통해 전달할 수 있습니다. 세 변수를 함께 설정하세요.

```bash
SUPABASE_MANAGED_PROXY=true
FRONTEND_SUPABASE_URL=/supabase
SUPABASE_PROXY_UPSTREAM=https://YOUR-PROJECT.supabase.co
```

- `SUPABASE_PROXY_UPSTREAM`은 경로가 없는 오리진입니다.
- `SUPABASE_URL`은 프로젝트의 HTTPS URL로 그대로 두세요. API는 계속 프로젝트에 직접 연결합니다.
- 브라우저는 `/supabase`를 페이지의 오리진을 기준으로 해석합니다. 웹 서버는 WebSocket 업그레이드를 포함해 로그인, REST, 스토리지, 실시간 요청을 프로젝트로 전달합니다.
- 토큰과 API 키는 바뀌지 않고 그대로 전달됩니다. 프록시는 특권 자격 증명을 추가하지 않습니다.
- Supabase에 커스텀 도메인을 추가하지 않고도 여러 도메인이 같은 설정을 쓸 수 있습니다.

Compose 파일은 `SUPABASE_MANAGED_PROXY`와 `SUPABASE_PROXY_UPSTREAM`을 `.env`에서 전달하지 않으므로, `nodaro` 서비스의 `environment:` 아래에 추가하세요. 설정하지 않으면 프록시는 꺼져 있고 번들된 경로는 이전처럼 동작합니다.

## 데이터베이스를 사용할 수 없을 때
마이그레이션이나 복구 때문에 Postgres가 중단되면, API는 데이터베이스에 다시 연결할 수 있을 때까지 재시작을 반복합니다. 예상된 동작입니다. Postgres가 돌아오면 Nodaro 컨테이너를 재시작하세요.

```bash
docker compose -f docker-compose.community.yml restart nodaro
```

## 데이터베이스에 담기는 내용
워크플로와 프로젝트, 사용자 프로필, 실행과 그 진행 상황, 작업, 생성된 미디어의 레코드, API 토큰과 OAuth 앱, 암호화된 공급자 키와 소셜 로그인 토큰이 담깁니다. 모든 테이블에 행 수준 보안이 적용되므로 사용자는 자신의 행만 볼 수 있습니다. 미디어 파일 자체는 객체 스토리지에 있고, Redis에는 수명이 짧은 작업 상태만 들어 있습니다.

데이터베이스는 암호화 키와 함께 백업하세요. [백업과 복원](https://nodaro.ai/docs/self-hosting/backups)을 참고하세요. 데이터베이스 하나로 설치 두 개를 실행하려면 [확장](https://nodaro.ai/docs/self-hosting/scaling#two-installs-one-database)을 참고하세요.

## 자주 묻는 질문

### Nodaro는 어떤 데이터베이스를 쓰나요?

Supabase를 씁니다. Supabase는 GoTrue 로그인 서비스와 PostgREST 데이터 API를 갖춘 Postgres입니다. Compose 스택에 세 가지가 모두 번들되어 있으며, Nodaro가 supabase.com의 관리형 프로젝트를 가리키게 할 수도 있습니다.

### 데이터베이스 마이그레이션을 직접 실행해야 하나요?

번들된 스택에서는 그럴 필요가 없습니다. 부팅할 때마다 마이그레이션을 적용하고 이미 적용된 것은 건너뜁니다. 관리형 Supabase 프로젝트에서는 RUN_MIGRATIONS_ON_BOOT=false로 설정하고, SQL 편집기나 supabase db push로 supabase/migrations/를 파일 이름 순서대로 적용하세요.

### 관리형 Supabase 프로젝트에서 붙여 넣은 키가 EncryptionKeyMissingError로 실패하는 이유는 무엇인가요?

스택은 마이그레이션 실행기가 켜져 있을 때만 인스턴스 암호화 키를 생성합니다. RUN_MIGRATIONS_ON_BOOT=false라면 NODARO_ENCRYPTION_KEY를 직접 설정하거나, 이전 번들 설치가 app-data 볼륨에 보관한 키를 재사용하세요.

### 첫 시작 후에 POSTGRES_PASSWORD를 바꿀 수 있나요?

직접 바꿔야만 합니다. 데이터베이스는 첫 시작 때만 내부 역할 비밀번호를 POSTGRES_PASSWORD에 맞춥니다. db-data 볼륨을 삭제하거나(데이터도 삭제됩니다) supabase_admin으로 역할 비밀번호를 바꾸세요.

### 마이그레이션을 롤백할 수 있나요?

아니요. 마이그레이션은 앞으로만 진행됩니다. 이전 버전으로 돌아가려면 업데이트 전에 만든 백업을 복원하세요.
