runlot
참조API

데이터베이스

database 묶음의 오퍼레이션 13 개입니다.

메서드경로하는 일
GET/v1/orgs/{orgSlug}/projects/{projectName}/database데이터베이스 자격 여부
POST/v1/orgs/{orgSlug}/projects/{projectName}/database데이터베이스를 만든다 (runlot pg create)
GET/v1/orgs/{orgSlug}/projects/{projectName}/database/connectpsql·드라이버가 붙는 데 필요한 전부
GET/v1/orgs/{orgSlug}/projects/{projectName}/database/endpoint자격 없는 접속 끝점 (runlot port-forward)
GET/v1/orgs/{orgSlug}/projects/{projectName}/database/tokens살아 있는 단기 자격 목록
POST/v1/orgs/{orgSlug}/projects/{projectName}/database/tokens단기 기계 자격 발급 (runlot pg token)
DELETE/v1/orgs/{orgSlug}/projects/{projectName}/database/tokens/{tokenUser}단기 자격 폐기
POST/v1/orgs/{orgSlug}/projects/{projectName}/database/export진단 이미지를 하나 만든다 (runlot pg export)
GET/v1/orgs/{orgSlug}/projects/{projectName}/database/generations백업 세대 목록 (runlot pg generations)
POST/v1/orgs/{orgSlug}/projects/{projectName}/database/restore세대로 되돌린다 (runlot pg restore)
POST/v1/orgs/{orgSlug}/projects/{projectName}/database/delete데이터베이스를 없앤다 (runlot pg delete)
GET/v1/orgs/{orgSlug}/projects/{projectName}/database/operations/{opId}연산 하나의 진행
POST/v1/orgs/{orgSlug}/projects/{projectName}/database/operations/{opId}/abort진행 중인 연산을 중단한다 (runlot pg abort)

GET /v1/orgs/{orgSlug}/projects/{projectName}/database

답은 {db: bool} 하나다. 크기·세대 같은 실물 상태는 노드가 아는 사실이라 여기 없다.

자격(비밀번호)은 이 답에 없다. 이 라우트는 viewer 도 받는다 — 접속 정보는 /database/connect 로 갈렸다.

operationId getDatabase

응답본문
200자격 여부object
403
404

POST /v1/orgs/{orgSlug}/projects/{projectName}/database

행이 곧 자격이다. 자격이 켜지면 node-agent 가 다음 수렴에서 그 프로젝트의 workerd 를 env.db 가 붙은 설정으로 교체한다 — 배포도 epoch 변경도 필요 없다.

멱등이고, 비밀번호를 굴리지 않는다. 두 번째 호출은 행에 있는 값을 다시 읽어 같은 접속 정보를 답한다. 굴리면 첫 응답을 받아 적어 둔 접속 문자열이 조용히 죽고, 죽었다는 신호는 다음 로그인 실패뿐이다.

operationId createDatabase

응답본문
200자격과 접속 정보DatabaseConnect
403
404

GET /v1/orgs/{orgSlug}/projects/{projectName}/database/connect

/database 와 나눈 이유는 역할이다. "데이터베이스가 있는가"는 viewer 가 알아도 되는 사실이고 비밀번호는 아니다. 한 응답에 둘을 담고 역할에 따라 필드를 지우면, 지우는 것을 잊은 경로 하나가 곧 유출이다. member 이상만 받는다.

operationId getDatabaseConnect

응답본문
200접속 정보DatabaseConnect
403
404프로젝트가 없거나 데이터베이스를 아직 만들지 않았다Error

GET /v1/orgs/{orgSlug}/projects/{projectName}/database/endpoint

host·port·database·sslmode 만이다. viewer 도 받는다 — 비밀이 없다. runlot port-forward 는 로그인 세션으로 붙으므로 (front 가 세션을 검증한다, docs/pg-driver-support.md §4.4) 비밀번호가 필요 없고, 이 끝점만 있으면 된다.

operationId getDatabaseEndpoint

응답본문
200끝점object
403
404

GET /v1/orgs/{orgSlug}/projects/{projectName}/database/tokens

비밀번호도 검증기도 없다. member.

operationId listDatabaseTokens

응답본문
200목록object
403
404

POST /v1/orgs/{orgSlug}/projects/{projectName}/database/tokens

접속 문자열에 넣는 user/password 한 벌. 비밀번호는 이 응답에만 있다 — CP 는 SCRAM 검증기만 두고, 잃으면 새로 발급한다. 세션은 그래도 프로젝트의 롤로 열린다: 토큰 사용자는 인증의 이름이지 엔진 롤이 아니다. member.

operationId createDatabaseToken

본문 application/json · object

응답본문
201발급된 자격DatabaseToken
400
403
404

DELETE /v1/orgs/{orgSlug}/projects/{projectName}/database/tokens/{tokenUser}

다음 연결부터 거절이다. 없는 것을 지우면 404. member.

operationId deleteDatabaseToken

응답본문
204폐기했다
403
404

POST /v1/orgs/{orgSlug}/projects/{projectName}/database/export

백업이 아니다 (docs/env-db-assembly.md §5). 만들어지는 것은 현재 (project, epoch) 아래의 불변 진단 키이고, latest·freshness· retention 어느 포인터도 움직이지 않으며 다음 자동 백업의 이름에도 영향을 주지 않는다.

정기 백업은 이제 돈다 (Phase 5, docs/phase5.md): node-agent 가 스케줄러와 노드 전역 세마포어를 소유하고 스텝 세대를 RPO 1h 격자로 뜬다. 그 세대는 gen/<project>/<epoch>/ 에 살고 …/database/generations 가 나열하며 …/database/restore 가 고른다. 이 경로가 만드는 진단 이미지는 그 네임스페이스 에 남는다 — 복원이 고를 수 없고, 프루닝이 세지 않으며, latest 를 못 움직인다.

멱등이 아니다. 부를 때마다 이미지가 하나씩 생긴다 — 서버가 요청마다 새 stamp 를 짓기 때문이다. 멱등하게 흡수되는 것은 노드까지 내려간 뒤의 같은 stamp 재시도뿐이다.

member 이상만 받는다. 이미지는 데이터베이스 전체라 viewer 가 한 번의 호출로 가져갈 것이 아니다.

느리다. 응답은 덤프가 끝난 뒤에 온다 — 크기에 비례하고, 그동안 그 프로젝트의 액터는 붙잡혀 있다.

operationId exportDatabase

응답본문
200만들어진 진단 키DatabaseExport
403
404프로젝트가 없거나 데이터베이스를 아직 만들지 않았다Error
409배치가 정지 상태다 (suspended). 진단 export 는 도는 incarnation 에서만 뜬다 — 정지된 프로젝트의 데이터를 꺼내는 것은 복원 경로의 일이다.Error
502노드가 이미지를 만들지 못했다 (export_failed)Error
503내보낼 수 있는 상태가 아니다 — 홈 노드 주소가 없거나 (no_home_node), CP 에 노드 admin 경로가 설정되지 않았다 (no_node_admin).Error

GET /v1/orgs/{orgSlug}/projects/{projectName}/database/generations

복원이 고를 수 있는 것 전부다 (docs/phase5.md B1). CP 의 db_generations 표를 그대로 읽는다 — 오프사이트를 훑지 않는다: bytes·sha256 가 CP 에 있어야 복원이 받은 바이트를 검증한다.

lastCheckedAt무변경 스킵의 하트비트다. 세대가 늘지 않는 것과 백업이 죽은 것은 다른 일이고, 이 값이 그 둘을 가른다 — 비어 있으면 아직 한 번도 확인하지 않았다는 뜻이다.

member 이상만 받는다. 목록에는 오프사이트 키와 다이제스트가 실린다.

데이터베이스 자격을 요구하지 않는다. pg delete 뒤에도 최종 안전 세대는 남고, 그것을 보는 것이 이 목록의 마지막 쓸모다.

operationId listGenerations

응답본문
200세대 목록 (최신 순)DatabaseGenerations
403
404

POST /v1/orgs/{orgSlug}/projects/{projectName}/database/restore

세대 복원은 퇴거 + 재활성이다 (docs/phase5.md B2). pg.restore 가 빈 저장소만 받는 성질이 이 모양을 정한다: draining → sealing(현재 데이터로 pre-restore 세대를 먼저 남긴다 — 되돌릴 길) → committing(고른 세대를 final_gen 에 적는다) → 재활성(epoch+1).

그 사이의 쓰기는 사라진다. 그래서 admin 이상이고, CLI 는 프로젝트 이름을 다시 입력받는다.

latest 를 서버가 해석하지 않는다. 목록에서 본 (epoch, seq) 를 그대로 싣는다 — 서버가 "가장 최근"을 고르면 그 사이에 정기 세대가 하나 더 뜬 경우 사용자가 본 것과 다른 세대로 간다.

202 다. 돌아오는 것은 결과가 아니라 연산 id 이고, 진행은 …/database/operations/{opId} 로 본다.

operationId restoreDatabase

본문 application/json · RestoreRequest

응답본문
202연산을 열었다OperationStarted
400
403
404프로젝트가 없거나 데이터베이스를 아직 만들지 않았다Error
409이미 다른 연산이 진행 중이거나 (operation_in_progress) 배치가 정지 상태다 (suspended).Error
503복원할 수 있는 상태가 아니다 (홈 노드 없음 등)Error

POST /v1/orgs/{orgSlug}/projects/{projectName}/database/delete

draining → sealing(최종 안전 세대를 final 로 남긴다) → committing(project_databases 행 삭제; 노드는 다음 수렴에서 env.db 없는 프로세스로 교체하고 데이터 디렉터리를 tombstone 으로 옮긴다, docs/phase5.md B3). admin 이상.

confirm 이 프로젝트 이름과 정확히 같아야 한다. 다르면 400 confirm_mismatch 이고 아무것도 시작되지 않는다. CLI 의 프롬프트만으로는 부족하다 — --yes 를 단 스크립트가 잘못된 디렉토리에서 돌면 프롬프트가 아예 뜨지 않는다.

DELETE 메서드가 아닌 이유: 이 요청은 행 하나를 지우는 것이 아니라 202 로 시작해 분 단위로 끝나는 연산이고, 본문에 확인 문자열을 받아야 한다 — DELETE 의 본문은 지나는 프록시마다 취급이 다르다.

operationId deleteDatabase

본문 application/json · DeleteRequest

응답본문
202연산을 열었다OperationStarted
400확인 문자열이 프로젝트 이름과 다르다 (confirm_mismatch)Error
403
404프로젝트가 없거나 데이터베이스를 아직 만들지 않았다Error
409이미 다른 연산이 진행 중이다 (operation_in_progress)Error

GET /v1/orgs/{orgSlug}/projects/{projectName}/database/operations/{opId}

복원·삭제의 진행을 본다. CLI 가 2 초마다 두드리고 phase 가 바뀔 때마다 찍는다.

연산이 프로젝트 아래에 사는 이유는 id 가 자격이 아니기 때문이다. cp-core 의 /v1/operations/{opId} 는 id 를 아는 클라이언트(노드· cp-public)에게 답하지만, 사용자 표면이 그러면 id 하나가 다른 조직의 연산 상태를 여는 열쇠가 된다. 이 라우트는 답하기 전에 연산의 projectId 가 경로의 프로젝트인지 보고, 아니면 없는 것과 같은 404 를 준다.

member 이상.

operationId getDatabaseOperation

응답본문
200연산 상태Operation
403
404프로젝트에 그 연산이 없다 (다른 프로젝트의 연산도 여기로 온다)Error

POST /v1/orgs/{orgSlug}/projects/{projectName}/database/operations/{opId}/abort

되돌릴 수 없는 phase 앞에서만 된다 (docs/phase5.md B4): evict·restore_generation·delete 는 committing 전까지, restore 는 불가. 중단은 배치를 active 로 되돌리고 terminalCode=aborted 를 남긴다.

admin 이상. 서버는 먼저 읽고 그 다음에 중단한다 — 순서가 반대면 남의 프로젝트 연산을 실제로 중단한 뒤에 404 를 돌려주게 된다.

operationId abortDatabaseOperation

응답본문
200중단된 연산의 상태Operation
403
404프로젝트에 그 연산이 없다Error
409돌이킬 수 없는 지점을 지났다 (not_abortable) — committing 이후이거나 restore 연산이다.Error

이 페이지에서