이번 편에서는 클라우드 기반 협업 도구의 핵심 기능인 ‘공유 드라이브’를 직접 만들어본다. 여러 사람이 파일을 올리고, 내려받고, 필요할 때 지우고, 목록을 확인하는 기본 기능부터 시작해서 파일 메타데이터를 관리하는 데이터베이스 구조까지 한 번에 다룬다. 개인 소개 웹페이지처럼 화면 하나짜리 실습이 아니라 백엔드와 클라우드 스토리지, 데이터베이스가 함께 얽히는 과제이기 때문에, 이번에는 AI 개발 파트너에게 무엇을 먼저 묻고 무엇을 나중에 요청해야 하는지가 더 중요해진다.
공유 드라이브는 파일 저장, 사용자 인증, 접근 제어, 데이터 동기화가 유기적으로 맞물리는 서비스다. 전통적인 개발 방식이라면 요구사항 분석부터 설계, 구현, 테스트까지 상당한 시간이 든다. 이 편에서는 그 과정을 AI 개발 파트너와 함께 어떤 순서로, 어떤 프롬프트로 좁혀가는지에 집중한다. 완성된 코드를 그대로 베끼는 것보다, AI에게 무엇을 먼저 물어야 하는지를 익히는 것이 이번 실습의 진짜 목표다.
스토리지는 AWS S3, 언어는 Python을 기준으로 진행한다. 다른 클라우드 스토리지나 언어를 쓰더라도 흐름 자체는 동일하니, 아래 프롬프트의 스토리지·언어 이름만 바꿔서 그대로 활용하면 된다.
1단계 — 요구사항을 좁히고 핵심 모듈을 나눈다
코드를 요청하기 전에 정리해야 할 질문이 있다. 어떤 사용자가, 어떤 종류의 파일을, 누구와 공유할 것인가. 파일 최대 크기나 동시 접속자 수 같은 제약도 미리 생각해두면 이후 AI와의 대화가 훨씬 구체적으로 흘러간다. 실습에서는 범위를 좁혀 아래 네 가지 모듈만 다룬다.
- 사용자 인증 모듈 — 가입, 로그인, 로그아웃
- 파일 업로드·다운로드 모듈 — 클라우드 스토리지 연동
- 파일 메타데이터 관리 모듈 — 데이터베이스 저장
- 파일 공유 모듈 — 공유 대상과 권한 지정
이 네 가지를 한꺼번에 요청하지 말고 순서대로 하나씩 요청하는 것이 핵심이다. 모듈 하나가 끝나야 다음 모듈의 코드가 앞 모듈과 자연스럽게 연결된다. 아래는 AI 개발 파트너에게 전체 구조를 먼저 스케치해달라고 요청하는 프롬프트다.
클라우드 기반 공유 드라이브 서비스를 만들려고 해.
- 언어: Python, 스토리지: AWS S3
- 사용자는 파일을 업로드하고, 특정 사용자와만 공유하고,
다운로드/삭제/목록 조회를 할 수 있어야 함
지금은 코드를 짜지 말고, 이 서비스를 구성할 핵심 모듈 목록과
모듈 간 데이터 흐름만 정리해줘. 각 모듈이 어떤 데이터베이스
테이블을 필요로 하는지도 같이 알려줘.
이 프롬프트는 코드 대신 설계도를 먼저 요청한다는 점이 중요하다. 설계 단계를 건너뛰고 바로 코드를 요청하면, 모듈 간 데이터 흐름이 꼬였을 때 뒤늦게 전체를 다시 짜야 하는 경우가 생긴다.

2단계 — 파일 메타데이터를 위한 데이터베이스 설계
파일 자체는 S3에 저장하지만, 파일명·소유자·생성일·공유 설정 같은 메타데이터는 별도 데이터베이스에 저장해야 한다. 관계형 데이터베이스를 쓴다면 사용자, 파일, 공유 세 개 테이블로 시작하는 것이 가장 단순하다. 아래는 이 구조를 AI에게 요청하는 프롬프트다.
PostgreSQL 기준으로 공유 드라이브에 필요한 테이블 세 개를
설계해줘.
- users: 사용자 계정 정보
- files: 업로드된 파일의 메타데이터 (S3 객체 키 포함)
- shares: 어떤 파일을 어떤 사용자와 공유했는지
각 테이블의 CREATE TABLE 문을 작성하고, 외래 키 관계를
주석으로 설명해줘.
이 프롬프트에 대해 AI는 보통 아래와 같은 형태의 DDL을 내놓는다. 이 코드는 세 테이블 사이의 관계(파일은 소유자를 가리키고, 공유는 파일과 대상 사용자를 함께 가리킨다)를 외래 키로 표현한 최소 구조다.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT now()
);
CREATE TABLE files (
id SERIAL PRIMARY KEY,
owner_id INTEGER REFERENCES users(id),
file_name VARCHAR(255) NOT NULL,
s3_key VARCHAR(512) NOT NULL,
size_bytes BIGINT,
created_at TIMESTAMP DEFAULT now()
);
CREATE TABLE shares (
id SERIAL PRIMARY KEY,
file_id INTEGER REFERENCES files(id),
shared_with_id INTEGER REFERENCES users(id),
permission VARCHAR(20) DEFAULT 'read',
created_at TIMESTAMP DEFAULT now()
);
실제 파일 바이너리는 S3에 두고, 데이터베이스에는 그 파일을 가리키는 s3_key만 저장한다는 점을 눈여겨보자. 이렇게 나누면 파일이 아무리 커져도 데이터베이스 자체는 가벼운 상태를 유지할 수 있다.
3단계 — AWS S3로 파일 업로드·다운로드 구현하기
이제 실제 파일을 다루는 부분이다. Python에서 AWS S3를 다룰 때는 boto3 라이브러리를 쓴다. AWS 공식 개발자 안내서에 따르면, upload_file 메서드는 파일명과 버킷 이름, 객체 이름을 인자로 받아 파일을 업로드하며, 큰 파일은 자동으로 여러 조각으로 나눠 병렬로 전송하는 방식으로 처리한다. 아래는 이 메서드를 활용한 업로드 함수다.
import boto3
from botocore.exceptions import ClientError
s3_client = boto3.client('s3')
def upload_file(file_path, bucket, object_name):
"""로컬 파일을 S3 버킷에 업로드한다."""
try:
s3_client.upload_file(file_path, bucket, object_name)
except ClientError as e:
print(f"업로드 실패: {e}")
return False
return True
업로드 진행률을 화면에 표시하고 싶다면 Callback 인자를 함께 넘길 수 있다. AWS 공식 안내서는 전송 도중 지금까지 전송된 바이트 수를 콜백 클래스에 전달하는 방식으로 진행률 표시를 구현하는 예시를 제공한다. 대용량 파일을 다루는 공유 드라이브라면 이 콜백을 프런트엔드의 진행률 바와 연결하는 식으로 확장할 수 있다.
업로드가 끝났다면 다운로드, 삭제, 목록 조회도 같은 클라이언트로 처리한다. 이 코드는 파일 하나를 로컬로 내려받고, 하나를 지우고, 버킷 안의 파일 목록을 가져오는 세 가지 동작을 각각의 함수로 나눈 것이다.
def download_file(bucket, object_name, save_path):
"""S3 객체를 로컬 경로로 내려받는다."""
try:
s3_client.download_file(bucket, object_name, save_path)
except ClientError as e:
print(f"다운로드 실패: {e}")
return False
return True
def delete_file(bucket, object_name):
"""S3 버킷에서 객체 하나를 삭제한다."""
try:
s3_client.delete_object(Bucket=bucket, Key=object_name)
except ClientError as e:
print(f"삭제 실패: {e}")
return False
return True
def list_files(bucket, prefix=""):
"""버킷 안의 객체 목록을 가져온다."""
response = s3_client.list_objects_v2(Bucket=bucket, Prefix=prefix)
return [obj["Key"] for obj in response.get("Contents", [])]
이 네 함수만으로 업로드·다운로드·삭제·목록 조회라는 공유 드라이브의 가장 기본적인 동작이 갖춰진다. AI 개발 파트너에게는 이 함수들을 한 번에 요청하기보다, “먼저 업로드 함수를 만들고, 정상 동작을 확인한 뒤 다운로드 함수를 추가해줘”처럼 순서를 정해 요청하면 중간에 뭔가 잘못됐을 때 원인을 좁히기 쉽다.
4단계 — 업로드 API와 데이터베이스 기록을 연결하기
S3 업로드 함수와 앞서 만든 files 테이블을 연결해야 실제 서비스가 된다. 파일을 S3에 올리는 것과, 그 파일의 존재를 데이터베이스에 기록하는 것은 별개의 작업이라는 점을 기억해두자. 이 프롬프트는 두 작업을 하나의 API 엔드포인트 안에서 순서대로 처리해달라는 요청이다.
Flask로 파일 업로드 API 엔드포인트를 만들어줘.
동작 순서:
1) 요청으로 들어온 파일을 S3에 업로드
2) 업로드가 성공하면 files 테이블에 소유자 ID, 파일명,
s3_key, 파일 크기를 저장
3) S3 업로드는 됐는데 DB 기록이 실패하면, S3에 올라간
파일을 다시 지우고 에러를 반환
완성되면 이 순서가 왜 필요한지 한 줄로 설명해줘.
3번 조건을 넣은 이유를 짚어두자. S3 업로드는 성공했는데 데이터베이스 기록만 실패하면, 실제로는 파일이 존재하지만 서비스 화면에는 보이지 않는 ‘고아 파일’이 생긴다. 이런 불일치를 막으려면 실패 시 되돌리는 로직까지 AI에게 명시적으로 요청해야 한다. AI가 알아서 이런 예외 상황을 챙겨줄 것이라고 기대하지 말고, 어떤 상황에서 무엇을 되돌려야 하는지를 직접 조건으로 적어주는 편이 안전하다.
5단계 — 공유 기능과 접근 제어 확인하기
마지막으로 파일을 다른 사용자와 공유하는 기능이다. 이 부분은 코드 자체보다 검증이 더 중요하다. 공유 설정을 잘못 구현하면 권한이 없는 사용자가 파일에 접근할 수 있는 심각한 문제로 이어진다. 아래 프롬프트는 공유 API를 요청하면서, 동시에 그 API가 권한 체크를 제대로 하는지 스스로 점검하도록 요구한다.
파일 공유 API를 만들어줘.
- 소유자만 자신의 파일을 다른 사용자와 공유할 수 있어야 함
- 공유받은 사용자는 read 권한만 가짐 (수정·삭제 불가)
- 파일 다운로드 API에도 shares 테이블을 확인하는 권한 체크를
추가해줘. 소유자도 아니고 공유받지도 않은 사용자가 요청하면
403을 반환해야 함
구현 후, 권한 체크를 우회할 수 있는 경우가 있는지 스스로
검토해서 알려줘.
마지막 문장이 핵심이다. AI에게 “만들어줘”로 끝내지 않고 “우회할 수 있는 경우가 있는지 검토해줘”까지 요청하면, AI가 놓쳤을 수 있는 예외 경로(예: 파일 ID를 직접 URL에 넣어 우회하는 경우)를 스스로 짚어주는 경우가 많다. 다만 이 검토 결과를 100% 신뢰하지 말고, 실제로 다른 계정으로 로그인해 접근이 막히는지 직접 눈으로 확인하는 과정은 반드시 거쳐야 한다.
결론
공유 드라이브는 파일 업로드 하나만 동작한다고 끝나는 과제가 아니다. 스토리지, 데이터베이스, 인증, 권한이 서로 맞물려야 실제로 쓸 수 있는 서비스가 된다. 이번 실습에서는 그 네 가지를 한꺼번에 요청하지 않고, 설계 → 데이터베이스 → 업로드·다운로드 → API 연결 → 공유·권한 순서로 하나씩 AI 개발 파트너에게 요청하는 흐름을 따라갔다. 이 순서를 지키면 중간에 문제가 생겼을 때 어느 단계에서 어긋났는지 훨씬 빨리 찾을 수 있다.
특히 5단계에서 다룬 권한 체크처럼, AI가 만든 코드를 그대로 믿지 않고 “이 코드가 놓칠 수 있는 상황이 있는지” 되물어보는 습관은 공유 드라이브뿐 아니라 앞으로 어떤 프로젝트를 만들 때도 그대로 쓸 수 있다.
참고 자료
- AWS boto3 개발자 안내서 — S3 파일 업로드 — https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html
#공유드라이브백엔드구현, #AWSS3파일업로드다운로드, #바이브코딩클라우드협업, #boto3파일관리코드, #파일공유권한체크, #바이브코딩, #클라우드협업도구, #AWSS3, #boto3, #공유드라이브
