Skip to content

DocumentLibrary 데이터베이스 전수 감사 보고서 ​

감사 대상: hohyun94/DocumentLibrary
감사 기준: MySQL/MariaDB와 PostgreSQL의 선택적 지원, 빈 데이터베이스에서의 초기화, 배포 플랫폼 배포 기동 안정성
판정: 수정 완료 및 양 방언 실제 엔진 검증 통과

범위와 방법 ​

이번 감사는 배포 로그에 나타난 relation "organization_departments" does not exist 오류를 시작점으로 삼았다. 단일 누락 테이블만 보완하는 대신, 서버의 연결 생성, 방언 판별, 직접 SQL, 트랜잭션, 결과 행 변환, Drizzle 스키마와 마이그레이션 체인, 최초 설치 API, 설치 화면, 배포 플랫폼 시작 명령, SSL 연결 모드까지 추적했다.

점검 영역확인 범위결과
연결 및 드라이버pg, mysql2, URL 프로토콜, DATABASE_DIALECT양 방언 선택 지원으로 정비
마이그레이션PostgreSQL 1개, MySQL 11개 파일, 저널 및 메타테이블빈 DB 및 재실행 검증 통과
런타임 SQL6개 직접 SQL 모듈과 부트스트랩 쿼리방언 의존 구문을 명시 분기
초기 설치/api/setup/status, validate, install, 관리자 프로비저닝PostgreSQL·MySQL 선택 지원
배포배포 설정, 시작 명령, health check마이그레이션 선행 후 서버 기동
데이터 정합성UPSERT, 블롭 참조 수, 갱신 시각, 집계 APIPostgreSQL과 MySQL 동작 일치 보강

주요 발견 사항과 조치 ​

심각도발견 사항영향조치
차단배포 플랫폼가 빌드 후 pnpm start만 실행했다. PostgreSQL 마이그레이션이 실행되지 않아 organization_departments가 없었다.서버 시작 직후 종료start:with-migrations를 추가하고 배포 플랫폼 시작 명령을 변경했다.
높음런타임 어댑터가 PostgreSQL만 허용해 기존 MySQL 코드를 실제로 사용할 수 없었다.MySQL/MariaDB 배포 불가mysql2 기반 공통 풀·트랜잭션 어댑터와 URL 기반 방언 선택을 구현했다.
높음설치 화면은 MySQL/MariaDB를 안내했지만 설치 API와 부트스트랩은 PostgreSQL 전용이었다.UI와 서버 계약 불일치설치 화면, validate, install, 마이그레이션 경로를 양 방언 기준으로 통일했다.
높음ON CONFLICT, EXCLUDED, JSONB, GROUP_CONCAT가 공통 경로에 혼재했다.선택한 DB에 따라 설치 또는 API가 실패UPSERT·문자열 집계·버전 조회를 방언별 SQL로 분기했다.
높음MySQL 마이그레이션에 빈 마지막 breakpoint와 64자를 초과하는 생성 제약 이름이 있었다.MariaDB 초기화 실패원본 해시는 유지한 채 실행 시 빈 구문을 제거하고 제약 이름을 64자로 안전하게 축약했다.
중간MySQL에는 portal_installation_config 스키마와 마이그레이션이 없었다.최초 설치 설정 저장 실패MySQL 스키마와 0010_add_portal_installation_config.sql을 추가했다.
중간PostgreSQL의 단순 ? 치환기는 SQL 문자열·주석 내부의 물음표까지 $n으로 바꿀 수 있었다.일부 쿼리 손상 위험문자열, 식별자, 주석, dollar-quoted body를 인지하는 변환기로 교체하고 회귀 테스트를 추가했다.
중간PostgreSQL에서 sslmode=require 경고가 발생할 수 있었다.차기 pg 버전에서 TLS 의미 변경 위험기존 안전 동작을 유지하도록 verify-full을 명시한다.
중간MySQL 자동 updated_at 갱신과 달리 PostgreSQL 블롭 갱신에는 갱신 시각 기록이 없었다.파일 대장의 최신성 정렬 불일치블롭 참조 수 변경 시 updated_at = CURRENT_TIMESTAMP를 명시했다.

구현 결과 ​

방언 선택 및 연결 ​

DATABASE_URL은 postgresql:// 또는 mysql:// 형식만 허용한다. DATABASE_DIALECT는 postgresql 또는 mysql이며, 설정된 경우 URL 프로토콜과 반드시 일치해야 한다. 일치하지 않으면 서버 또는 마이그레이션은 즉시 실패하므로 잘못된 드라이버로 연결되는 묵시적 장애를 방지한다.

구성PostgreSQLMySQL/MariaDB
런타임 드라이버pgmysql2
마이그레이션 폴더drizzle/postgres-migrationsdrizzle/legacy/mysql/migrations
설치 화면 선택값postgresqlmysql
상태 저장 UPSERTON CONFLICT ... EXCLUDEDON DUPLICATE KEY UPDATE
파일 대장 문자열 집계STRING_AGGGROUP_CONCAT

배포 경로 ​

pnpm start:with-migrations는 pnpm db:migrate를 먼저 실행하고 성공한 경우에만 pnpm start를 실행한다. 따라서 스키마가 없는 새 데이터베이스에서는 서버가 테이블을 참조하기 전에 해당 방언의 전체 마이그레이션이 적용된다. 배포 설정은 PostgreSQL을 기본 배포 방언으로 명시하고 이 시작 명령을 사용한다.

이번 배포 장애의 직접 원인은 데이터베이스 연결 자체가 아니라 테이블 생성 전 서버가 기동된 순서 문제였다. 수정 후에는 마이그레이션 실패가 서버 기동 실패로 명확히 노출되며, 마이그레이션이 성공한 경우에만 readiness endpoint가 제공된다.

MySQL 레거시 체인 호환성 ​

기존 MySQL SQL 파일의 원문과 SHA-256 해시는 보존한다. 실행기는 Drizzle 메타데이터 규약에 맞춰 원본 해시와 저널 시각을 기록하되, 실행 직전에만 빈 breakpoint 구간을 제외하고 MariaDB 제한을 넘는 제약 이름을 축약한다. 따라서 기존 설치의 이력을 임의로 재작성하지 않으면서, 새 MySQL/MariaDB 설치가 실제로 통과하도록 한다.

실제 검증 결과 ​

검증에는 PostgreSQL 16.15 및 MariaDB 10.11.14의 빈 로컬 데이터베이스를 사용했다. 각 방언에서 최초 마이그레이션, 반복 마이그레이션, 실제 배포 시작 명령, readiness endpoint 및 파일 대장 API를 실행했다.

검증 항목PostgreSQLMySQL/MariaDB결과
TypeScript 정적 검사공통공통통과
기존 클라이언트 테스트공통공통44개 통과, 3개 기존 skip
새 서버 어댑터 테스트공통공통5개 통과
프로덕션 번들 생성공통공통통과 (dist/index.js, dist/run-migrations.js)
빈 DB 최초 마이그레이션14개 애플리케이션 테이블14개 애플리케이션 테이블통과
반복 마이그레이션1개 마이그레이션 레코드 유지11개 마이그레이션 레코드 유지통과
pnpm start:with-migrationsreadiness ready: truereadiness ready: true통과
/api/archive/file-ledger[] 응답 및 STRING_AGG 실행[] 응답 및 GROUP_CONCAT 실행통과

운영 주의 사항 ​

개발 서버는 데이터 보존이 필요 없다는 현재 전제에 따라, 배포가 계속 실패할 경우 개발용 데이터베이스를 비운 뒤 최신 커밋으로 재배포해도 된다. 구체적인 선택 방언, 환경 변수, 재초기화 절차는 이중 데이터베이스 배포 가이드에 정리했다.

항목현재 처리주의 사항
배포 플랫폼 doclib 환경 전달DATABASE_URL을 그대로 수신URL이 PostgreSQL URL인지, DATABASE_DIALECT=postgresql과 일치하는지 확인해야 한다.
MySQL과 PostgreSQL 사이의 데이터 이전범위 외두 DB를 모두 지원하지만 자동 데이터 변환 도구는 제공하지 않는다. 현재 개발 서버는 데이터 재생성이 허용된다.
다중 인스턴스 동시 배포단일 인스턴스 기준 검증다중 replica 운영으로 바꿀 경우 별도 migration job 또는 배포 잠금이 필요하다.
운영 DB 초기화금지운영 환경은 백업과 롤백 계획이 있는 별도 변경 절차를 사용해야 한다.

변경 파일 요약 ​

구분주요 파일
드라이버 및 방언 추상화server/db-adapter.ts, server/db.ts
마이그레이션server/database-migrations.ts, server/run-migrations.ts, drizzle.config.ts
MySQL 스키마 보완drizzle/legacy/mysql/schema.ts, drizzle/legacy/mysql/migrations/0010_add_portal_installation_config.sql
설치 API 및 UIserver/setupBootstrap.ts, server/portalIntegrationConfig.ts, client/src/pages/Setup.tsx
런타임 쿼리 호환성server/archive-api-db.ts
배포와 문서package.json, 배포 설정, .env.example, docs/DATABASE_DIALECT_DEPLOYMENT.md

결론적으로, DocumentLibrary는 이제 PostgreSQL과 MySQL/MariaDB를 명시적으로 선택해 설치·마이그레이션·기동할 수 있으며, 최초 장애를 유발한 PostgreSQL 스키마 미적용 경로는 배포 시작 단계에서 차단된다.