9c58b022e2
- ERP 셸: 좌측 사이드바 + 상단 헤더 + 콘텐츠 영역(erp_base.html)
- 분기: 슈퍼관리자 → 업무모듈 카드, 일반사용자 → ERP 메인(erp_home.html)
- 신규 라우트: /modules (슈퍼관리자 모듈 카드 재진입)
- 개인경비 모듈: app/modules/expense/ (라우터/저장소/템플릿)
- JSON 저장소(ExpenseStore) + PostgreSQL 저장소(ExpenseDBStore)
- 팩토리: EXPENSE_DB_URL 있으면 DB, 없으면 JSON 폴백
- DB: scripts/sql/expense_db_init.sql (멱등 DDL, postgres-db 컨테이너)
- expense_db, 역할 expense_app, 테이블 expense_items, 인덱스/트리거
- 마이그레이션: scripts/migrate_expense_json_to_db.py (멱등, --dry-run)
- 의존성: psycopg[binary,pool]>=3.2
- 환경변수: EXPENSE_DB_URL 추가
- 문서: CLAUDE.md 작업 기준 + docs/{PROJECT_OVERVIEW,SERVER_ARCHITECTURE,DATABASES,DEPLOYMENT}.md
- main-app 배포 경로 /opt/www/main 고정 명시
- 위험 명령(DROP/TRUNCATE/rm -rf/volume 삭제) 사용자 승인 정책
5.1 KiB
5.1 KiB
Databases
PostgreSQL DB 목록
| DB명 | 용도 |
|---|---|
itemcode_db |
상품코드, 단품/세트 구성, 채널 ↔ 사내 코드 매칭 |
orderlist_db |
주문 수집·분석·관리 (구 orderlist_app) |
return_db |
반품·교환·CS 데이터 |
expense_db |
개인경비 / 법인카드 사용내역 / 정산 |
명명 규칙
- 모든 DB 이름은 소문자 + 언더스코어,
_db로 끝낸다.- ✅
inventory_db,cs_db - ❌
inventoryApp,cs-database
- ✅
- 신규 DB가 필요하면 사용자 승인 후 생성한다.
- 신규 DB 생성 시 함께 정리할 항목:
- 용도와 책임 모듈
- 소유자(OWNER) 계정
- 백업 주기와 위치
.env의 연결 정보 변수명
레거시 이름 매핑
| 예전 이름 | 현재 기준 |
|---|---|
orderlist_app |
orderlist_db |
코드/문서/설정에서 orderlist_app을 발견하면 orderlist_db로 수정한다 (수정 전 영향 범위 확인).
DB 작업 원칙
- 작업 전 백업 우선. 백업 없는 변경은 진행하지 않는다.
- 테이블 owner, 권한, sequence 권한을 확인한다.
- 운영 DB의
DROP,TRUNCATE, 조건 없는 대량DELETE/UPDATE는 사용자 확인 없이 실행 금지. - 스키마 변경은 마이그레이션 스크립트(
scripts/또는 alembic 등)로 관리한다. - 운영 DB와 개발 DB의 접속 정보를 혼동하지 않는다 (
.env로 분리).
위험 명령 (사용자 승인 필수)
| 명령 | 비고 |
|---|---|
DROP DATABASE |
복구 불가. 백업 없으면 절대 실행 금지 |
DROP TABLE / DROP SCHEMA |
의존 객체 확인 필수 |
TRUNCATE |
FK CASCADE 시 광범위 삭제 위험 |
조건 없는 DELETE / UPDATE |
WHERE 없는 문 차단 |
docker volume rm <postgres_volume> |
운영 데이터 영구 손실 |
docker compose down -v |
볼륨까지 제거. 운영에서 금지 |
실행 전 반드시:
- 백업 확인 (
pg_dump, 컨테이너 외부 마운트) - 영향 범위 설명
- 사용자 명시 승인
자주 쓰는 점검 명령
# 컨테이너/네트워크
docker ps
docker network ls
docker inspect <postgres_container_name>
# DB 목록 / 접속
sudo -u postgres psql -l
docker exec -it <postgres_container_name> psql -U postgres -l
# 특정 DB 접속
docker exec -it <postgres_container_name> psql -U <user> -d itemcode_db
# 테이블/권한 확인
\dt
\dn+
\du
\z <table_name>
expense_db 스키마 / 초기화
DDL: scripts/sql/expense_db_init.sql (멱등). DB·역할·테이블·인덱스·트리거를 한 번에 생성.
테이블 expense_items
| 컬럼 | 타입 | 비고 |
|---|---|---|
id |
TEXT PK | 12자 hex (uuid4 앞 12자) |
owner |
TEXT | 소유자 email (소문자) |
spent_at |
DATE | 사용일 |
category |
TEXT | 식대/교통/숙박/비품/접대/통신/기타 |
method |
TEXT | 법인카드/개인지출/현금 |
merchant |
TEXT | 가맹점 |
amount |
BIGINT | 원 단위, ≥ 0 |
memo |
TEXT | 비고 |
status |
TEXT | 작성중/제출/승인/반려/정산완료 |
created_at / updated_at |
TIMESTAMPTZ | 트리거로 자동 갱신 |
인덱스: (owner, spent_at DESC), (status), (created_at DESC).
운영 서버 초기화 (1회)
# 1) 비밀번호 변수 준비 (셸 히스토리에 남지 않게 환경변수 사용)
read -s -p "expense_app password: " APP_PWD; echo
# 2) PostgreSQL 컨테이너에 DDL 적용
docker exec -i postgres-db psql -U postgres \
-v app_password="$APP_PWD" \
< scripts/sql/expense_db_init.sql
# 3) main-app .env 에 EXPENSE_DB_URL 추가
# EXPENSE_DB_URL=postgresql://expense_app:<APP_PWD>@postgres-db:5432/expense_db
# 4) main-app 재기동
docker compose up -d --build
JSON → DB 마이그레이션
docker exec -e EXPENSE_DB_URL="$EXPENSE_DB_URL" -it dbx-main \
python scripts/migrate_expense_json_to_db.py \
--json /data/expense.json --dry-run
# 결과 확인 후
docker exec -e EXPENSE_DB_URL="$EXPENSE_DB_URL" -it dbx-main \
python scripts/migrate_expense_json_to_db.py --json /data/expense.json
멱등 INSERT(
ON CONFLICT DO NOTHING). 원본 JSON 은 건드리지 않는다.
백업 / 복구 (안전 절차)
백업
# 단일 DB 덤프 (운영 권장)
docker exec -t <postgres_container_name> \
pg_dump -U <user> -F c -d orderlist_db \
> /var/backups/postgres/orderlist_db_$(date +%F).dump
복구 (덮어쓰기 위험 → 사용자 승인 필수)
# 1) 신규 DB로 먼저 복구해 검증
docker exec -i <postgres_container_name> \
pg_restore -U <user> -d <new_db_name> < backup.dump
# 2) 검증 완료 후 운영 DB 교체 (필요 시)
pg_restore --clean은 기존 객체를 삭제한다. 운영 대상 DB에서 절대 무단 실행 금지.
.env 관련
- DB 접속 정보(
*_HOST,*_PORT,*_USER,*_PASSWORD,*_NAME)는 모두.env로 관리한다. .env는 Git에 올리지 않는다..env.example만 커밋한다.- 비밀값 유출이 의심되면 즉시 회전(비밀번호/키 변경)을 진행한다.