Skip to content

feat(db): D1/Postgres/MySQL/SQLite 다중 방언 + Node 런타임 + S3 스킨 캐시 지원 - #66

Merged
mack-erel merged 4 commits into
mainfrom
claude/hyperdrive-multi-db-support-avsgcm
Jul 1, 2026
Merged

feat(db): D1/Postgres/MySQL/SQLite 다중 방언 + Node 런타임 + S3 스킨 캐시 지원#66
mack-erel merged 4 commits into
mainfrom
claude/hyperdrive-multi-db-support-avsgcm

Conversation

@mack-erel

Copy link
Copy Markdown
Owner

개요

기존 Cloudflare D1 전용이던 데이터 계층을 여러 DB 방언과 런타임에서 동작하도록 일반화합니다. Cloudflare 락인을 해제하되, 미설정 시 기본값은 전부 기존과 동일(d1 + adapter-cloudflare)하여 하위 호환을 유지합니다.

주요 변경

  • 다중 DB 방언: d1(기본) / postgres / mysql / sqlite(libSQL)DB_DIALECT 환경변수로 선택. vite define으로 __DB_DIALECT__를 리터럴 치환 → esbuild DCE로 활성 드라이버만 번들에 포함.
  • 스키마 분리: 단일 schema.ts → 방언별 schema.sqlite.ts / schema.pg.ts / schema.mysql.ts. schema.ts$db-active-schema alias로 재-export하는 배럴. (D1이 쓰는 schema.sqlite.ts는 기존 schema.ts와 코드 동일)
  • 런타임 선택: adapter-cloudflare(기본) / adapter-node(BUILD_TARGET=node). 설정을 platform.env(Workers) → process.env(Node) 순으로 읽어 순수 Node 배포 지원.
  • 연결 경로: Postgres/MySQL은 Hyperdrive 바인딩 → DATABASE_URL(var/secret) → process.env 순으로 해석. Hyperdrive 없는 직결도 지원.
  • 스킨 캐시 스토리지: R2 바인딩(기본) → S3 호환(AWS/MinIO/Ceph, aws4fetch) → 없으면 무캐시 폴백.
  • 방언 중립화: UPDATE ... RETURNING 미지원인 MySQL 등을 위해 grant / ratelimit / webauthn / signing-keys 에 방언별 분기 추가. d1 브랜치는 기존 코드와 동일 동작.

하위 호환 / 안전성

  • 기본 경로(Cloudflare + D1)는 동작 변경 없음: 스키마·마이그레이션·필수 바인딩 모두 기존과 동일.
  • 신규 마이그레이션 없음 (drizzle/는 gitignore, D1 out 경로 유지).
  • 신규 의존성(postgres, mysql2, @libsql/client, aws4fetch, adapter-node)은 d1 번들에서 DCE로 제거됨.

확인 필요

  • 기본값(d1/cloudflare)으로 bun run build 시 Worker 번들에 Node 전용 모듈이 섞이지 않는지 (DCE 정상 동작).

🤖 Generated with Claude Code

claude added 3 commits July 2, 2026 00:34
배포 단위로 D1(SQLite)·PostgreSQL·MySQL 중 하나를 선택해 사용할 수 있게 한다.
D1 의 높은 지연을 피하려면 Cloudflare Hyperdrive 로 PostgreSQL/MySQL 에 연결한다.

- DB_DIALECT(d1|postgres|mysql) 환경변수로 배포 단위 방언 선택 (기본 d1)
- 방언별 스키마 분리: schema.sqlite/pg/mysql.ts (테이블·컬럼·인덱스명, JS 추론
  타입을 동일하게 유지). schema.ts 배럴이 $db-active-schema alias 로 활성 방언 해석
- getDb() 가 방언에 맞는 드라이버(d1/postgres-js/mysql2) 선택. vite define +
  리터럴 분기 DCE 로 활성 방언 드라이버만 워커 번들에 포함
- 정규 DB 타입은 $db-active-driver alias 로 활성 방언 드라이버 타입에 매핑되어
  대부분의 쿼리 코드가 방언과 무관하게 컴파일됨
- 방언 차이 흡수: MySQL 은 UPDATE...RETURNING·partial unique index 미지원 →
  인가코드/WebAuthn challenge 소진, signing key 회전, rate limit upsert 를
  affectedRows 판정·재조회·트랜잭션으로 분기
- drizzle.config 방언별 분기(db:generate / :pg / :mysql), wrangler/.env 예시에
  HYPERDRIVE 바인딩·DB_DIALECT 문서화, README 갱신

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UH64JEZoYNB2j9T8QeatCt
Cloudflare Workers 외에 순수 Node(adapter-node) 환경도 지원하고, PostgreSQL/MySQL
을 Hyperdrive 없이 DATABASE_URL 로 직접 연결할 수 있게 한다.

- BUILD_TARGET(cloudflare|node) 로 어댑터 전환: node 는 @sveltejs/adapter-node 로
  빌드되어 순수 Node 서버로 구동 (platform 바인딩 없음)
- 연결 문자열 해석 우선순위: HYPERDRIVE 바인딩 → platform.env.DATABASE_URL →
  process.env.DATABASE_URL. Workers(Hyperdrive/직결)·Node 모두 지원
- getRuntimeConfig 가 platform.env 부재 시 process.env 로 폴백 (Node 설정 로딩)
- D1 은 Workers 전용 — Node 에서 d1 선택 시 명확한 에러 안내
- .env.example/README 에 BUILD_TARGET·DATABASE_URL·Node 구동법 문서화

검증: cloudflare/d1·node/postgres 빌드 성공(드라이버 DCE 격리 확인),
세 방언 svelte-check 0 errors.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UH64JEZoYNB2j9T8QeatCt
DB_DIALECT 에 sqlite(libSQL) 추가, 스킨 캐시를 R2 외 S3 호환 스토리지로 확장.

DB:
- DB_DIALECT=sqlite → libSQL 드라이버. 로컬 파일(file:) 또는 Turso 연결
  (DATABASE_URL/SQLITE_URL, file: 스킴 없으면 로컬 파일로 간주, 원격은 AUTH_TOKEN)
- 스키마는 D1 과 동일한 schema.sqlite.ts 공유, driver-sqlite.ts 로 정규 DB 타입 매핑
- libSQL 은 batch 지원 → signing key 회전을 d1 과 동일하게 batch 로 처리
- drizzle.config sqlite 분기 + db:generate:sqlite 스크립트

스토리지:
- 스킨 캐시 스토리지 추상화(SkinCacheStore): R2 바인딩 우선, 없으면 S3 호환
  (S3_ENDPOINT/S3_BUCKET/키)로 폴백, 둘 다 없으면 캐시 없이 graceful 동작
- aws4fetch 로 서명 → AWS S3/MinIO/Ceph/R2 S3 endpoint 모두 지원, Workers/Node 공용
- S3_FORCE_PATH_STYLE 로 path-style/virtual-host 선택

검증: d1/sqlite svelte-check 0 errors, node+sqlite 빌드에서 libSQL 만 번들(DCE 확인),
db:generate:sqlite 정상. .env.example/README 문서화.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UH64JEZoYNB2j9T8QeatCt
@mack-erel
mack-erel force-pushed the claude/hyperdrive-multi-db-support-avsgcm branch from 643ebcb to 92a06ca Compare July 1, 2026 15:37
schema.ts → schema.{sqlite,pg,mysql}.ts 분리 시 파일/라인이 바뀌면서
기존 .gitleaksignore 지문(schema.ts:62)이 더 이상 매칭되지 않아 gitleaks 가
"pbkdf2/argon2id hash" 설명 주석을 generic-api-key 로 오탐.

commit SHA 에 의존하는 .gitleaksignore 지문 대신, 재-rebase 에도 안 깨지는
인라인 `gitleaks:allow` 주석으로 3개 스키마 파일 모두 처리. 실제 시크릿이 아니라
credentials.secret 컬럼이 저장하는 해시 형식을 설명하는 문자열임.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mack-erel
mack-erel merged commit d4db189 into main Jul 1, 2026
5 of 6 checks passed
@mack-erel
mack-erel deleted the claude/hyperdrive-multi-db-support-avsgcm branch July 1, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants