프로젝트

일반

사용자정보

Actions

이슈 #433

진행중
JL HP

VfsService 포팅 — per-account 가상 파일시스템 (Read/Write/List/Mkdir/Delete/Stat/Exists/Lock/Unlock)

이슈 #433: VfsService 포팅 — per-account 가상 파일시스템 (Read/Write/List/Mkdir/Delete/Stat/Exists/Lock/Unlock)

James Lee이(가) 약 7시간 전에 추가함.

상태:
해결
우선순위:
보통
담당자:
목표버전:
시작일:
2026/05/11
완료일:
진척도:

0%

추정시간:

설명

배경

alphea-ai-edge (Rust) 에 legacy VfsService 9 RPC 를 포팅한다. legacy 구현은 wallet-keyed vfs_nodes 테이블 + in-memory MemLocker 로 단순한 per-account 가상 파일시스템을 제공.

레거시 위치:

  • proto: ~/Works/alphea-rpc-next/alphea-rpc/proto/alphea/v1/vfs.proto (9 RPC)
  • handler: ~/Works/alphea-rpc-next/alphea-rpc/internal/handler/stubs.go:51-330 (~280 LoC)
  • store: ~/Works/alphea-rpc-next/alphea-rpc/internal/store/vfs.go (231 LoC)
  • domain locker: ~/Works/alphea-rpc-next/alphea-rpc/internal/domain/vfs/{locker.go,memlocker.go} (123 LoC)

목표

  • 9 RPC 모두 작동: Read, Write, List, Mkdir, Delete, Stat, Exists, Lock, Unlock.
  • legacy 와 기능 동등하지만 account-scope (user_id UUID) 로 전환 — wallet_address 키는 사용 안 함 (#421 정합성).
  • in-memory locker 백그라운드 evictor 포함.
  • /modules, /sys read-only 경로 보호.
  • 처음 접근 시 default tree 자동 초기화 (/home/node/{jobs,logs,workspace}, /modules/demo.*, /sys/version 등).

Proto 처리

proto/alphea/v1/vfs.proto 를 legacy 에서 복사하되:

  • option go_package 라인 제거 (CLAUDE.md 규칙).
  • 기존 필드명 wallet_address 는 wire 호환성을 위해 그대로 유지. 핸들러는 이 필드를 무시하고 JWT caller_user_id 를 사용 (silent override) — 향후 정리 시 별도 이슈에서 user_id 로 rename.
  • build.rs 에 vfs.proto 추가.

DB 스키마 (#254 refs)

신규 마이그레이션 migrations/0014_vfs_nodes.sql:

CREATE TABLE vfs_nodes (
    id            BIGSERIAL PRIMARY KEY,
    user_id       UUID        NOT NULL,
    path          TEXT        NOT NULL,
    name          TEXT        NOT NULL,
    node_type     TEXT        NOT NULL,        -- 'file' | 'directory'
    content       TEXT,
    mime_type     TEXT,
    size          BIGINT      NOT NULL DEFAULT 0,
    readonly      BOOLEAN     NOT NULL DEFAULT FALSE,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    modified_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (user_id, path)
);

CREATE INDEX idx_vfs_user_path ON vfs_nodes (user_id, path);

(legacy 의 BIGINT unix-seconds 타임스탬프 → Rust 측 TIMESTAMPTZ 통일. proto wire 에서는 .timestamp() 로 변환.)

인증

  • auth_middleware::public_path_set() 에 VfsService RPC 추가하지 않음 — 모두 protected.
  • 핸들러 본문에서 require_user_token(&request)? 로 GoTrue user UUID 가져와 user_id 로 사용.
  • proto 의 wallet_address 필드는 받아서 무시 (deprecated).
  • node 토큰은 거부 — VFS 는 사용자 계정 스코프 자원.

Lock 의미

  • holder_id 는 클라이언트가 정하는 자유 문자열 (legacy 와 동일 — node_id, session id, 임의 UUID 모두 가능).
  • TTL 기본 60초, 커스텀 TTL 지정 가능.
  • 동일 holder 의 재 lock 은 TTL 연장.
  • Write/Delete 핸들러는 metadata x-holder-id (gRPC 소문자 헤더) 로 lock ownership 검증 — holder 가 다른 사람의 lock 키와 매치되면 aborted 반환.

파일 추가

  • proto/alphea/v1/vfs.proto (copy + go_package 제거)
  • migrations/0014_vfs_nodes.sql
  • src/store/vfs.rs — VfsRow, get_node, list_children, write, mkdir, delete, exists, ensure_init
  • src/domain/vfs/mod.rs + src/domain/vfs/locker.rs — MemLocker (tokio::sync::Mutex<HashMap> 기반, evictor task)
  • src/handler/vfs.rs — 9 RPC

파일 수정

  • build.rs — proto 목록에 vfs.proto 추가
  • src/handler/mod.rs — VfsHandler 노출
  • src/server/mod.rs — AppState.vfs_locker: Arc<MemLocker> 추가, evictor spawn, gRPC 서비스 등록
  • src/main.rs — AppState 구성
  • src/store/mod.rs — pub mod vfs;
  • src/domain/mod.rs — pub mod vfs;

완료 기준 (DoD)

  • 9 RPC 모두 구현 (unimplemented stub 없음).
  • cargo build clean.
  • cargo clippy --lib 신규 코드 경고 0.
  • cargo test --lib 전부 통과 + 신규 단위 테스트:
    • vfs::locker::* (acquire / re-acquire same holder / blocked by other / TTL expiry / unlock).
    • vfs::store::* (path 정규화 / list_children direct-child filter — 가능하면).
  • CLAUDE.md 의 "Current Implementation Snapshot" 표에 VfsService 추가, "5 미포팅 서비스" 목록에서 제거.

관련 이슈

  • #254 — DB 스키마 (마이그레이션 추가 시 refs).
  • #421 — account-scope 전환. 본 이슈가 그 정책 위에서 동작.
  • #375 — JWT 전역 인터셉터. require_user_token 사용.

예상 작업량

  • proto + migration + store: 1.5h
  • locker + evictor: 1h
  • handler 9 RPC: 2h
  • 테스트 + wiring + CLAUDE.md: 1.5h
  • 총: 6h

연결된 일감 2 (2 건 진행 중 — 모두 미완료)

다음 일감과 관련됨: 이슈 #254: 8-2. 데이터베이스 스키마 설계 (사용자. 앱. 일정)진행James Lee2026/04/282026/04/29

Actions
다음 일감과 관련됨: 이슈 #421: AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환해결James Lee2026/04/27

Actions

JL James Lee이(가) 6달 전에 변경 Actions #1

  • 다음 일감과 관련됨:에 이슈 #254: 8-2. 데이터베이스 스키마 설계 (사용자. 앱. 일정)이(가) 추가되었습니다.

JL James Lee이(가) 6달 전에 변경 Actions #2

  • 다음 일감과 관련됨:에 이슈 #421: AGX 잔액을 Wallet 종속 → Account(GoTrue user_id) 종속으로 전환이(가) 추가되었습니다.

JL James Lee이(가) 6달 전에 변경 Actions #3

  • 상태을(를) 신규에서 해결(으)로 변경되었습니다.

VfsService 포팅 완료

commit:server|fed4ea0

9 RPC 모두 구현, account-scope (user_id) 로 전환, in-memory locker + 백그라운드 evictor, default tree seed, read-only 경로 보호 — 단일 commit 으로 마무리.

변경

  • proto/alphea/v1/vfs.proto (신규) — legacy 에서 복사, option go_package 제거. wallet_address 필드는 wire 호환을 위해 유지하되 핸들러는 무시 (silent override). 향후 정리 시 별도 이슈에서 user_id 로 rename 가능.
  • migrations/0014_vfs_nodes.sql (신규) — vfs_nodes 테이블, (user_id, path) UNIQUE + (user_id, path) 인덱스. legacy 의 BIGINT unix-seconds 대신 TIMESTAMPTZ 통일.
  • src/store/vfs.rs (신규) — VfsRow + get_node / list_children / write / mkdir / delete / exists / ensure_init. is_direct_child 헬퍼로 legacy directory listing 시맨틱 동등. ensure_init 가 16개 default entry seed (/home/node/{jobs,logs,workspace}, /modules/demo.*, /data/sample.json, /sys/{version,profile} 등) 를 트랜잭션으로 처리.
  • src/domain/vfs/mod.rs + locker.rs (신규) — Locker trait (object-safe, LockFuture<'a, T> type alias 로 Pin<Box> 복잡도 감춤) + MemLocker (tokio::sync::Mutex<HashMap>). 10초 주기 백그라운드 evictor, 동일 holder 재-lock 시 TTL 연장, zero-TTL 입력 시 60s 기본값.
  • src/handler/vfs.rs (신규) — 9 RPC.
    • 모든 RPC require_user_token (node token 거부).
    • Write / Mkdir / Delete 는 /modules, /sys 와 그 하위 거부 (permission_denied).
    • Write / Delete 는 metadata x-holder-id 가 있을 때만 lock 소유 검증 — 다른 holder 가 lock 보유 중이면 aborted.
    • Lock / Unlock 은 holder_id 필수.
  • build.rs — proto 목록에 vfs.proto 추가.
  • wiring — src/handler/mod.rs (VfsHandler export), src/store/mod.rs + src/domain/mod.rs (pub mod vfs;), src/server/mod.rs (AppState.vfs_locker + spawn_evictor + VfsServiceServer 등록), src/main.rs (동일 wiring).
  • CLAUDE.md — "Current Implementation Snapshot" 표에 VfsService 행 추가, vfs_nodes 를 마이그레이션된 테이블 목록으로 이동, project structure 의 domain/ 코멘트 갱신.

검증

  • cargo build clean.
  • cargo clippy --lib 신규 코드 경고 0 (사전 admin 1건 무관).
  • cargo test --lib 103/103 통과 (9건 신규):
    • vfs::store::direct_child_of_root, direct_child_of_subdir
    • vfs::locker::acquire_then_unlock, same_holder_extends_ttl, other_holder_blocked, expired_lock_is_reacquirable, unlock_wrong_holder_fails, evict_expired_drops_overdue_entries, zero_ttl_uses_default

DoD 충족

  • ✅ 9 RPC 모두 구현 (unimplemented stub 없음)
  • ✅ cargo build clean
  • ✅ cargo clippy --lib 신규 경고 0
  • ✅ cargo test --lib 전부 통과 + locker 7건 + store 2건 단위 테스트
  • ✅ CLAUDE.md "Current Implementation Snapshot" 표에 VfsService 추가, 미포팅 서비스 목록에서 제거 (← 이번 commit 으로 7/11 서비스 완료)

→ 상태를 해결로 전환.

CP Chris Park이(가) 6달 전에 변경 Actions #4

  • 담당자을(를) James Lee에서 Henry Park(으)로 변경되었습니다.
Actions

내보내기 PDF Atom