Skip to content

[REFACTOR] Tauri 도입#29

Merged
i-meant-to-be merged 6 commits into
developfrom
refactor/#26
Jul 18, 2026
Merged

[REFACTOR] Tauri 도입#29
i-meant-to-be merged 6 commits into
developfrom
refactor/#26

Conversation

@i-meant-to-be

@i-meant-to-be i-meant-to-be commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🚩 연관 이슈

Closes #26
Closes #27
Closes #28

📝 작업 내용

1. 변경 개요

기존 Electron 빌드와 실행 경로를 유지하면서, 같은 React 애플리케이션을 Windows용 Tauri 앱으로도 빌드하고 사용할 수 있도록 기반을 추가했습니다.

  • Electron과 Tauri를 각각 독립적으로 개발·빌드할 수 있는 스크립트와 설정을 구성했습니다.
  • 기존 React의 window.db 계약을 변경하지 않고 Tauri Rust 백엔드와 연결했습니다.
  • Electron과 Tauri가 서로 다른 DB 파일을 사용하도록 데이터 저장 위치를 완전히 분리했습니다.
  • Windows x64 및 ia32용 Electron/Tauri NSIS 설치 파일을 생성할 수 있도록 로컬 빌드와 GitHub Actions를 구성했습니다.
  • 기존 src/** React 구현과 Electron 백엔드의 기능 동작은 변경하지 않았습니다.

2. Electron과 Tauri 빌드 체계 분리

Electron

  • Electron 소스 디렉터리를 electron/에서 src-electron/으로 이동했습니다.
  • 기존 vite.config.mtsvite.config.electron.mts로 변경하고 관련 npm script와 TypeScript 설정의 참조를 함께 수정했습니다.
  • Electron renderer, main, preload의 출력 구조와 기존 IPC/DB 동작은 그대로 유지했습니다.
  • 기존 ia32/x64 통합 및 개별 NSIS 설치 파일 빌드가 계속 동작하는 것을 확인했습니다.

Tauri

  • src-tauri/에 Tauri 2 프로젝트와 Windows 전용 설정을 추가했습니다.
  • 사용자에게 표시되는 제품명과 창 제목은 디베이트 타이머로 설정했습니다.
  • 내부 바이너리 이름은 Electron 산출물과 구분할 수 있도록 Debate Timer (Tauri)로 유지했습니다.
  • 앱 identifier를 com.debatetimer.app.tauri로 분리했습니다.
  • Windows x64와 ia32 MSVC target 및 NSIS installer를 지원합니다.
  • WebView2가 설치되지 않은 환경에서도 설치할 수 있도록 offline installer 방식을 사용합니다.
  • Tauri 생성 산출물은 dist/tauri-renderersrc-tauri/target에 별도로 생성됩니다.

3. Electron/Tauri 데이터 소스 격리

두 앱을 동시에 실행해도 같은 JSON 파일을 조작하지 않도록 저장 경로를 분리했습니다.

Electron
└─ app.getPath('userData')/db.json

Tauri
└─ app.path().app_data_dir()/tauri-db.json
   └─ identifier: com.debatetimer.app.tauri
  • Tauri는 Electron DB를 탐색하거나 복사·마이그레이션하지 않습니다.
  • Tauri command는 프런트엔드에서 파일 경로를 전달받지 않고, Rust에서 계산한 전용 경로만 사용합니다.
  • 따라서 Electron과 Tauri의 생성·수정·삭제 작업은 서로의 데이터에 영향을 주지 않습니다.

4. Rust DB 백엔드 구현

Electron의 TypeScript 백엔드 동작을 다음 Rust 모듈로 나누어 이식했습니다.

model.rs — TypeScript interface에 대응하는 데이터 모델

  • DebateTableData, DebateInfo, TimeBoxInfo 구조체를 정의했습니다.
  • Stance, TimeBoxType enum을 정의하고 기존 JSON 문자열인 PROS, CONS, NEUTRAL, NORMAL, TIME_BASED와 호환되도록 구성했습니다.
  • Rust 필드명은 snake_case를 사용하지만 serde의 camelCase 변환을 통해 기존 JSON key를 그대로 유지합니다.
  • null이 가능한 값은 Option<T>로 표현했습니다. 이는 TypeScript의 T | null 또는 optional 값과 유사합니다.
  • 현재 모델이 알지 못하는 미래 JSON 필드는 #[serde(flatten)] map에 보관합니다. 따라서 데이터를 읽고 다시 저장해도 추가 필드가 사라지지 않습니다.

seed.rs — Electron 초기 데이터 이식

  • src-electron/constants.ts의 초기 토론 2건을 값 단위로 동일하게 옮겼습니다.
  • 최초 DB 생성 시 각 항목에 새로운 UUID v4를 부여합니다.
  • 초기화 시각을 한 번만 계산해 두 항목에 같은 로컬 datetime을 저장합니다.
  • 테스트에서는 UUID와 시각을 제외한 전체 JSON 구조가 Electron 초기 데이터와 같은지 비교합니다.

db.rs — JSON DB와 CRUD 처리

  • DB 최초 생성, JSON 읽기·쓰기, schema 검증, 정렬 및 CRUD를 담당합니다.
  • get, get_all, post, delete, patch의 반환 동작과 없는 ID 처리 방식을 기존 Electron 구현에 맞췄습니다.
  • 잘못된 JSON, 배열이 아닌 JSON, 필수 필드 타입 오류 또는 알 수 없는 enum 값이 발견되면 Tauri DB만 삭제하고 초기 데이터 2건으로 복구합니다.
  • 파일 권한이나 디스크 오류 같은 I/O 문제는 데이터 손상으로 간주하지 않고 호출자에게 오류로 전달합니다.
  • tokio::sync::Mutex로 한 Tauri 프로세스 안의 read-modify-write 작업을 직렬화해 동시 요청에 의한 lost update를 방지합니다.
  • 복수 프로세스 간 file lock은 이번 작업 범위에 포함하지 않았습니다.

commands.rslib.rs — Electron IPC handler에 대응하는 진입점

  • commands.rsdb_get, db_get_all, db_post, db_delete, db_patch는 Electron의 IPC handler와 같은 역할을 합니다.
  • command는 얇은 adapter로 두고 실제 DB 규칙은 테스트 가능한 db.rs에 배치했습니다.
  • 각 command의 Result<T, DbError>는 TypeScript 관점에서 성공 시 resolve되고 실패 시 reject되는 Promise와 유사합니다.
  • lib.rs는 앱 시작 시 Tauri 전용 DB 경로를 계산하고 초기화를 완료한 다음, DbState와 다섯 command를 Tauri에 등록합니다.

5. React와 Rust 연결

  • src-tauri/frontend/db.ts에서 @tauri-apps/api/coreinvoke를 기존 window.db API로 변환합니다.
  • vite.config.tauri.mts가 이 bridge를 기존 React entry보다 먼저 주입합니다.
  • React repository와 component는 Electron/Tauri 실행 환경을 구분할 필요 없이 기존 window.db를 그대로 사용합니다.
  • Electron Vite 설정에는 Tauri bridge를 연결하지 않았으므로 Electron 번들에는 @tauri-apps/api 호출이 포함되지 않습니다.
React repository (`window.db`)
├─ Electron → preload → Electron IPC → Electron db.json
└─ Tauri    → db.ts   → Tauri invoke → Rust → Tauri tauri-db.json

6. 의존성과 품질 설정

  • JavaScript
    • @tauri-apps/cli: Tauri 개발 및 빌드 명령
    • @tauri-apps/api: 프런트엔드에서 Rust command 호출
  • Rust
    • serde, serde_json: 모델 및 JSON 직렬화/역직렬화
    • uuid: UUID v4 생성
    • chrono: 로컬 시각 생성과 정렬
    • tokio: 비동기 파일 I/O와 mutex
    • thiserror: DB 오류 구분
    • tempfile: 격리된 Rust DB 테스트
  • ESLint, Stylelint, Git ignore 대상에 Tauri 생성 디렉터리를 추가했습니다.
  • Tauri TypeScript 검사와 Rust fmt/Clippy를 실행하는 별도 lint script를 추가했습니다.

7. GitHub Actions

기존 build job을 다음 두 job으로 분리했습니다.

  • build-electron
    • 기존 Electron renderer/main/preload 빌드
    • ia32/x64 NSIS 설치 파일 생성 및 업로드
  • build-tauri
    • x64/ia32 matrix 구성
    • 최신 stable Rust와 각 MSVC target 설치
    • React 및 Tauri TypeScript 검사
    • x64 job에서 Rust 백엔드 테스트 1회 실행
    • 아키텍처별 Tauri NSIS 설치 파일 생성 및 업로드

8. 테스트 및 빌드 결과

검증 항목 결과
npm run lint 성공 — 오류 0건
npm run lint:tauri 성공 — TypeScript, rustfmt, Clippy 통과
전체 Vitest 성공 — 10 files, 43 tests passed
Tauri bridge Vitest 성공 — 3 tests passed
Rust unit test 성공 — 10 tests passed
Rust x64 cargo check 성공
Rust i686 cargo check 성공
Electron ia32/x64 NSIS build 성공
Tauri x64 NSIS build 성공
Tauri ia32 NSIS build 성공

Rust 테스트에는 다음 항목이 포함됩니다.

  • 모델의 camelCase, enum, null/optional 및 알 수 없는 필드 round-trip
  • Electron 초기 데이터와 Tauri seed의 동등성
  • 최초 초기화와 중복 seed 방지
  • CRUD 및 없는 ID에 대한 Electron 호환 동작
  • 잘못된 DB schema 복구
  • CRUD 이후에도 알 수 없는 추가 필드 보존
  • 유효한/유효하지 않은 datetime 정렬
  • 동시 쓰기 요청에서 데이터 유실 방지
  • 복구할 수 없는 파일 시스템 오류 전달

🏞️ 스크린샷 (선택)

UI 변경 없이 동일한 React 화면을 Electron과 Tauri에서 사용하므로 별도 스크린샷은 첨부하지 않았습니다.

🗣️ 리뷰 요구사항 (선택)

권장 리뷰 순서

Rust가 익숙하지 않은 경우 다음 순서로 보면 TypeScript/Electron 구조와 비교하기 쉽습니다.

  1. src-tauri/frontend/db.ts
    • React의 window.db 호출이 어떤 Tauri command로 변환되는지 확인합니다.
  2. src-tauri/src/commands.rs
    • Electron IPC handler에 대응하는 다섯 command의 입력과 반환형을 확인합니다.
  3. src-tauri/src/model.rs
    • 기존 TypeScript interface와 JSON 형식이 어떻게 Rust 구조체로 표현되는지 확인합니다.
  4. src-tauri/src/db.rs
    • 실제 초기화, 복구, CRUD와 동시성 규칙을 확인합니다.
  5. src-tauri/src/seed.rs
    • Electron 초기 상수와 동일한 데이터인지 확인합니다.
  6. src-tauri/src/lib.rs
    • 앱 시작 시 경로 계산, state 및 command 등록 흐름을 확인합니다.

중점 확인 요청

  • Electron과 Tauri의 DB 경로가 충분히 명확하게 분리되어 있는지 확인 부탁드립니다.
  • 기존 Electron CRUD의 다소 특이한 edge case도 의도적으로 유지했습니다.
    • 없는 ID를 delete해도 현재 배열을 저장하고 반환합니다.
    • 없는 ID를 patch해도 DB는 바뀌지 않지만 전달받은 항목을 반환합니다.
  • 손상된 Tauri DB는 초기 데이터로 복구하지만, 미정의 추가 필드만 있는 유효한 DB는 초기화하지 않습니다.
  • Mutex는 Tauri 프로세스 내부 요청만 보호하며, 여러 Tauri 프로세스가 같은 파일을 동시에 조작하는 경우는 이번 범위 밖입니다.
  • 사용자에게 표시되는 이름에서는 (Tauri)를 제거했지만 내부 바이너리 이름에는 구분을 위해 유지했습니다.

Summary by CodeRabbit

  • 새 기능

    • Windows용 Tauri 데스크톱 앱 빌드와 NSIS 설치 프로그램을 지원합니다.
    • 토론 데이터를 로컬에 저장하고 불러오며, 추가·수정·삭제할 수 있습니다.
    • 앱 최초 실행 시 메인 및 결선 라운드 예시 데이터가 제공됩니다.
    • 토론 일정과 발언 시간 정보가 안정적으로 저장되고 시간순으로 표시됩니다.
  • 개선 사항

    • Electron과 Tauri 환경에서 각각 안정적인 실행·빌드 구성을 제공합니다.
    • 기존 데이터의 확장 정보도 유지하여 호환성을 강화했습니다.

@i-meant-to-be
i-meant-to-be requested a review from useon July 15, 2026 15:37
@i-meant-to-be i-meant-to-be self-assigned this Jul 15, 2026
@i-meant-to-be i-meant-to-be added the refactor 기능 변경 없이 코드만 바뀌었을 경우 label Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@i-meant-to-be, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a19aa41-2f44-4844-ae76-52647850e602

📥 Commits

Reviewing files that changed from the base of the PR and between b9248a9 and e54faca.

📒 Files selected for processing (1)
  • eslint.config.mjs

Walkthrough

Electron JSON DB 경로를 유지하면서 토론 데이터 모델, Rust 기반 Tauri JSON DB, Tauri 프론트엔드 브리지, Electron preload API, Windows용 Electron·Tauri 빌드 워크플로우를 추가했다.

Changes

Tauri 기반 전환과 DB 통합

Layer / File(s) Summary
데이터 모델과 시드 라운드
src-tauri/Cargo.toml, src-tauri/src/model.rs, src-tauri/src/seed.rs, src-electron/type.ts, src-electron/constants.ts
토론 데이터의 Rust·TypeScript 타입과 JSON 확장 필드 처리를 정의하고 메인·결선 라운드 시드 데이터를 추가했다.
Rust JSON DB CRUD
src-tauri/src/db.rs
Mutex 기반 파일 접근 직렬화, 초기화·복구, datetime 정렬, CRUD, 오류 처리와 테스트를 구현했다.
Tauri 명령과 프론트엔드 브리지
src-tauri/src/commands.rs, src-tauri/src/lib.rs, src-tauri/frontend/*, src-tauri/tauri.conf.json, vite.config.tauri.mts, tsconfig.tauri.json
Tauri 명령과 앱 상태 등록을 구성하고 프론트엔드 db API를 invoke 호출에 연결했다.
Electron DB API와 런타임 경로
src-electron/api.ts, src-electron/api.test.ts, src-electron/preload.ts, vite.config.electron.mts, src/renderer.d.ts
Electron 파일 DB CRUD, preload 브리지, 라운드 상수 및 관련 테스트를 추가하고 소스 경로를 src-electron으로 갱신했다.
Tauri 스크립트와 Windows 빌드
package.json, .github/workflows/build-windows.yml, *.ignore, eslint.config.mjs
Tauri 실행·빌드 스크립트와 x64·ia32 NSIS 산출물 빌드를 추가하고 생성 디렉터리 제외 규칙을 확장했다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: useon, jaeml06

Poem

당근을 문 토끼가 달려와요
Rust DB에 씨앗을 심어요
Electron도 Tauri도 길을 찾아
Windows 빌드가 깡충 뛰어요
토론 타이머, 이제 출발해요!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.61% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 Tauri 도입이라는 핵심 변경을 직접적으로 요약해 관련성이 높습니다.
Linked Issues check ✅ Passed Tauri 도입, Rust 백엔드 변환, 빌드 기반 준비라는 직접 이슈의 핵심 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 변경 사항은 Electron/Tauri 분리, Rust 백엔드, CI·설정 보강 등 목표 범위 안에 있습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#26

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
src-electron/api.test.ts (1)

110-113: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

주석을 훅(hook)의 동작과 일치하도록 수정하세요.

주석에는 "after each test"라고 되어 있으나, 실제로는 모든 테스트가 끝난 후 한 번만 실행되는 afterAll 훅을 사용하고 있습니다. 혼동을 피하기 위해 주석을 수정하는 것을 권장합니다.

📝 제안하는 수정안
 afterAll(async () => {
-  // Delete all files and temp directory after each test
+  // Delete all files and temp directory after all tests
   await fs.rm(TEST_DIR, { recursive: true, force: true });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-electron/api.test.ts` around lines 110 - 113, Update the comment above
the afterAll hook to state that files and the temporary directory are deleted
after all tests complete, matching the one-time cleanup performed by afterAll.
src-electron/preload.ts (1)

2-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

타입 전용으로 가져오기(type import)를 사용하세요.

이 파일에서 DebateTableDataUUID는 타입으로만 사용됩니다. import type을 명시적으로 사용하면 빌드 시점에 완전히 지워지므로, 프리로드(preload) 환경에서 발생할 수 있는 불필요한 모듈 해석 문제를 예방할 수 있습니다.

♻️ 제안하는 수정안
-import { DebateTableData } from './type';
-import { UUID } from 'crypto';
+import type { DebateTableData } from './type';
+import type { UUID } from 'crypto';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-electron/preload.ts` around lines 2 - 3, Update the imports of
DebateTableData and UUID in the preload module to use type-only imports,
ensuring both type references are removed from the runtime bundle while
preserving their existing type usage.
.github/workflows/build-windows.yml (1)

94-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

추가한 Rust lint를 CI에서도 실행하세요.

현재 테스트와 빌드는 cargo fmt --checkclippy -D warnings를 보장하지 않습니다. x64 작업에서 npm run lint:tauri:rust를 한 번 실행하면 됩니다.

수정 예시
       - name: Typecheck Tauri configuration
         run: npm run lint:tauri:tsc

+      - name: Lint Tauri Rust backend
+        if: matrix.architecture == 'x64'
+        run: npm run lint:tauri:rust
+
       - name: Test Tauri Rust backend
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-windows.yml around lines 94 - 99, Add an x64-only CI
step in the workflow near the existing Tauri checks to run npm run
lint:tauri:rust. Ensure the Windows job executes this Rust lint command so cargo
fmt --check and clippy -D warnings are validated alongside the existing Rust
tests.
src-tauri/tauri.conf.json (2)

26-28: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

보안 강화를 위해 Content Security Policy(CSP) 활성화 권장

"csp": null로 설정하여 Tauri가 제공하는 기본 CSP(콘텐츠 보안 정책) 주입을 비활성화했습니다. index.html 내부에 강력한 <meta> 태그 기반 CSP가 선언되어 있지 않다면, XSS(크로스 사이트 스크립팅) 취약점이 발생했을 때 악의적인 스크립트 실행이나 로컬 데이터 변조를 막아줄 방어막이 얇아집니다.
앱의 전반적인 보안(Defense-in-depth)을 위해 가급적 엄격한 CSP를 설정하는 것을 권장합니다.

🛡️ CSP 설정 예시
     "security": {
-      "csp": null
+      "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost"
     }

(앱에서 외부 API를 호출하거나 외부 리소스를 사용한다면 해당 도메인을 connect-srcimg-src 등에 추가해야 합니다)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tauri.conf.json` around lines 26 - 28, Update the security
configuration to enable a strict Content Security Policy instead of setting csp
to null. Define the policy using the app’s required resource and API sources,
preserving necessary functionality while defaulting to restrictive directives.

26-28: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

보안 강화를 위해 Content Security Policy(CSP) 활성화 권장

"csp": null로 설정하여 Tauri가 제공하는 기본 CSP 주입을 비활성화했습니다. index.html 내부에서 강력한 <meta> 태그 기반 CSP를 이미 제공하고 있지 않다면, XSS(크로스 사이트 스크립팅) 공격 시 방어막이 얇아져 로컬 DB 변조 등의 위험이 발생할 수 있습니다.
앱의 보안을 위해 가급적 엄격한 CSP(예: "default-src 'self'; script-src 'self' 'unsafe-inline'")를 설정하는 것을 권장합니다.

🛡️ CSP 설정 예시
     "security": {
-      "csp": null
+      "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost"
     }

(앱에서 외부 API를 호출하거나 외부 이미지를 사용한다면 해당 도메인을 connect-src, img-src 등에 추가해야 합니다)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tauri.conf.json` around lines 26 - 28, Update the Tauri security
configuration around the csp key to enable a strict Content Security Policy
instead of setting csp to null. Use an appropriate policy for the app’s actual
script, connection, and image sources, preserving only the required trusted
origins and avoiding unnecessary allowances.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-windows.yml:
- Around line 49-64: Update the build-tauri job to declare contents read-only
permissions, and configure its actions/checkout@v4 step with persist-credentials
disabled. Keep the existing matrix and build steps unchanged.

In `@package.json`:
- Line 18: Remove the hardcoded --project-token value from the chromatic script
in package.json and configure Chromatic to receive the token through the CI
secret/environment-variable mechanism instead. Revoke the exposed token and
issue a replacement outside the repository.

In `@src-electron/api.ts`:
- Around line 11-16: Update the readDb function to catch fs.readFile errors and
return an empty array when the database file is missing (ENOENT), while
preserving the existing JSON parsing and array validation behavior for existing
files.

In `@src-tauri/src/db.rs`:
- Around line 123-125: Update the Invalid branch in the database read/recovery
flow and replace_with_seed_locked so database writes use a temporary file in the
same directory followed by an atomic replacement. When parsing fails, preserve
the original file by backing it up and return the read error (or invoke an
explicit recovery procedure) instead of deleting it and replacing all user data
with the seed database.

In `@vite.config.tauri.mts`:
- Around line 6-23: tauriDatabaseBridge의 transformIndexHtml 핸들러에서 db.ts의 고정 경로를
제거하고 Vite의 설정된 base를 반영하는 경로로 생성하세요. 프로덕션에서 base가 ./인 경우에도 주입된 script의 src가 올바른
상대 경로가 되도록 하며, 개발 환경의 동작은 유지하세요.

---

Nitpick comments:
In @.github/workflows/build-windows.yml:
- Around line 94-99: Add an x64-only CI step in the workflow near the existing
Tauri checks to run npm run lint:tauri:rust. Ensure the Windows job executes
this Rust lint command so cargo fmt --check and clippy -D warnings are validated
alongside the existing Rust tests.

In `@src-electron/api.test.ts`:
- Around line 110-113: Update the comment above the afterAll hook to state that
files and the temporary directory are deleted after all tests complete, matching
the one-time cleanup performed by afterAll.

In `@src-electron/preload.ts`:
- Around line 2-3: Update the imports of DebateTableData and UUID in the preload
module to use type-only imports, ensuring both type references are removed from
the runtime bundle while preserving their existing type usage.

In `@src-tauri/tauri.conf.json`:
- Around line 26-28: Update the security configuration to enable a strict
Content Security Policy instead of setting csp to null. Define the policy using
the app’s required resource and API sources, preserving necessary functionality
while defaulting to restrictive directives.
- Around line 26-28: Update the Tauri security configuration around the csp key
to enable a strict Content Security Policy instead of setting csp to null. Use
an appropriate policy for the app’s actual script, connection, and image
sources, preserving only the required trusted origins and avoiding unnecessary
allowances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 953c9fc0-a873-4f10-ac95-668f0d59ad30

📥 Commits

Reviewing files that changed from the base of the PR and between 9e932c7 and b9248a9.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .github/workflows/build-windows.yml
  • .gitignore
  • .stylelintignore
  • eslint.config.mjs
  • package.json
  • src-electron/api.test.ts
  • src-electron/api.ts
  • src-electron/constants.ts
  • src-electron/main.ts
  • src-electron/preload.ts
  • src-electron/type.ts
  • src-tauri/Cargo.toml
  • src-tauri/build.rs
  • src-tauri/capabilities/default.json
  • src-tauri/frontend/db.test.ts
  • src-tauri/frontend/db.ts
  • src-tauri/src/commands.rs
  • src-tauri/src/db.rs
  • src-tauri/src/lib.rs
  • src-tauri/src/main.rs
  • src-tauri/src/model.rs
  • src-tauri/src/seed.rs
  • src-tauri/tauri.conf.json
  • src/renderer.d.ts
  • tsconfig.node.json
  • tsconfig.tauri.json
  • vite.config.electron.mts
  • vite.config.tauri.mts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 5

🧹 Nitpick comments (5)
src-electron/api.test.ts (1)

110-113: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

주석을 훅(hook)의 동작과 일치하도록 수정하세요.

주석에는 "after each test"라고 되어 있으나, 실제로는 모든 테스트가 끝난 후 한 번만 실행되는 afterAll 훅을 사용하고 있습니다. 혼동을 피하기 위해 주석을 수정하는 것을 권장합니다.

📝 제안하는 수정안
 afterAll(async () => {
-  // Delete all files and temp directory after each test
+  // Delete all files and temp directory after all tests
   await fs.rm(TEST_DIR, { recursive: true, force: true });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-electron/api.test.ts` around lines 110 - 113, Update the comment above
the afterAll hook to state that files and the temporary directory are deleted
after all tests complete, matching the one-time cleanup performed by afterAll.
src-electron/preload.ts (1)

2-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

타입 전용으로 가져오기(type import)를 사용하세요.

이 파일에서 DebateTableDataUUID는 타입으로만 사용됩니다. import type을 명시적으로 사용하면 빌드 시점에 완전히 지워지므로, 프리로드(preload) 환경에서 발생할 수 있는 불필요한 모듈 해석 문제를 예방할 수 있습니다.

♻️ 제안하는 수정안
-import { DebateTableData } from './type';
-import { UUID } from 'crypto';
+import type { DebateTableData } from './type';
+import type { UUID } from 'crypto';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-electron/preload.ts` around lines 2 - 3, Update the imports of
DebateTableData and UUID in the preload module to use type-only imports,
ensuring both type references are removed from the runtime bundle while
preserving their existing type usage.
.github/workflows/build-windows.yml (1)

94-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

추가한 Rust lint를 CI에서도 실행하세요.

현재 테스트와 빌드는 cargo fmt --checkclippy -D warnings를 보장하지 않습니다. x64 작업에서 npm run lint:tauri:rust를 한 번 실행하면 됩니다.

수정 예시
       - name: Typecheck Tauri configuration
         run: npm run lint:tauri:tsc

+      - name: Lint Tauri Rust backend
+        if: matrix.architecture == 'x64'
+        run: npm run lint:tauri:rust
+
       - name: Test Tauri Rust backend
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-windows.yml around lines 94 - 99, Add an x64-only CI
step in the workflow near the existing Tauri checks to run npm run
lint:tauri:rust. Ensure the Windows job executes this Rust lint command so cargo
fmt --check and clippy -D warnings are validated alongside the existing Rust
tests.
src-tauri/tauri.conf.json (2)

26-28: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

보안 강화를 위해 Content Security Policy(CSP) 활성화 권장

"csp": null로 설정하여 Tauri가 제공하는 기본 CSP(콘텐츠 보안 정책) 주입을 비활성화했습니다. index.html 내부에 강력한 <meta> 태그 기반 CSP가 선언되어 있지 않다면, XSS(크로스 사이트 스크립팅) 취약점이 발생했을 때 악의적인 스크립트 실행이나 로컬 데이터 변조를 막아줄 방어막이 얇아집니다.
앱의 전반적인 보안(Defense-in-depth)을 위해 가급적 엄격한 CSP를 설정하는 것을 권장합니다.

🛡️ CSP 설정 예시
     "security": {
-      "csp": null
+      "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost"
     }

(앱에서 외부 API를 호출하거나 외부 리소스를 사용한다면 해당 도메인을 connect-srcimg-src 등에 추가해야 합니다)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tauri.conf.json` around lines 26 - 28, Update the security
configuration to enable a strict Content Security Policy instead of setting csp
to null. Define the policy using the app’s required resource and API sources,
preserving necessary functionality while defaulting to restrictive directives.

26-28: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

보안 강화를 위해 Content Security Policy(CSP) 활성화 권장

"csp": null로 설정하여 Tauri가 제공하는 기본 CSP 주입을 비활성화했습니다. index.html 내부에서 강력한 <meta> 태그 기반 CSP를 이미 제공하고 있지 않다면, XSS(크로스 사이트 스크립팅) 공격 시 방어막이 얇아져 로컬 DB 변조 등의 위험이 발생할 수 있습니다.
앱의 보안을 위해 가급적 엄격한 CSP(예: "default-src 'self'; script-src 'self' 'unsafe-inline'")를 설정하는 것을 권장합니다.

🛡️ CSP 설정 예시
     "security": {
-      "csp": null
+      "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost"
     }

(앱에서 외부 API를 호출하거나 외부 이미지를 사용한다면 해당 도메인을 connect-src, img-src 등에 추가해야 합니다)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tauri.conf.json` around lines 26 - 28, Update the Tauri security
configuration around the csp key to enable a strict Content Security Policy
instead of setting csp to null. Use an appropriate policy for the app’s actual
script, connection, and image sources, preserving only the required trusted
origins and avoiding unnecessary allowances.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-windows.yml:
- Around line 49-64: Update the build-tauri job to declare contents read-only
permissions, and configure its actions/checkout@v4 step with persist-credentials
disabled. Keep the existing matrix and build steps unchanged.

In `@package.json`:
- Line 18: Remove the hardcoded --project-token value from the chromatic script
in package.json and configure Chromatic to receive the token through the CI
secret/environment-variable mechanism instead. Revoke the exposed token and
issue a replacement outside the repository.

In `@src-electron/api.ts`:
- Around line 11-16: Update the readDb function to catch fs.readFile errors and
return an empty array when the database file is missing (ENOENT), while
preserving the existing JSON parsing and array validation behavior for existing
files.

In `@src-tauri/src/db.rs`:
- Around line 123-125: Update the Invalid branch in the database read/recovery
flow and replace_with_seed_locked so database writes use a temporary file in the
same directory followed by an atomic replacement. When parsing fails, preserve
the original file by backing it up and return the read error (or invoke an
explicit recovery procedure) instead of deleting it and replacing all user data
with the seed database.

In `@vite.config.tauri.mts`:
- Around line 6-23: tauriDatabaseBridge의 transformIndexHtml 핸들러에서 db.ts의 고정 경로를
제거하고 Vite의 설정된 base를 반영하는 경로로 생성하세요. 프로덕션에서 base가 ./인 경우에도 주입된 script의 src가 올바른
상대 경로가 되도록 하며, 개발 환경의 동작은 유지하세요.

---

Nitpick comments:
In @.github/workflows/build-windows.yml:
- Around line 94-99: Add an x64-only CI step in the workflow near the existing
Tauri checks to run npm run lint:tauri:rust. Ensure the Windows job executes
this Rust lint command so cargo fmt --check and clippy -D warnings are validated
alongside the existing Rust tests.

In `@src-electron/api.test.ts`:
- Around line 110-113: Update the comment above the afterAll hook to state that
files and the temporary directory are deleted after all tests complete, matching
the one-time cleanup performed by afterAll.

In `@src-electron/preload.ts`:
- Around line 2-3: Update the imports of DebateTableData and UUID in the preload
module to use type-only imports, ensuring both type references are removed from
the runtime bundle while preserving their existing type usage.

In `@src-tauri/tauri.conf.json`:
- Around line 26-28: Update the security configuration to enable a strict
Content Security Policy instead of setting csp to null. Define the policy using
the app’s required resource and API sources, preserving necessary functionality
while defaulting to restrictive directives.
- Around line 26-28: Update the Tauri security configuration around the csp key
to enable a strict Content Security Policy instead of setting csp to null. Use
an appropriate policy for the app’s actual script, connection, and image
sources, preserving only the required trusted origins and avoiding unnecessary
allowances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 953c9fc0-a873-4f10-ac95-668f0d59ad30

📥 Commits

Reviewing files that changed from the base of the PR and between 9e932c7 and b9248a9.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .github/workflows/build-windows.yml
  • .gitignore
  • .stylelintignore
  • eslint.config.mjs
  • package.json
  • src-electron/api.test.ts
  • src-electron/api.ts
  • src-electron/constants.ts
  • src-electron/main.ts
  • src-electron/preload.ts
  • src-electron/type.ts
  • src-tauri/Cargo.toml
  • src-tauri/build.rs
  • src-tauri/capabilities/default.json
  • src-tauri/frontend/db.test.ts
  • src-tauri/frontend/db.ts
  • src-tauri/src/commands.rs
  • src-tauri/src/db.rs
  • src-tauri/src/lib.rs
  • src-tauri/src/main.rs
  • src-tauri/src/model.rs
  • src-tauri/src/seed.rs
  • src-tauri/tauri.conf.json
  • src/renderer.d.ts
  • tsconfig.node.json
  • tsconfig.tauri.json
  • vite.config.electron.mts
  • vite.config.tauri.mts
🛑 Comments failed to post (5)
.github/workflows/build-windows.yml (1)

49-64: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- .github/workflows/build-windows.yml (outline) ---'
ast-grep outline .github/workflows/build-windows.yml --view expanded || true

printf '\n%s\n' '--- relevant lines ---'
nl -ba .github/workflows/build-windows.yml | sed -n '1,140p'

printf '\n%s\n' '--- search for permissions / persist-credentials in workflows ---'
rg -n "permissions:|persist-credentials|actions/checkout@v4" .github/workflows -S || true

Repository: debate-timer/debate-timer-fe-win

Length of output: 338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- .github/workflows/build-windows.yml ---'
cat -n .github/workflows/build-windows.yml | sed -n '1,180p'

printf '\n%s\n' '--- workflow-level permission/checkout search ---'
rg -n "^(permissions:|\\s+persist-credentials:|\\s+uses: actions/checkout@v4)" .github/workflows -S || true

Repository: debate-timer/debate-timer-fe-win

Length of output: 4307


build-tauri에 최소 권한을 명시하고 checkout 자격 증명을 남기지 마세요.
permissions: contents: read를 추가하고 actions/checkoutpersist-credentials: false를 설정하면, 빌드 중 불필요한 쓰기 권한과 토큰 잔존을 줄일 수 있습니다.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 63-64: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 49-110: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-windows.yml around lines 49 - 64, Update the
build-tauri job to declare contents read-only permissions, and configure its
actions/checkout@v4 step with persist-credentials disabled. Keep the existing
matrix and build steps unchanged.

Source: Linters/SAST tools

package.json (1)

18-18: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant package.json section with line numbers
sed -n '1,80p' package.json | nl -ba

# Locate any other Chromatic references in the repository
rg -n "chromatic|chpt_[A-Za-z0-9]+" .

Repository: debate-timer/debate-timer-fe-win

Length of output: 210


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== package.json ==="
cat -n package.json | sed -n '1,80p'

echo
echo "=== Chromatic references ==="
rg -n "chromatic|chpt_[A-Za-z0-9]+" . || true

Repository: debate-timer/debate-timer-fe-win

Length of output: 5204


Chromatic 토큰을 제거하고 교체하세요. package.json:18--project-token 하드코딩은 저장소 접근자에게 노출됩니다. 스크립트에서 토큰을 빼고 CI secret/환경변수로 주입한 뒤, 현재 토큰은 폐기·재발급하세요.

🧰 Tools
🪛 Betterleaks (1.6.1)

[high] 18-18: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 18, Remove the hardcoded --project-token value from the
chromatic script in package.json and configure Chromatic to receive the token
through the CI secret/environment-variable mechanism instead. Revoke the exposed
token and issue a replacement outside the repository.

Source: Linters/SAST tools

src-electron/api.ts (1)

11-16: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

초기 읽기 시 데이터베이스 파일이 없는 경우를 처리하세요.

앱의 첫 실행 등 데이터베이스 파일이 아직 생성되지 않은 상태에서 fs.readFile이 호출되면 ENOENT 에러가 발생하여 앱 초기화나 postItem 등의 작업이 실패하게 됩니다. 에러를 catch로 잡아서 파일이 존재하지 않는 경우 빈 배열을 반환하도록 예외 처리를 추가하는 것이 좋습니다.

🛠️ 제안하는 수정안
 async function readDb(dbPath: string) {
-  const data = await fs.readFile(dbPath, 'utf-8');
-  const parsedData = JSON.parse(data);
-  return Array.isArray(parsedData) ? parsedData : [];
+  try {
+    const data = await fs.readFile(dbPath, 'utf-8');
+    const parsedData = JSON.parse(data);
+    return Array.isArray(parsedData) ? parsedData : [];
+  } catch (error: any) {
+    if (error.code === 'ENOENT') {
+      return [];
+    }
+    throw error;
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

// Read database (helper function for API requests)
async function readDb(dbPath: string) {
  try {
    const data = await fs.readFile(dbPath, 'utf-8');
    const parsedData = JSON.parse(data);
    return Array.isArray(parsedData) ? parsedData : [];
  } catch (error: any) {
    if (error.code === 'ENOENT') {
      return [];
    }
    throw error;
  }
}
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 12-12: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFile(dbPath, 'utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-electron/api.ts` around lines 11 - 16, Update the readDb function to
catch fs.readFile errors and return an empty array when the database file is
missing (ENOENT), while preserving the existing JSON parsing and array
validation behavior for existing files.
src-tauri/src/db.rs (1)

123-125: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

손상된 JSON 하나로 전체 사용자 DB를 초기화하지 마세요.

현재 파일을 직접 덮어쓰므로 쓰기 중 종료 시 부분 JSON이 남을 수 있고, 다음 읽기에서는 해당 파일을 삭제한 뒤 seed로 교체합니다. 단일 레코드의 스키마 오류도 같은 방식으로 모든 토론 데이터를 영구 삭제합니다.

같은 디렉터리의 임시 파일에 기록한 뒤 원자적으로 교체하고, 파싱 실패 파일은 삭제하지 말고 백업한 후 오류를 반환하거나 명시적인 복구 절차를 제공해 주세요.

Also applies to: 143-145

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/db.rs` around lines 123 - 125, Update the Invalid branch in the
database read/recovery flow and replace_with_seed_locked so database writes use
a temporary file in the same directory followed by an atomic replacement. When
parsing fails, preserve the original file by backing it up and return the read
error (or invoke an explicit recovery procedure) instead of deleting it and
replacing all user data with the seed database.
vite.config.tauri.mts (1)

6-23: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Vite 빌드를 수행하고 index.html의 변환 결과를 확인합니다.
npm run tauri:frontend:build || npx vite build -c vite.config.tauri.mts
cat dist/tauri-renderer/index.html | grep db.ts || echo "db.ts가 별도 파일로 분리되지 않았거나 번들링 후 해시된 파일명으로 변경되었는지 확인해야 합니다."

Repository: debate-timer/debate-timer-fe-win

Length of output: 15588


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## vite.config.tauri.mts\n'
if [ -f vite.config.tauri.mts ]; then
  cat -n vite.config.tauri.mts
else
  echo 'missing'
fi

printf '\n## index.html / related html files\n'
git ls-files '*.html' | sed -n '1,20p'
for f in $(git ls-files '*.html'); do
  printf '\n### %s\n' "$f"
  cat -n "$f"
done

printf '\n## src-tauri/frontend/db.ts and references\n'
git ls-files | rg '^src-tauri/frontend/db\.ts$|^src-tauri/frontend/|db\.ts$|tauri-database-bridge|transformIndexHtml|base:' -n || true

printf '\n## any imports/references to /src-tauri/frontend/db.ts\n'
rg -n --hidden --glob '!node_modules' '/src-tauri/frontend/db\.ts|src-tauri/frontend/db\.ts|db\.ts' .

Repository: debate-timer/debate-timer-fe-win

Length of output: 2789


🌐 Web query:

Vite transformIndexHtml injected script tag absolute src base './' build rewrite module script entry handling

💡 Result:

In Vite, the base path configuration ('base: "./"') is primarily intended for production builds to generate relative asset paths, making the deployment host-agnostic [1][2]. However, this behavior often conflicts with manual script injection via the transformIndexHtml hook, which may produce absolute paths that break in sub-path deployments [3][4]. Key Technical Considerations: 1. Base Configuration (./): Setting base to './' in your vite.config.ts directs Vite to use relative paths for built assets [1]. During the build process, Vite automatically rewrites standard <script> tags in index.html to respect this relative base [1]. 2. transformIndexHtml Injection: When you manually inject a <script> tag via the transformIndexHtml hook, Vite does not automatically rewrite the src attribute of your custom tag during the build [5][6]. It treats your injected tag as literal HTML and injects it as-is [4]. 3. Handling Entry Points: To ensure your injected scripts work in both development (where absolute paths like /src/main.js are typically required by the dev server) and production (where relative paths are required), you must handle the logic inside the hook based on the command [4]: Implementation Pattern: You can check viteConfig.command within your plugin to conditionally set the path [4]. // Example Logic transformIndexHtml(html, { bundle }) { const isBuild = process.env.NODE_ENV === 'production'; // Or check viteConfig.command const src = isBuild? './my-script.js': '/my-script.js'; return [ { tag: 'script', attrs: { type: 'module', src }, injectTo: 'body', }, ]; } 4. Ordering: Always ensure your transformIndexHtml hook uses order: 'pre' if you need the script to be processed by Vite's pipeline, or 'post' if you want it to run after Vite has already processed the HTML [7][5][8]. For script injection, 'pre' or 'post' depends on whether you want the injected script to be subject to further transformations (like asset hashing or minification) [7]. If your injected script needs to reference hashed assets generated by Vite, you should look up the resulting filename in the bundle object provided to the transformIndexHtml hook rather than hardcoding paths [4].

Citations:


🌐 Web query:

Vite transformIndexHtml injected module script src build entry relative base rewrite official docs

💡 Result:

Vite does not provide a native, direct configuration option within the transformIndexHtml hook to automatically rewrite or force-inject relative paths for build entry scripts [1][2]. When using transformIndexHtml, keep the following technical considerations in mind: 1. Handling of Build Entry Points: Vite processes index.html entry points during the build to resolve assets, apply hashing, and update paths based on the base configuration [3][4]. If you inject a script tag manually via transformIndexHtml, Vite might not automatically process the src attribute if the hook logic does not account for the build pipeline or if the injection happens after standard path resolution [5][6]. 2. Injection Order: To ensure your injected tags interact correctly with the build process, consider using the order property in your plugin hook (e.g., order: 'pre') [5]. This ensures your transformation occurs before other plugins or internal Vite HTML processing [7]. 3. Base URL and Relative Paths: Vite typically handles absolute path rewriting based on the base configuration [3][4]. If you require relative paths (like./assets/...), you may need to manually compute the path relative to the current HTML file's location within your plugin's transformIndexHtml implementation, as Vite's internal processors prioritize configured base paths [3][8][4]. 4. Plugin Strategy: If you need to modify script tags injected by Vite or dynamically inject your own, a common pattern is to return an array of tags from the transformIndexHtml hook [1][5]. For complex manipulations (like rewriting paths to be relative), many developers use the hook to perform a string replacement or DOM-like transformation on the HTML content [9][6]. Note that if you are attempting to modify existing tags, you must ensure your hook executes at the appropriate stage (pre or post) relative to Vite's internal HTML plugins [7][6]. For further implementation, consult the official Vite Plugin API documentation regarding the IndexHtmlTransformHook interface, which allows for either returning a transformed HTML string or an array of tag objects for injection [1].

Citations:


🌐 Web query:

site:vite.dev transformIndexHtml injected script tag rewritten by build base config src attribute official

💡 Result:

When using the Vite transformIndexHtml hook to inject a script tag, Vite does not automatically rewrite the src attribute of manually injected tags to respect the build.base configuration. You are responsible for ensuring the injected path accounts for the base public path [1][2]. To correctly handle the base path in your injected script: 1. Retrieve the current base configuration from the Vite config object. The transformIndexHtml hook provides access to the server or bundle, but the base path is generally available via the resolved configuration. 2. Manually prepend the base path to your script src. Example implementation: import { defineConfig } from 'vite'; export default defineConfig({ plugins: [ { name: 'inject-script-with-base', configResolved(config) { this.base = config.base; }, transformIndexHtml { return [ { tag: 'script', attrs: { src: ${this.base}path/to/your/script.js, type: 'module' }, injectTo: 'head' } ]; } } ] }); If you are injecting a script that you want Vite to process (e.g., resolve as a module, add hashes, or apply base path rewriting automatically), you should use the tag injection mechanism provided by transformIndexHtml returning an array of HtmlTagDescriptor objects [3]. However, Vite's automatic base path rewriting primarily applies to static references in your source index.html file during the build process, not necessarily to dynamic strings returned by plugin hooks unless Vite explicitly processes those specific attributes [1][2]. To ensure reliability, manually prefixing with the resolved base path is the recommended official approach [1].

Citations:


/src-tauri/frontend/db.ts를 base-aware 경로로 바꾸세요

transformIndexHtml로 주입한 태그는 base: './'를 자동 반영하지 않아서, 프로덕션 빌드에 /src-tauri/frontend/db.ts가 그대로 남을 수 있습니다. 이 경우 Tauri 배포판에서 모듈을 찾지 못합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vite.config.tauri.mts` around lines 6 - 23, tauriDatabaseBridge의
transformIndexHtml 핸들러에서 db.ts의 고정 경로를 제거하고 Vite의 설정된 base를 반영하는 경로로 생성하세요.
프로덕션에서 base가 ./인 경우에도 주입된 script의 src가 올바른 상대 경로가 되도록 하며, 개발 환경의 동작은 유지하세요.

@i-meant-to-be
i-meant-to-be merged commit 23af800 into develop Jul 18, 2026
5 checks passed
@i-meant-to-be
i-meant-to-be deleted the refactor/#26 branch July 18, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor 기능 변경 없이 코드만 바뀌었을 경우

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] BE 코드 Rust로 변환 [REFACTOR] Tauri 빌드 기반 준비 [REFACTOR] Tauri 도입

1 participant