Repository navigation
[feat] Google Drive 녹음 가져오기와 전사 결과 Drive 동기화 - #13
Merged
Merged
Conversation
…in the host
Why: galpi#12. Users keep meeting recordings in Google Drive and want the
transcripts back there without moving files by hand. The host now connects
a Drive account with the drive.file scope, imports one recording picked in
the system browser's desktop Picker, and uploads the meeting's results into
a Galpi folder per meeting.
- domain/drive.rs: MeetingKey (`drive:<fileId>` or FNV-1a of the canonical
source path, so a re-transcription into `{stem} 2` syncs to the same
folder), the stateless conflict rule `decide` over appProperties
galpiSha256 vs Drive sha256Checksum, file-id and token value objects.
- application/drive.rs: DriveAccounts behind three new ports
(DriveAuthPort, DriveFilesPort, DriveSessionStore); connect/disconnect
under a store lock, token renewal near expiry, invalid_grant is the only
failure that forgets the connection, gateway 401 signs the app out.
Picker tokens are stored only while the same account is still connected.
- AppAccessGate gains bearer()/expire(): the auth-gateway session pays for
POST /drive/native/token, which holds the OAuth client secret; the source
carries only the desktop client ID.
- adapters/outbound/drive: consent over the shared browser_sign_in
loopback/PKCE, gateway-brokered token exchange, Drive v3 REST (multipart
upload, streamed download into cache/drive-imports, cleaned on failure,
cancel and startup).
- tauri.rs/composition.rs: 7 commands (35 total); settings and the secret
store keep the Drive session (Windows entry
com.m16khb.galpi:drive-session); opener allows drive.google.com.
Tested: cargo test --manifest-path src-tauri/Cargo.toml --all-targets (295
passed, 1 ignored); cargo clippy --all-targets -- -D warnings; cargo fmt
--check; live smoke against real Google, auth-gateway and Drive (connect,
Picker import, upload, unchanged, updated, conflict, overwrite, minutes,
disconnect) recorded in .issueops/evidence/task-12-drive-smoke.md
Not-tested: memory during a 50MB+ download; the full flow inside the app
window (no engine/models on the test machine)
Why: galpi#12. The host's Drive commands need a surface: a way to connect, a way to bring a recording in from Drive, and a visible result of each meeting's upload, all following DESIGN.md (SEED tokens only, status as color plus text, no progress percentages that the download cannot back). - drive-machine.ts: pure reducer for connection, consent wait, and sync state; drive-controller.ts drives it and follows AUTH_REQUIRED back to the login screen; a Drive failure after the user's own disconnect does not bring the onboarding card back. - Onboarding card (Drive 연결 / 나중에 / cancel), top-bar Drive chip (truncates a long address, full one in its title), settings section, and the sync row with per-file lines, Drive 폴더 열기, and an explicit Drive 버전 덮어쓰기 on a conflict. - Drive에서 가져오기 runs as a job on the progress card with 작업 취소; a consent declined or Picker closed in the browser shows as cancelled. begin() sets the job kind before rendering so the card title follows the new job. Audio from Drive carries driveSourceId into the transcription request; recording or picking a local file replaces it. - Focus moves to the control that replaces a hidden Drive button (settings when start actions are disabled); empty status lines stay live regions. - tauri-backend.ts: strict Zod schemas so no Drive token reaches the window. Tested: bun run check; bun test (233 pass); Chromium via Vite with a fake Tauri IPC (onboarding, connect wait, chip, import card, sync conflict, settings; 1024px long-address layout; keyboard focus handoff); combined web QA (aside-web-qa) with no functional defect Not-tested: the window inside the real app (no engine/models on the test machine); prefers-reduced-motion toggled at runtime (no new animation)
Why: galpi#12. Users need to know what Drive access Galpi asks for and what lands in their Drive; agents need the new ports, commands, and adapters on the architecture map. - README.md / README.en.md: Drive connection, import, sync, conflicts, and the drive.file scope. - INSTALL.md: Drive sign-in is handed back to the user like the other sign-ins. - docs/ARCHITECTURE.md, AGENTS.md, adapters/outbound/AGENTS.md: 35 IPC commands, 18 ports, the Drive use cases and adapters, and the auth-gateway token exchange. Tested: Not applicable (documentation); bun run check passes Not-tested: n/a
Why: the IssueOps cycle for galpi#12 publishes its contract and evidence with the change: the approved plan and its review, the gate ledger, the verification report (including verify-stage review and QA fixes), and the live Drive smoke result. The decisions and pitfalls found on the way are recorded where the next change will look. - ADR: Drive tokens exchanged by auth-gateway; stateless sync through appProperties and sha256Checksum. - Cautions: set the job kind before rendering the job card; gate CHECKs with secret-like arguments are denied, and secret scans must include untracked files and match the real value shape; the desktop Picker consent's transient Google 500 clears on reload. - architecture/testing overviews: 18 ports, 35 commands, Drive adapters, Drive manual checks and the fake-server vs live smoke boundary. Tested: issueops gates check --write (12/12) Not-tested: n/a (records)
13 tasks
Why: the completion record points at this report; it now names the draft PR it was published as and what stays out of the cycle (merge, deploy, cleanup). Tested: issueops remote verify-artifact (PR #13, base main, enhancement, m16khb) Not-tested: n/a (record)
m16khb
marked this pull request as ready for review
October 11, 2026 03:07
Why: PR #13's rust (windows-latest) job failed downloaded_names_are_sanitized_and_keep_the_extension: local_name parsed the Drive file name with std::path::Path, and Windows read "a:" in "a:b?.WAV" as a drive prefix and dropped it ("b.WAV"). macOS treated "\" as an ordinary character, so the two OSes disagreed on names like "C:\x\y.m4a". - local_name splits the name itself on "/" and "\" on every OS, skips empty and "." segments, falls back to "meeting" for "..", and splits the extension with the same rule as Path::file_stem. - paths::sanitized_stem holds the shared sanitize-or-"meeting" rule; meeting_stem keeps its behavior and now calls it. - The test adds Windows path syntax (C:\x\y.m4a, ..\..\boot.ini, C:, c:.wav) so the mismatch fails on macOS too. Tested: cargo test --all-targets (295 passed, 1 ignored); cargo clippy --all-targets -- -D warnings; cargo fmt --check Not-tested: Windows locally (verified by PR CI after push)
Why: the reopened cycle (generation 3) publishes its evidence with the fix, and the pitfall belongs where the next change will look. - gates.md: G13, downloaded Drive names are OS-independent. - verification-report.md: cause, RED/GREEN, side effects (cache name, local meeting folder and result stem, new Drive meeting folder name), review, and why web QA was not rerun. - Caution: parsing Drive names with Path differs on Windows. Tested: issueops gates check (13/13) Not-tested: n/a (records)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
Galpi 데스크톱 앱에 Google Drive 연동을 추가합니다. 사용자는 건너뛸 수 있는 온보딩에서 Drive를 연결하고, Drive에 있는 녹음을 데스크톱 Google Picker로 골라 전사할 수 있습니다. 전사 결과와 회의록은 내 Drive의 Galpi 폴더에 회의별로 올라갑니다. 같은 회의를 다시 처리하면 기존 파일을 갱신하고, 그사이 Drive에서 파일이 바뀌었으면 덮어쓰지 않고 알립니다. 권한은
drive.file하나이고, 클라이언트 보안 비밀번호 없이 auth-gateway가 토큰 교환을 대행합니다.Closes #12
변경 내용
DriveAccounts)와 포트 3개를 추가했습니다. 포트는 18개, IPC 명령은 7개 늘어 35개가 되었습니다.{이름} 2로 바뀌어도 같은 Drive 폴더로 동기화됩니다.appProperties에 기록한 SHA-256과 Drive가 계산한sha256Checksum을 비교해 판정합니다. 로컬에 Drive 파일 기록을 따로 두지 않습니다.invalid_grant하나뿐입니다. auth-gateway가 401을 돌려주면 앱 로그인도 함께 풀립니다. 그 밖의 실패는 해당 Drive 작업만 실패로 끝나며, 앱이 저절로 재시도하지 않습니다.Path로 해석해서, Windows CI에서a:b?.WAV의a:를 드라이브 접두어로 보고 버렸습니다(b.WAV). 지금은/와\를 모든 OS에서 구분자로 보고, 드라이브 접두어는 일반 문자로 정리하므로 두 OS가 같은 이름을 만듭니다(7232f4a).Drive에서 가져오기는 진행 카드에서 작업으로 실행되고작업 취소로 멈출 수 있습니다. 충돌이 나면Drive 버전 덮어쓰기를 눌러야만 덮어씁니다..issueops/에 남겼습니다. 네 번째 주의 사항은 Drive 파일 이름을Path로 해석하면 Windows에서 결과가 달라진다는 내용입니다.확인한 것
sha256Checksum을 돌려주는 것도 확인했습니다.cargo test --all-targets295개,bun test233개가 통과했습니다.cargo clippy -D warnings,cargo fmt --check,bun run check도 통과했습니다. Drive 어댑터는 가짜 서버로 gateway 대행 교환, 오류 매핑, multipart 업로드, 스트리밍 다운로드 계약을 검사하고, use case 테스트는 로그인 게이트, 계정 불일치 거부, 취소, 생성·갱신·충돌·실패 격리를 검사합니다.C:\x\y.m4a,..\..\boot.ini,C:,c:.wav)를 더하자 macOS에서도 수정 전 구현이 실패했고(C--x-y.m4a), 수정 뒤 통과했습니다. 이 커밋의 PR CI에서rust (windows-latest)를 포함한 모든 작업이 통과했습니다.확인하지 못한 것
bun run dev)에서 전 과정을 실행하지 못했습니다. 테스트한 컴퓨터에 전사 엔진과 모델이 없어서, 화면은 DOM 테스트와 가짜 IPC 화면 확인으로, 호스트 동작은 실제 Google 스모크로 나눠 검증했습니다..part파일에 바로 씁니다.리뷰 포인트
/drive/native/token이 배포되어 있어야 동작합니다. 엔드포인트는 이미 배포되어 응답하지만 m16khb-org/auth-gateway#10(PR [feat] auth-gateway Google 로그인이 있어야 Galpi를 사용하도록 변경 #11)은 아직 열려 있습니다. 엔드포인트가 없으면 Drive 연결만 실패하고 나머지 기능에는 영향이 없습니다.domain/drive.rs의decide)이 Drive 앱이나 웹에서 파일을 고치는 경우를 충분히 덮는지 봐 주세요.\가 있으면 마지막 조각만 쓰므로(1팀\주간 회의.m4a→주간 회의), 이 규칙이 괜찮은지 봐 주세요.