프로젝트 개요 및 기술 스택
FrankMega는 Mega.nz의 기능을 모방한 자가 호스팅용 파일 공유 서비스로, 다음과 같은 현대적인 기술 스택을 사용하여 구축되었습니다. * Framework: Rails 8 (Solid Queue, Cache, Cable 포함) * Database: SQLite (별도의 Redis나 PostgreSQL 없이 운영) * Frontend: Tailwind CSS, Hotwire, Stimulus * Security: Rack::Attack, WebAuthn (Passkeys), TOTP (2FA) * Deployment: Docker, Thruster, Cloudflare Tunnel
AI 기반 개발의 첫 단계: IDEA.md와 첫 번째 커밋
개발은 명확한 요구사항을 담은 docs/IDEA.md 작성으로 시작되었습니다. 여기에는 파일 업로드, 다운로드 제한, 자동 만료, 초대 전용 가입 시스템 등 핵심 기능이 정의되었습니다. 첫 번째 커밋은 AI의 도움으로 약 7,000줄에 달하는 방대한 양의 코드로 구성되었으나, 이는 어디까지나 기능적인 프로토타입에 불과했습니다. 저자는 이 과정에서 AI가 제시하는 추가 기능 제안을 수용하면서도, 프로젝트의 본질적인 목적을 잃지 않도록 명확한 가이드라인을 유지했습니다.
보안 강화: 22가지 취약점 수정
저자는 AI가 생성한 초기 코드에서 발견된 22가지 보안 이슈를 직접 수정하며 프로덕션 수준으로 끌어올렸습니다.
* OTP 리플레이 공격 방지: 단순히 코드의 유효성만 검사하던 방식에서 last_otp_at 타임스탬프를 기록하여 동일한 코드가 재사용되는 것을 차단했습니다. 이는 대부분의 튜토리얼에서 간과하는 중요한 보안 세부 사항입니다.
* 원자적(Atomic) 카운터: 루비 레벨에서 숫자를 증가시키는 방식은 동시 요청 시 데이터 정합성 문제가 발생할 수 있으므로, SQL의 UPDATE ... WHERE 문을 사용하여 원자성을 보장했습니다. 이를 통해 TOCTOU(Time of Check, Time of Use) 버그를 예방했습니다.
* 암호화 키 관리: 환경 변수가 없을 때 하드코딩된 키로 폴백되는 위험을 제거하고, 프로덕션 환경에서는 반드시 환경 변수가 존재해야만 앱이 구동되도록 수정했습니다.
* CSP 및 Nonce 설정: 세션 ID를 Nonce로 사용하던 취약한 방식을 버리고 요청마다 무작위 Nonce를 생성하도록 변경하여 인라인 스크립트 주입 공격을 방어했습니다.
파일 공유 시스템의 세부 구현 사항
단순한 다운로드를 넘어 실제 운영 환경에서 필요한 세부 로직들이 구현되었습니다.
* 파일명 정규화(Sanitization): Path Traversal 방지, 제어 문자 제거, 윈도우 예약어 처리 등을 통해 서버 파일 시스템의 안정성을 확보했습니다. 특히 파일명의 바이트 수 제한을 고려하여 확장자가 잘리지 않도록 처리하는 세심함을 더했습니다.
* 서버 측 MIME 타입 감지: 클라이언트가 보내는 헤더를 신뢰하지 않고 Marcel 젬을 사용하여 파일의 매직 바이트를 직접 검사함으로써 악성 파일 업로드 위험을 줄였습니다.
* 자동 정리 및 IP 차단: 만료된 파일을 주기적으로 삭제하는 백그라운드 잡(Solid Queue)과 잘못된 해시로 반복 접근하는 IP를 자동으로 차단하는 보안 레이어를 구축했습니다.
배포 아키텍처: Docker와 Cloudflare
홈 서버 환경에 최적화된 배포 방식을 채택했습니다.
* Multi-stage Docker Build: jemalloc을 적용하여 메모리 효율을 높이고, non-root 사용자로 실행하여 컨테이너 보안을 강화했습니다.
* Thruster: Basecamp에서 개발한 HTTP 프록시를 사용하여 Gzip 압축, 에셋 캐싱, X-Sendfile 가속을 처리합니다.
* Cloudflare Tunnel: 방화벽 포트를 개방할 필요 없이 아웃바운드 터널을 통해 안전하게 외부에서 접근 가능하도록 설정했으며, SSL 종료 및 DDoS 보호 기능을 활용했습니다.
Vibe Coding에 대한 통찰
저자는 AI(Claude Code)가 생산성을 극대화해주지만, 의사결정의 주체는 여전히 개발자여야 함을 강조합니다. AI는 개발자의 역량을 증폭시키는 도구일 뿐, 보안 아키텍처나 동시성 제어와 같은 복잡한 문제를 스스로 완벽하게 해결하지 못합니다. 숙련된 개발자는 AI에게 무엇을 요구해야 할지 알고, 생성된 코드의 결함을 파악할 수 있는 능력을 갖추어야 합니다. 결국 ‘Vibe Coding’의 성공은 프롬프트 엔지니어링이 아니라 개발자의 깊은 경험과 기술적 통찰력에 달려 있습니다.