권장 프로젝트 파일 구조와 의존성 설계
업데이트: 2026-10-02
DashCloud는 개발자가 별도의 Dockerfile이나 복잡한 인프라 설정 파일을 작성하지 않아도, 프로젝트 루트 디렉터리의 표준 파일 구성을 자동으로 분석하여 가장 적합한 런타임 환경을 조립합니다.
로컬 개발 환경에서는 문제없이 작동하던 코드가 클라우드 배포 시 에러를 일으키지 않도록, 권장되는 표준 디렉터리 구조와 의존성 파일 작성 요령을 상세히 알아봅니다.
언어별 표준 디렉터리 구조
프로젝트 루트 폴더에는 메인 진입점 파일과 의존성 명세 파일이 반드시 포함되어야 합니다.
Python 표준 프로젝트 구조
가장 널리 사용되는 기본 구조입니다. 루트에 main.py와 requirements.txt를 배치합니다.
- my-python-bot/
- main.py # [필수] 실행 진입점 파일
- requirements.txt # [필수] 의존성 패키지 목록
- .env.example # [권장] 필요한 환경변수 샘플 명세
- .gitignore # [권장] Git 추적 제외 목록
- config.py # 설정 및 환경변수 로더
- data/ # [선택] 로컬 데이터 디렉터리 (/app 볼륨에 영구 저장)
- bot.db # SQLite 데이터베이스 파일
- modules/ # 보조 비즈니스 로직
- handlers.py # 메시지 핸들러
- utils.py # 헬퍼 함수
진입점 파일 자동 감지 우선순위
DashCloud 빌드 엔진은 배포 시 프로젝트 루트를 검사하여 별도의 진입점을 지정하지 않았을 때 아래 우선순위에 따라 메인 프로세스를 스스로 찾아 실행합니다.
1. Python 런타임 진입점 탐색 순서
- 사용자가 대시보드나 CLI에서 명시적으로 지정한 파일명 (예:
bot.py) dashcloud.json매니페스트의entrypoint설정- 프로젝트 루트의
main.py - 프로젝트 루트의
app.py - 프로젝트 루트의
bot.py - 프로젝트 루트의
run.py
2. Node.js 런타임 진입점 탐색 순서
package.json의"scripts": { "start": "..." }스크립트 명령어package.json의"main"필드에 지정된 파일 (예:"main": "index.js")- 프로젝트 루트의
index.js - 프로젝트 루트의
app.js - 프로젝트 루트의
server.js
진입점 파일이 src/index.js나 bot/main.py처럼 하위 디렉터리에 위치해 있다면, 대시보드의 진입점 입력 필드에 상대 경로(src/index.js)를 명시해 주어야 정상 실행됩니다.
의존성 파일 작성 요령 및 베스트 프랙티스
1. requirements.txt 올바르게 작성하기
로컬 환경에서 무심코 pip freeze > requirements.txt를 실행하면, 운영체제 종속적인 패키지나 로컬 개발 도구(black, pytest, jupyter 등)까지 전부 포함되어 클라우드 빌드 시간이 수 분 이상 지연되거나 OS 불일치로 빌드 오류가 발생할 수 있습니다.
실제 프로덕션 봇 구동에 필요한 라이브러리만을 선별하고, 메이저 버전 호환성을 보장하는 유연한 버전 핀을 지정합니다.
# 핵심 봇 및 통신 라이브러리
python-telegram-bot>=21.0,<22.0
requests>=2.31.0
httpx>=0.27.0
# 데이터베이스 및 비동기 유틸리티
aiofiles>=23.2.1
python-dotenv>=1.0.0
# 퀀트 및 수치 계산 (필요한 경우만)
ccxt>=4.4.0
pandas>=2.2.02. package.json 올바르게 작성하기
최신 Node.js 환경에서는 "type": "module"을 지정하여 import/export 구문을 활성화하고, "scripts": { "start": "..." }를 명시하는 것이 표준입니다.
{
"name": "dashcloud-telegram-bot",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"telegraf": "^4.16.3",
"dotenv": "^16.4.5"
},
"devDependencies": {
"eslint": "^9.0.0"
},
"engines": {
"node": ">=20.0.0"
}
}파일 경로 다루기: 상대 경로와 Pathlib
클라우드 컨테이너 환경에서는 사용자의 로컬 PC 드라이브 경로(C:\, /Users/username/)가 존재하지 않습니다. 코드 안에서 파일을 읽고 쓸 때는 항상 스크립트 실행 위치 기준의 상대 경로를 구성해야 합니다.
import os
from pathlib import Path
# 현재 스크립트 파일이 위치한 디렉터리 절대경로 산출
BASE_DIR = Path(__file__).resolve().parent
# 데이터 저장 디렉터리 (없으면 자동 생성)
DATA_DIR = BASE_DIR / "data"
DATA_DIR.mkdir(parents=True, exist_ok=True)
# 영구 보존할 SQLite 데이터베이스 경로
DATABASE_PATH = DATA_DIR / "bot_database.db"
# 잘못된 예:
# DB_PATH = "C:\\Users\\admin\\Desktop\\my-bot\\bot.db" # 에러 발생!
# DB_PATH = "/Users/kochanhyun/Documents/my-bot/bot.db" # 에러 발생!프로세스 Graceful Shutdown 구현
새 버전으로 코드를 재배포하거나 대시보드에서 서비스 재시작을 누르면, 호스트 시스템은 프로세스에 SIGTERM 종료 신호를 먼저 전달합니다.
종료 신호를 받았을 때 진행 중이던 DB 쓰기 트랜잭션을 마무리하고 소켓을 닫지 않으면, 데이터베이스 잠금이 남거나 데이터가 깨질 수 있습니다.
import signal
import sys
import logging
import asyncio
logger = logging.getLogger(__name__)
async def cleanup_resources():
logger.info("종료 신호를 감지했습니다. 자원을 정리합니다...")
# 1. 활성 텔레그램 세션/소켓 닫기
# 2. SQLite DB 커넥션 커밋 및 닫기
# 3. 임시 버퍼 파일 디스크 플러시
logger.info("모든 자원이 안전하게 정리되었습니다. 정상 종료합니다.")
def handle_sigterm(signum, frame):
logger.warning(f"시스템 신호({signum}) 수신: 프로세스 종료 절차 시작")
# 비동기 이벤트 루프 종료 스케줄링
sys.exit(0)
# SIGTERM, SIGINT(Ctrl+C) 신호 등록
signal.signal(signal.SIGTERM, handle_sigterm)
signal.signal(signal.SIGINT, handle_sigterm).gitignore 필수 체크리스트
불필요하게 용량이 크거나 보안상 위험한 파일은 Git 저장소에 커밋되지 않도록 .gitignore에 등록하세요.
# 환경 변수 및 시크릿 (절대 커밋 금지!)
.env
.env.local
*.key
*.pem
# 파이썬 캐시 및 가상환경
__pycache__/
*.py[cod]
.venv/
env/
venv/
# 노드 의존성 및 빌드 산출물
node_modules/
dist/
.npm/
# IDE 및 OS 설정 파일
.DS_Store
Thumbs.db
.vscode/
.idea/
# 로컬 테스트용 임시 데이터
data/*.db-journal
data/*.db-wal