AI 앱 빌더를 위한 PostgreSQL 데이터베이스 접근
읽기 전용 탐색, 범위가 제한된 자격 증명, 승인된 마이그레이션, 안전한 풀링으로 AI 앱 빌더의 PostgreSQL 데이터베이스 접근을 설정하세요.

AI 앱 빌더는 스키마를 소유하지 않아도 기존 PostgreSQL 데이터베이스에 연결할 수 있습니다. 다만 그 경계를 PostgreSQL에서 실제로 강제해야 합니다. «프로덕션을 변경하지 마세요»라는 프롬프트는 통제 수단이 아닙니다. 별도 역할, 트랜잭션 기본값, 명시적인 마이그레이션 검토, 스키마 검사는 통제 수단입니다.
안전한 모델은 데이터베이스 작업을 세 경로로 나눕니다. 탐색은 메타데이터를 읽고 허용된 데이터를 일부 확인합니다. 애플리케이션은 필요한 테이블과 작업에만 읽기와 쓰기를 수행합니다. 스키마 변경은 사람이 정확한 SQL을 승인한 뒤 별도의 마이그레이션 계정으로 실행합니다. 여러 팀이 이 경로를 편리한 소유자 자격 증명 하나로 합쳤다가, 에이전트가 그럴듯한 열 이름을 살아 있는 테이블을 다시 설계해도 된다는 허가로 받아들인 일을 봤습니다. 편리함은 반나절이었지만 정리는 훨씬 오래 걸렸습니다.
탐색은 구조적으로 읽기 전용이어야 합니다
탐색 연결에는 허용된 스키마를 파악할 만큼의 접근 권한은 필요하지만, 그것을 고칠 만큼의 권한은 필요 없습니다. 데이터베이스나 역할을 만들 수 없고, 행 수준 보안을 우회할 수 없으며, 광범위한 그룹에서 뜻밖의 권한을 상속받지 않는 로그인 역할을 만드세요. PostgreSQL은 새 역할에 처음부터 이런 권한을 주지 않지만, 명시적으로 선언하면 의도를 검토할 수 있습니다.
CREATE ROLE app_discovery
LOGIN
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
NOINHERIT
NOBYPASSRLS
CONNECTION LIMIT 3
PASSWORD 'replace-through-secret-manager';
ALTER ROLE app_discovery SET default_transaction_read_only = on;
GRANT CONNECT ON DATABASE customer_portal TO app_discovery;
GRANT USAGE ON SCHEMA app TO app_discovery;
GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_discovery;
default_transaction_read_only는 기본값을 유지하는 세션에서 일반 쓰기를 막습니다. 유용한 보호 장치이지만 유일한 방어선은 아닙니다. 클라이언트가 트랜잭션 설정을 바꾸더라도 역할을 제한하는 것은 INSERT, UPDATE, DELETE, TRUNCATE, CREATE 권한과 소유 권한이 없다는 사실입니다. 이 역할을 애플리케이션 소유자 그룹의 구성원으로 추가하지 말고, 스키마 소유자로도 만들지 마세요.
빌더가 연결하기 전에 기존 권한을 살펴봐야 합니다. 다음 쿼리는 테이블 권한마다 한 행을 반환하므로 검토자가 SELECT를 넘는 권한을 찾아낼 수 있습니다.
SELECT table_schema, table_name, privilege_type
FROM information_schema.role_table_grants
WHERE grantee = 'app_discovery'
ORDER BY table_schema, table_name, privilege_type;
정상적인 결과는 app | invoices | SELECT 같은 형태입니다. 결과가 비어 있으면 탐색이 필요한 테이블을 보지 못한다는 뜻일 수 있고, UPDATE로 끝나는 행이 있으면 역할의 권한이 너무 강합니다. 테이블 권한만으로 역할이 다른 곳에 객체를 만들 수 있는지 알 수 없으므로 has_schema_privilege로 스키마 권한을, has_database_privilege로 데이터베이스 권한도 확인하세요.
프로덕션 스냅샷을 소유자 자격 증명을 공유할 이유로 쓰지 마세요. 복사본에도 고객 데이터가 있을 수 있고, 소유 권한을 가진 에이전트가 이를 지나치게 바꾸면 나중의 비교가 무의미해질 수 있습니다. 모든 환경에서 탐색에는 전용 ID를 사용하세요.
카탈로그 검사는 허용 목록 안에 머물러야 합니다
빌더는 승인된 스키마만 탐색하고 PostgreSQL이 실제로 보고하는 내용을 기록해야 합니다. information_schema는 테이블, 열, 제약 조건, 권한에 관한 이식성 있는 뷰를 제공합니다. pg_catalog는 인덱스, 타입, 생성 표현식, 행 보안처럼 PostgreSQL에 특화된 세부 정보를 제공합니다. 둘 다 일반적인 고객 테이블에 대한 LLM의 기억보다 믿을 만한 출처입니다.
app, reporting 같은 허용 목록에서 시작하세요. pg_catalog, information_schema, 임시 스키마, 확장 스키마, 목록에 없는 모든 테넌트 스키마를 애플리케이션 대상에서 제외하세요. 쿼리는 데이터베이스, 역할, SQL 수준에서 필터링해야 합니다. 프롬프트 수준의 허용 목록만 두면 나중의 대화에서 사라질 수 있습니다.
SELECT
c.table_schema,
c.table_name,
c.ordinal_position,
c.column_name,
c.data_type,
c.is_nullable,
c.column_default
FROM information_schema.columns AS c
WHERE c.table_schema IN ('app', 'reporting')
ORDER BY c.table_schema, c.table_name, c.ordinal_position;
결과는 조회 시각과 데이터베이스 식별자를 포함한 스키마 스냅샷으로 저장하세요. 이 스냅샷은 생성기가 무엇을 보았는지 보여 주는 근거이지, 영구적인 진실은 아닙니다. 탐색과 코드 생성 사이에 PostgreSQL은 바뀔 수 있으므로 배포 전에 새 지문을 비교하세요. 실용적인 지문은 정렬된 테이블, 열, 타입, null 허용 여부, 기본값, 제약 조건, 인덱스 설명을 해시할 수 있습니다. 지문이 다르면 어떤 변경이 무해한지 추측하지 말고 멈춘 뒤 다시 탐색하세요.
행 샘플링은 별도의 권한 결정입니다. 열 메타데이터에는 개인정보가 거의 없지만 행 샘플에는 흔히 있습니다. 코드 생성에는 행을 전혀 샘플링하지 않는 편이 좋습니다. 예시가 꼭 필요하다면 비밀 정보와 직접 식별자를 제거하거나 마스킹한 뷰를 만들고, 그 뷰에만 SELECT를 부여하세요. LIMIT 10이 민감한 쿼리를 안전하게 만들지는 않습니다. 유출 규모만 줄일 뿐입니다.
검색 경로도 같은 방식으로 다뤄야 합니다. 승인된 스키마와 pg_catalog로 설정하고, 생성된 테이블 이름은 정규화하며, PostgreSQL이 먼저 찾아낸 객체에 의존하지 마세요. 공격자나 부주의한 마이그레이션이 쓰기 가능한 스키마에 같은 이름의 객체를 만들 수 있습니다. app.orders 같은 정규화된 이름은 이런 모호함을 없앱니다.
런타임 역할은 실제 사용자 작업에 맞춰야 합니다
탐색과 런타임은 다른 일입니다. 런타임 애플리케이션은 주문 삽입, 임시 저장본 업데이트, 신중하게 설계한 함수 호출이 필요할 수 있습니다. 그렇다고 발견한 스키마 전체에 폭넓은 쓰기 권한을 줄 이유는 없습니다. 사용자 작업을 바탕으로 권한 매트릭스를 만들고, 각 작업을 최소한의 PostgreSQL 권한으로 바꾸세요.
예를 들어 청구서 뷰어에는 app.invoices와 app.invoice_lines에 대한 SELECT가 필요할 수 있습니다. 메모 기능에는 app.invoice_notes에 대한 SELECT와 INSERT가 필요합니다. 청구서 DELETE, 비밀번호 재설정 기록 접근, 스키마 생성은 아마 필요하지 않을 것입니다. 삽입이 실제로 그 시퀀스에 의존할 때만 시퀀스 사용 권한을 주세요. PostgreSQL은 시퀀스를 별도 객체로 취급하므로 소유자 계정으로 테스트하는 생성기에는 이 점이 놀라움이 됩니다.
뷰와 함수로 노출 범위를 더 줄일 수 있습니다. 뷰는 내부 필드를 숨기면서 승인된 열만 보여 줄 수 있습니다. SECURITY DEFINER 함수는 일반 권한으로 표현하기 어려운 통제된 작업 하나를 수행할 수 있지만, 고정된 search_path, 엄격한 입력 검사, 불필요한 권한이 없는 소유자가 필요합니다. 이런 함수는 권한 모델을 우회하는 지름길이 아니라 권한 있는 코드로 다루세요.
행 수준 보안은 공유 테이블 안에서 데이터 경계를 더합니다. 테이블 권한을 대신하지는 않습니다. PostgreSQL은 먼저 역할이 작업을 할 수 있는지 검사한 뒤, 활성화되어 적용되는 경우 행 보안 정책을 적용합니다. 테이블 소유자와 BYPASSRLS 역할은 정책을 벗어날 수 있으므로 정확한 런타임 역할로 테스트하세요. 마이그레이션 소유자로 한 테스트는 최종 사용자가 무엇을 볼 수 있는지 거의 증명하지 못합니다.
비밀 정보는 프롬프트, 생성된 소스, 브라우저 번들, 빌드 로그, 스크린샷에 넣지 마세요. 런타임 자격 증명은 호스팅 환경의 비밀 저장소에 두고 서버 프로세스에만 주입하세요. 모바일과 브라우저 애플리케이션은 PostgreSQL 비밀번호를 비밀로 보관할 수 없으므로 직접 연결 대신 서버 API를 호출해야 합니다. 탐색, 런타임, 마이그레이션 자격 증명은 각각 독립적으로 교체하세요. 한 경로에서 유출이 발생해도 나머지 두 경로가 열리면 안 됩니다.
마이그레이션 권한은 별도 승인 경로에 둬야 합니다
앱 빌더는 마이그레이션을 제안할 수 있지만, 탐색이나 런타임 세션으로 실행해서는 안 됩니다. 마이그레이션 작업에 별도 역할을 주거나, 기존 배포 시스템이 승인된 작업 하나에 한해 그 역할을 맡도록 하세요. 일반 대화와 미리보기 세션 중에는 그 자격 증명을 사용할 수 없게 두세요.
승인에는 정확한 SQL, 대상 데이터베이스 식별자, 준비에 사용한 스키마 지문, 예상되는 잠금이나 재작성 동작이 포함되어야 합니다. «고객 상태를 추가한다» 같은 자연어 문장을 승인하면 여지가 너무 큽니다. 실제 변경은 null을 허용하는 텍스트 열을 추가할 수도 있고, 큰 테이블을 다시 만들거나, enum을 만들거나, 기존 모든 행을 업데이트할 수도 있습니다. 이들은 실패 방식이 서로 다른 작업입니다.
저는 간결한 마이그레이션 패킷을 사용합니다.
- 변경 이유와 이를 필요로 하는 애플리케이션 버전.
- 정확한 순방향 SQL과, 정직하게 제공할 수 있는 경우 정확한 되돌리기 SQL.
- 명령이 영향을 줄 수 있는 객체, 권한, 행.
- 사전 점검 쿼리, 예상 결과, 새 스키마 지문.
- 잠금 시간 제한, 문 시간 제한, 백업 또는 스냅샷 참조, 릴리스 책임자.
되돌리기 스크립트가 항상 롤백은 아닙니다. 새로 추가한 열을 삭제하면 카탈로그 변경은 되돌릴 수 있지만, 릴리스 후 그 열에 기록된 데이터도 파괴합니다. PostgreSQL의 트랜잭션 DDL은 많은 카탈로그 작업에 도움이 되지만, 트랜잭션으로 외부 부작용이나 이후 명령이 삭제한 데이터를 되살릴 수는 없습니다. DOWN을 마법의 단어처럼 다루지 말고 파괴적인 되돌리기에는 분명히 표시하세요.
lock_timeout을 설정해 마이그레이션이 새 작업을 막으면서 바쁜 트랜잭션 뒤에서 기다리는 대신 실패하게 하세요. statement_timeout은 검토한 작업에 맞춰 설정하세요. 변경 시간 창 안에서 사전 점검 쿼리를 다시 실행하세요. 테이블 크기, 충돌 객체, null 수, 스키마 지문이 승인 당시 가정과 다르면 중단하세요. 에이전트는 프로덕션에서 새 마이그레이션을 즉흥적으로 만들지 말고 불일치 보고서를 반환해야 합니다.
생성된 테스트가 통과했다는 이유만으로 마이그레이션을 자동 승인하지 마세요. 테스트는 보통 작고 깨끗한 스키마에서 실행되므로 잠금 대기열, 오래된 null, 특이한 제약 조건, 확장, 아직 트래픽을 처리하는 애플리케이션 버전을 놓칩니다. 승인은 사람이 생성된 의도와 실제 시스템을 조정하는 지점입니다.
연결 풀은 안전성 판단을 바꿉니다
풀은 데이터베이스 세션을 재사용하므로 세션 상태가 이를 만든 요청보다 오래 남을 수 있습니다. 한 요청이 SET search_path를 실행하거나 역할을 바꾸고, 임시 객체를 만들고, 시간 제한을 끄면 다음 사용자가 그 결과를 물려받을 수 있습니다. 애플리케이션은 변경 가능한 세션 상태를 피하거나 연결이 풀로 돌아갈 때 확실히 초기화해야 합니다.
트랜잭션 풀링에서는 경계가 더 엄격합니다. 클라이언트는 트랜잭션마다 다른 서버 세션을 받을 수 있어 세션 준비 문, 임시 테이블, 자문 잠금, 세션 수준 설정에 대한 가정이 깨집니다. 빌더는 직접 연결에서는 작동하지만 이 차이를 모델링하지 않아 풀 뒤에서는 실패하는 코드를 자주 생성합니다. 풀이 세션 모드인지 트랜잭션 모드인지 정한 뒤, 그 모드를 생성과 테스트에 포함하세요.
배포 전에 연결 수를 계획하세요. 데이터베이스가 허용하는 연결 수에서 관리, 마이그레이션, 모니터링, 다른 서비스용 여유를 빼고, 남은 수를 애플리케이션 인스턴스에 나누세요. 인스턴스 10개가 각각 연결 20개를 열면 트래픽이 한가해도 PostgreSQL은 잠재적으로 200개 세션을 봅니다. 데이터베이스가 거부할 때까지 연결을 늘리는 것보다, 대기열을 둔 보수적인 작은 풀이 대체로 안전합니다.
서버 측 시간 제한을 최후 방어선으로 쓰세요. statement_timeout은 긴 문을 제한하고, lock_timeout은 잠금 대기 시간을 제한하며, idle_in_transaction_session_timeout은 아무 작업도 하지 않으면서 트랜잭션을 열어 둔 세션을 제거합니다. 생성된 모든 클라이언트가 기억할 것이라 믿지 말고 역할별로 값을 설정하세요. 실제 역할과 실제 풀을 통해 SHOW로 값을 확인하세요.
상태 확인은 가벼워야 합니다. SELECT 1은 왕복을 확인하지만 애플리케이션이 승인된 테이블에 도달할 수 있는지나 검색 경로가 올바른지는 확인하지 못합니다. 준비 상태 확인은 런타임 역할로 작고 안정적인 뷰를 조회할 수 있습니다. 애플리케이션 시작 과정에서 마이그레이션을 실행하지 마세요. 스키마를 바꾸려고 동시에 경쟁하는 인스턴스는 이 설계가 없애려는 결합을 정확히 다시 만듭니다.
지어낸 열은 쿼리 실행 전에 실패해야 합니다
LLM은 그럴듯한 식별자를 지어냅니다. 프롬프트에서 고객의 표시 이름을 언급하면, 데이터베이스에는 given_name과 family_name만 있어도 생성된 코드가 customers.display_name을 찾을 수 있습니다. 데이터베이스가 그 쿼리를 거부하는 편이 잘못된 필드를 조용히 읽는 것보다 낫지만, 프로덕션 오류도 좋은 스키마 검증 전략은 아닙니다.
승인된 카탈로그 스냅샷에서 형식이 지정된 스키마 아티팩트를 생성하고, 그것만 쿼리 구성의 출처로 삼으세요. 이 아티팩트에 없는 테이블이나 열은 생성 오류를 일으켜야 합니다. 작업이 명시적으로 마이그레이션 경로에 들어가지 않았다면 모델이 마이그레이션을 추가해 오류를 고치게 두지 마세요. 누락된 식별자는 오래된 탐색, 철자 오류, 잘못된 환경, 실제 제품 요구 사항을 뜻할 수 있습니다. 각각 대응 방식이 다릅니다.
정적 검사는 SQL을 파싱하고 모든 관계와 열을 스냅샷에 대조해야 합니다. 그다음 쓰기가 불가능한 트랜잭션이나 일회용 데이터베이스에서 문을 준비하세요. PostgreSQL 파서는 실제 업무 데이터가 성공적으로 없어도 알 수 없는 열, 모호한 참조, 연산자 타입 오류, 많은 잘못된 캐스트를 찾아냅니다. 런타임 역할로 통합 테스트를 실행해 권한과 행 정책도 참여하게 하세요.
실패 보고서에는 사람이 결정할 수 있을 만큼의 정보가 필요합니다. SQL 위치, 해결되지 않은 식별자, 인근의 유효 식별자, 스냅샷 지문, 대상 데이터베이스 식별자를 포함하세요. 제안은 유용하지만 자동 유사어 치환은 위험합니다. 이름이 비슷하다는 이유로 billing_address_id를 shipping_address_id로 바꾸면 유효한 SQL이 되더라도 잘못된 업무 의미를 가질 수 있습니다.
동적 필터와 정렬에는 공개 API 이름을 정규화된 SQL 표현식의 닫힌 집합으로 매핑하세요. 값 파라미터를 사용하더라도 모델이 준 식별자를 SQL에 그대로 넣지 마세요. 파라미터는 값은 보호하지만 테이블이나 열 이름은 보호하지 못합니다. 사용자가 정렬 필드를 고를 수 있다면 created를 app.orders.created_at처럼 알려진 표현식으로 바꾸고, 알 수 없는 모든 토큰은 거부하세요.
스키마 드리프트는 릴리스를 멈춰야지 창의적인 조정을 시작하게 해서는 안 됩니다. 스냅샷을 다시 만들고 차이를 보여 준 뒤 테스트를 반복하세요. 그 지연은 까다롭게 느껴질 수 있지만, 데이터베이스에 대한 이해가 대화 기록에만 존재하는 코드를 배포하는 것보다 비용이 적습니다.
파괴적인 SQL에는 거부 정책과 근거가 필요합니다
빌더는 누구든 실행하기 전에 SQL을 분류해야 합니다. DROP, TRUNCATE, 검토된 조건이 없는 광범위한 DELETE 또는 UPDATE, 소유권 변경, 권한 상승, 확장 변경, 승인된 스키마 밖을 대상으로 한 명령을 차단하세요. ALTER TABLE은 자동으로 안전하다고 보지 말고 검토가 필요하다고 처리하세요. 열 타입 변경이나 새 nonnull 제약 조건은 데이터를 스캔하거나 다시 쓰고 중요한 잠금을 잡을 수 있습니다.
텍스트 일치만으로는 SQL에 주석, 인용된 식별자, 함수, 부작용을 표현하는 여러 방식이 있으므로 약합니다. PostgreSQL을 이해하는 파서로 문을 파싱하고 구문 트리를 검사하며, 데이터베이스 역할에도 금지된 작업을 거부하게 하세요. 분류기는 검토를 개선하고 권한은 경계를 강제합니다. 어느 하나도 모든 부담을 떠안아서는 안 됩니다.
마이그레이션이 실제 테이블 모양이나 데이터 분포에 의존한다면 최근의 적절히 보호된 스냅샷에서 복원한 스테이징 데이터베이스를 사용하세요. 그곳에 정확한 마이그레이션 패킷을 적용하고, 기간과 잠금 관찰 결과를 기록하며, 런타임 자격 증명으로 애플리케이션 테스트를 실행한 다음 환경을 폐기하세요. 스테이징과 프로덕션 사이에서 SQL을 조용히 고치지 마세요. 수정할 때마다 새 지문과 승인이 필요한 새 아티팩트가 됩니다.
로그는 비밀 정보나 민감한 행을 기록하지 않고 제안과 실행을 연결해야 합니다. 변경할 수 없는 마이그레이션 아티팩트를 승인한 사람, 다이제스트, 대상 식별자, 시작과 종료 상태, PostgreSQL 오류 세부 정보를 기록하세요. 생성된 차이와 사전 점검 결과도 보존하세요. 에이전트 대화는 유용한 맥락이지만 사용자가 분기, 재시도, 지시를 바꿔 말할 수 있으므로 감사 기록은 아닙니다.
스냅샷과 롤백 통제는 복구 시간을 줄이지만 파괴적인 SQL을 허용할 이유가 되지 않습니다. 실제 필요가 삭제된 열 하나를 복구하는 것인데도 스냅샷은 데이터베이스 전체를 이전 시점으로 복원할 수 있으며, 복원 과정에서 스냅샷 이후의 정상 쓰기가 사라질 수 있습니다. 복구는 별도로 테스트하고 누가 실행할 수 있는지 문서화하세요.
Koder.ai로 기존 데이터베이스를 다루는 앱을 만들 때 저는 내보낸 소스와 제안된 데이터베이스 경계를 검토할 때까지 작업을 계획 모드에 둡니다. 스냅샷과 롤백은 복구 통제이지 그 검토를 건너뛸 권한이 아닙니다. 이 원칙은 어떤 빌더에도 같습니다. 제품의 편리함은 데이터베이스 강제 기능 뒤에 있어야 합니다.
스키마 변경은 혼재된 애플리케이션 버전을 견뎌야 합니다
마이그레이션은 릴리스 시간 창에 이전 애플리케이션과 새 애플리케이션이 모두 실행될 수 있을 때만 안전합니다. 프로덕션이 한순간에 한 버전에서 다른 버전으로 바뀌는 일은 드뭅니다. 새 인스턴스가 시작되는 동안 요청은 이전 인스턴스에 도달할 수 있고, 대기열 작업은 오래된 페이로드를 담을 수 있으며, 롤백하면 오늘의 스키마에 어제의 코드가 다시 올라갈 수 있습니다. 최종 코드와 최종 스키마만 검증하는 앱 빌더는 이 겹침을 놓칩니다.
먼저 추가적인 변경을 선호하세요. null을 허용하는 열, 새 테이블, 기존 경로를 없애지 않는 인덱스를 추가하세요. 두 표현을 모두 읽을 수 있고 적절한 곳에 새 표현을 쓰는 코드를 배포하세요. 별도 검토를 거친 작업으로 기존 행을 채우고, 오류와 지연을 지켜본 뒤 새 필드를 기준으로 삼으세요. 실행 중인 코드가 옛 열이나 제약 조건을 사용하지 않는다는 근거가 생긴 뒤 다음 릴리스에서 제거하세요.
이 순서는 ALTER TABLE 문 하나를 생성하는 것보다 오래 걸리지만 실패를 분리합니다. 제거 전에 새 코드가 오작동해도 이전 경로는 남아 있습니다. 데이터 채우기가 늦어져도 애플리케이션 릴리스를 붙잡지 않고 멈출 수 있습니다. 배포를 롤백해도 이전 애플리케이션은 데이터베이스를 이해합니다. 추가 릴리스의 비용은 롤백 중에 이전 바이너리가 이미 삭제된 열을 조회한다는 사실을 발견하는 비용보다 작습니다.
이름 변경은 PostgreSQL이 이름을 즉시 바꾸므로 특히 조심해야 합니다. 생성기는 새 이름이 더 읽기 좋다는 이유로 customer_ref를 customer_id로 바꾸자고 제안할 수 있습니다. 이전 인스턴스는 마이그레이션이 커밋되는 즉시 실패합니다. customer_id를 추가하고, 애플리케이션 코드나 좁게 검토한 트리거로 두 필드를 동기화하며, 읽는 쪽을 옮긴 뒤, 이전 작성자가 사라진 다음에만 customer_ref를 제거하세요. 임시 중복은 제거 조건이 있는 눈에 보이는 부채이고, 즉시 이름 변경은 눈에 보이지 않는 릴리스 결합입니다.
기본값과 nonnull 제약 조건에도 숨은 작업이 있을 수 있습니다. SET NOT NULL을 승인하기 전에 기존 null 수를 세고, 실행 중인 모든 작성자가 값을 제공함을 증명하세요. 크거나 바쁜 테이블에서는 PostgreSQL 버전이 제약 조건을 어떻게 검증하고 어떤 잠금을 잡는지 검토하세요. 빌더는 대표 트래픽이 없는 스키마에서 이를 추론하지 말고 이런 전제 조건을 보고해야 합니다.
데이터 채우기는 범위가 정해지지 않은 스키마 트랜잭션 안에서 수행하면 안 됩니다. 승인된 워커로 행을 측정 가능한 배치 단위로 업데이트하고, 안정적인 커서로 진행 상황을 기록하며, 재시도를 멱등적으로 만드세요. 멱등적 재시도란 PostgreSQL이 두 번째 쿼리를 받아들이는 것만이 아니라 두 번 적용해도 의도한 상태가 되는 것입니다. 파생 값은 이후 코드가 다르게 계산할 수 있다면 파생 버전도 기록하세요.
릴리스 패킷에는 호환성 지점 네 가지를 명시해야 합니다.
- 마이그레이션 전에 실행이 허용되는 가장 오래된 애플리케이션 버전.
- 이전 버전과 새 버전이 모두 받아들이는 스키마 상태.
- 파괴적 정리 릴리스를 허용하는 신호.
- 데이터 변경 뒤 새 코드가 롤백될 때의 복구 경로.
생성된 쿼리는 이 전환 과정에서 SELECT *를 피해야 합니다. 열을 추가하면 이전 SQL이 여전히 파싱되더라도 스캔 비용, 결과 디코딩, 위치 매핑, 데이터 노출이 바뀔 수 있습니다. 정규화된 열을 명시적으로 나열하고 같은 스키마 스냅샷에서 디코더를 생성하세요. 그러면 소스 검토에서 어떤 데이터가 데이터베이스 경계를 넘는지도 정확히 드러납니다.
정비된 마이그레이션 도구는 종종 적용된 버전을 테이블에 기록하지만, 버전 번호만으로 호환성을 증명할 수는 없습니다. 보기 좋은 이름이 같은 두 파일에 다른 명령이 들어 있을 수 있으므로 정확한 SQL 아티팩트의 다이제스트를 기록하세요. 실행기는 이미 기록된 버전에 다른 다이제스트가 있으면 거부해야 합니다. 필요한 선행 마이그레이션이 없을 때도 이후 마이그레이션을 거부해야 합니다.
애플리케이션 인스턴스마다 시작 시 마이그레이션을 실행하게 하지 마세요. 마이그레이션 도구가 자문 잠금을 쓰더라도 이제 시작은 권한 있는 자격 증명과 상태 확인 시간 제한 전에 스키마 작업이 끝나는 데 의존합니다. 마이그레이션 실행은 하나의 릴리스 작업에 두고 기록된 결과를 기다린 뒤, 스키마를 바꿀 수 없는 ID로 런타임 인스턴스를 시작하세요. 릴리스 시스템이 이 단계를 분리할 수 없다면 애플리케이션에 소유자 권한을 주기 전에 릴리스 시스템부터 고치세요.
목적지만이 아니라 다음 시간선을 테스트하세요. 이전 스키마의 이전 코드, 확장된 스키마의 이전 코드, 확장된 스키마의 새 코드, 새 쓰기 후 롤백된 코드입니다. 정리는 나중에 별도 테스트를 받습니다. 이 매트릭스는 문법적으로는 유효하지만 운영상 되돌릴 수 없는 변경을 찾아냅니다.
부정 테스트로 경계를 증명하세요
안전 설계는 금지된 작업이 테스트에서 실패할 때까지 완성되지 않습니다. 탐색 역할로 연결해 삽입, 테이블 생성, SET TRANSACTION READ WRITE를 시도하세요. 런타임 역할로 연결해 권한이 없는 테이블 접근, 행 보안이 적용된 테넌트 간 읽기, 스키마 변경을 시도하세요. 기대 결과는 에이전트 로그의 약속이 아니라 PostgreSQL 권한 오류입니다.
긍정 테스트도 실행하세요. 탐색은 허용된 모든 카탈로그 항목을 계속 읽을 수 있어야 합니다. 런타임은 풀을 통해 승인된 모든 사용자 작업을 수행해야 합니다. 마이그레이션 실행은 승인 경로를 통해서만 작동해야 합니다. 제품의 정상 작업을 막는 경계는 사고가 났을 때 누군가 소유자 자격 증명으로 바꾸고 싶게 만듭니다.
애플리케이션 소스 옆에 작은 접근 계약을 두세요. 데이터베이스, 허용 스키마, 탐색 범위, 런타임 작업, 풀 모드, 시간 제한 정책, 마이그레이션 승인자, 스키마 지문 방식, 금지 문을 적어야 합니다. 지속적 검사에서 실제 권한을 이 계약과 비교하세요. 아무도 애플리케이션 코드를 바꾸지 않았더라도 PostgreSQL 권한 드리프트는 구성 드리프트입니다.
역할 변경, 새 테이블, 데이터베이스 복원, 풀 업그레이드, 호스팅 변경 후에는 다시 확인하세요. 기본 권한은 미래 객체에 중요합니다. GRANT SELECT ON ALL TABLES는 현재 테이블에는 적용되지만 나중에 만든 테이블에는 적용되지 않습니다. 새 객체를 검토 전까지 보이지 않게 할지, 좁게 설정한 기본 권한으로 포함할지 결정하세요. 명시적 권한 부여가 새 테이블을 접근 권한 논의에 올려놓으므로 저는 기본적으로 보이지 않게 두는 편입니다.
권한 철회도 테스트 계획에 넣으세요. 탐색 자격 증명을 비활성화하고 런타임 트래픽은 계속되는지 확인하세요. 런타임을 비활성화하고 마이그레이션 도구가 더 강한 ID를 조용히 대신 쓰지 않는지 확인하세요. 그다음 연결이 살아 있는 동안 각 비밀 정보를 교체하고 풀이 의도한 시간 창 안에 이전 세션을 폐기하는지 살펴보세요. 비밀번호를 바꿔도 이미 인증된 세션은 종료되지 않으므로, 교체 절차에는 명시적인 풀 재시작이나 PostgreSQL 세션 종료 정책이 필요합니다.
이 테스트 중에는 오류 메시지가 실수로 정보를 드러내지 않는지도 검토하세요. PostgreSQL 오류에는 관계 이름, SQL 조각, 제약 조건 이름, 제공된 값이 들어갈 수 있습니다. 상세 오류는 접근이 제한된 서버 로그로 보내고, 클라이언트에는 일관된 공개 오류를 반환하며, 프로덕션 오류 스트림 전체를 에이전트 대화에 다시 넣지 마세요. 빌더가 코드를 고치려면 문 위치와 정제된 데이터베이스 응답이 필요할 뿐 고객 값은 필요하지 않습니다.
마지막 테스트 하나로 놀랄 만큼 많은 안전하지 않은 통합을 찾아낼 수 있습니다. 마이그레이션 자격 증명을 완전히 제거하고 애플리케이션 테스트 모음을 실행하세요. 정상 시작, 상태 확인, 미리보기, 요청 처리가 실패한다면 스키마 소유 권한이 런타임 경로로 새어 나온 것입니다. 빌더를 프로덕션에 연결하기 전에 그 결합을 고치세요. AI 앱 빌더는 소유하지 않은 데이터베이스와도 작동할 수 있지만, 생성된 코드가 약속을 잊었을 때 PostgreSQL은 거부할 수 있어야 합니다.
자주 묻는 질문
AI 앱 빌더가 기존 PostgreSQL 데이터베이스를 사용할 수 있나요?
예. 빌더가 전용 역할로 연결하고 승인된 스키마만 탐색하도록 하면 됩니다. 도구를 연결했다고 해서 스키마 소유 권한까지 주어지지 않도록 탐색, 런타임 쿼리, 마이그레이션을 서로 다른 권한 경로로 분리하세요.
읽기 전용 PostgreSQL 사용자를 만들면 데이터가 절대 바뀌지 않나요?
SELECT만 있고 객체 소유 권한이 없는 역할이 핵심 통제 수단입니다. default_transaction_read_only도 보호를 더하지만, 광범위한 권한이나 상속된 멤버십을 보완하는 수단으로 삼아서는 안 됩니다.
빌더에 데이터베이스 소유자 비밀번호를 줘야 하나요?
아니요. 소유자 자격 증명은 경계를 무너뜨리고, 생성된 SQL이 권한, 테이블, 데이터를 바꾸게 할 수 있습니다. 탐색용, 런타임용, 통제된 마이그레이션 작업용 자격 증명을 따로 만드세요.
앱 빌더가 스키마를 안전하게 파악하려면 어떻게 해야 하나요?
범위가 제한된 역할로 승인된 information_schema와 pg_catalog 뷰만 조회하게 한 뒤, 지문이 포함된 스냅샷을 저장하세요. 그 목적을 위해 마스킹된 뷰를 준비하지 않았다면 행 샘플링은 피하세요.
AI가 PostgreSQL 열 이름을 지어내면 어떻게 되나요?
배포 전에 형식이 지정된 스키마 스냅샷과 대조해 생성이 실패해야 합니다. 알 수 없는 이름과 가까운 유효 이름을 보고하되, 코드 수정, 새 탐색, 승인된 마이그레이션 중 무엇이 필요한지는 사람이 결정해야 합니다.
애플리케이션이 브라우저나 모바일 앱에서 직접 연결해도 되나요?
브라우저와 모바일 앱은 데이터베이스 비밀번호를 비밀로 지킬 수 없으므로 PostgreSQL에 직접 연결하면 안 됩니다. 데이터베이스 접근은 서버 프로세스에 두고, 브라우저나 모바일 앱은 그 API를 호출하게 하세요.
생성된 애플리케이션에 연결 풀이 필요한가요?
대체로 필요하지만 신중하게 설정해야 합니다. 전체 세션 수를 제한하고, 세션 모드 또는 트랜잭션 모드를 선택하며, 변경 가능한 상태를 초기화하고, 프로덕션과 같은 풀을 통해 생성된 코드를 테스트하세요.
PostgreSQL 마이그레이션을 안전하게 롤백할 수 있나요?
일부 카탈로그 변경은 트랜잭션 안에서 깔끔하게 되돌릴 수 있지만, 데이터 손실과 외부 부작용은 그렇지 않습니다. 순방향 SQL과 되돌리기 SQL을 따로 검토하고, 스냅샷은 변경이 안전하다는 증명이 아니라 복구 도구로 다루세요.
빌더가 승인되지 않은 테이블을 바꾸지 못하게 하려면 어떻게 하나요?
스키마 허용 목록, 정규화된 이름, 좁은 권한, 파싱된 SQL 정책, 부정 권한 테스트를 사용하세요. 모델이나 정책 검사기가 실수하더라도 PostgreSQL 역할은 작업을 거부해야 합니다.
앱 빌더가 스키마를 얼마나 자주 다시 탐색해야 하나요?
저장된 지문이 달라졌을 때와 마이그레이션, 복원, 환경 변경 후에 다시 탐색하세요. 릴리스 중에 조용히 새로고침하지 말고, 차이를 보여 준 뒤 새 스냅샷을 기준으로 검증을 다시 실행하세요.