M
MESSAGE FOR LOVE AND PEACE
Meslap 디지털 사역
시스템 설계 · 운영 백서
meslap.ecolab-x.com · 기술 · 운영 문서
LIVE · 배포 검증 완료
작성 2026-06-26
대상: 운영자 · 차기 유지보수자
0 문서의 목적
이 백서는 meslap.ecolab-x.com 의 실제 배포된 시스템 구조와 운영 절차를 기록한 기술 문서입니다. 성도용 나레이션 백서(meslap-whitepaper)와 짝을 이루는 시스템 설계·운영 짝입니다.
1 한눈에 보기 — 배포 검증
2026-06-26 실측. 모든 구성요소 라이브 확인.
| 항목 | 값 | 검증 |
| 공개 사이트 | https://meslap.ecolab-x.com | 200 · 69,233 B ✅ |
| 구사이트 미러 | https://meslap-old.ecolab-x.com | 200 ✅ |
| API 공개 암송구절 | /api/public/verse | 정상 응답 ✅ |
| API 인증 보호 | /api/me | 401 ✅ |
| 백엔드 서비스 | meslap-api.service | active/running ✅ |
| 자동연동 | youtube.json · blog.json | 12:17 / 12:22 갱신 ✅ |
2 인프라 아키텍처
인터넷 (HTTPS)
│
┌───────────────────┴────────────────────┐
│ 오라클 클라우드 ARM 서버 │ 168.107.25.230 (4코어/23GB)
│ Ubuntu · SSH 별칭 `arm` │
│ │
│ ┌────────────── nginx ──────────────┐ │
│ │ :443 ssl (와일드카드 SSL) │ │ ecolab-x.com-0001
│ │ server_name meslap.ecolab-x.com │ │
│ │ │ │
│ │ location / ─────────────────────┼───┼─▶ /var/www/meslap/index.html
│ │ try_files … /index.html (SPA) │ │ (정적 단일 HTML)
│ │ location /api/ ────────────────────┼───┼─▶ 127.0.0.1:3001 (proxy_pass)
│ └────────────────────────────────────┘ │
│ │
│ ┌─ systemd: meslap-api ─────────────┐ │
│ │ node --experimental-sqlite │ │ User=ubuntu · Restart=always
│ │ /opt/meslap-api/server.js :3001 │ │ Node v22.23.1 · 의존성 0개
│ │ └─ meslap.db (SQLite, 내장) │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ cron: /etc/cron.d/meslap-youtube ─┐ │
│ │ 00:17,12:17 fetch_youtube.py ──────┼───┼─▶ data/youtube.json
│ │ 00:22,12:22 fetch_blog.py ──────┼───┼─▶ data/blog.json
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
핵심 설계 원칙
- 무의존(zero-dependency) 백엔드 — Node 내장
http + node:sqlite + crypto만. npm 패키지 0개 → 공급망 위험·버전 깨짐 없음.
- 정적 + API 분리 — 공개층은 단일 정적 HTML(빠름·견고), 동적 기능만
/api 프록시.
- 로컬 바인딩 — API는
127.0.0.1:3001 에만, 외부 노출·TLS는 nginx 전담.
- 자가 치유 —
Restart=always / RestartSec=3 로 프로세스 죽어도 자동 복구.
- 올리면 채워짐 — cron이 유튜브·블로그를 정적 JSON으로 떨궈, 프론트가 동일 도메인에서 읽음(CORS 불필요).
3 파일 · 경로 지도
| 경로 | 역할 | 소유/권한 |
/var/www/meslap/index.html | 공개 SPA (69KB 단일 파일) | root |
/var/www/meslap/data/youtube.json | 유튜브 최신 영상 캐시 | ubuntu |
/var/www/meslap/data/blog.json | 네이버 블로그 본문 캐시 | ubuntu |
/var/www/meslap/data/bulletins/ | 주보 이미지/PDF 저장소 | ubuntu |
/opt/meslap-api/server.js | 멤버존 API 본체 | ubuntu |
/opt/meslap-api/meslap.db | SQLite DB (전 데이터) | ubuntu rw |
/opt/meslap-api/secret | PIN 해시 솔트 (0600) — 백업·비공개 필수 | ubuntu |
/opt/meslap/fetch_youtube.py | 유튜브 RSS 수집기 | ubuntu |
/opt/meslap/fetch_blog.py | 블로그 본문 수집기 | ubuntu |
/etc/nginx/conf.d/meslap.conf | 공개 사이트 + /api 프록시 | root |
/etc/nginx/conf.d/meslap-old.conf | 구사이트 미러 | root |
/etc/cron.d/meslap-youtube | 자동연동 스케줄 | root |
4 멤버존 백엔드 설계 (server.js)
4.1 인증
- 로그인: 이름 + PIN. 첫 로그인 시 입력 PIN으로 자동 등록(미등록 이름 거부 → 관리자 사전 등록 필요).
- PIN 저장:
SHA256(secret + ':' + pin) — 평문 미저장. 솔트는 /opt/meslap-api/secret.
- 세션:
randomBytes(24) 토큰, Authorization: Bearer, TTL 30일, 만료 시 자동 삭제.
4.2 권한 4단계 (위 단계는 아래 포함)
| 레벨 | 역할 | 대표 권한 |
| 1 | member 성도 | 조회, 본인 주차·출결·가정예배, 성경공부 기록 |
| 2 | officer 재직 | + 보고서 작성, 공람 게시 |
| 3 | pastor 목회자 | + 암송구절·재정 입력, 주보 업로드 |
| 4 | admin 관리자 | + 계정·역할 지정, 명단 관리 |
안전장치: 마지막 관리자 강등/삭제 차단 (setrole·remove 가드).
4.3 데이터 모델 — SQLite 12 테이블
members · sessions · parking · attendance · families · fam_worship · bible_study · reports · board · finance · settings · bulletins
4.4 API 엔드포인트
| 메서드 · 경로 | 권한 | 기능 |
POST /api/login ·/logout · GET /api/me | — / 1 | 인증 |
GET /api/public/verse ·/public/bulletins | 공개 | 홈 화면용(무인증) |
POST /api/admin/verse | 3 | 금주 암송구절 등록 |
GET /api/parking · POST /claim ·/release | 1 | 주차 11칸 (claim은 지정 운전자만) |
POST /api/attendance | 1 | 주일 출석 |
GET /api/family · POST /toggle ·/admin/family | 1 / 4 | 가정예배 |
GET·POST /api/bible ·/bible/remove | 1 | 성경공부(멘토·멘티·진행·기도) |
GET·POST /api/reports ·/remove | 1 / 2 | 보고서 |
GET·POST /api/board ·/remove | 1 / 2 | 공람 |
GET /api/roster | 1 | 요람(명단) |
GET /api/finance · POST /admin/finance | 1 / 3 | 재정 |
GET /api/bulletins · POST /admin/bulletin ·/remove | 1 / 3 | 주보 업로드(≤25MB) + OCR |
/api/admin/member·setdriver·setrole·resetpin·remove | 4 | 계정 관리 |
4.5 주보 OCR → 암송구절 자동추출
- 업로드 시
?extract=1 → PDF는 pdftotext(실패 시 pdftoppm+tesseract), 이미지는 tesseract -l kor+eng.
- "심비에 새기는 365구절" 블록에서 번호·제목·출처·본문 파싱, 66권 성경 정규식으로 출처 인식.
- 사람 확인 필수 — 2단 인쇄 주보는 인식 오류 가능 → 초안 제안 후 목회자가 확인·저장.
5 자동연동 (cron)
/etc/cron.d/meslap-youtube — 실행 사용자 ubuntu, 하루 2회:
| 시각 | 작업 | 출력 | 로그 |
| 00:17 / 12:17 | fetch_youtube.py | data/youtube.json | /tmp/meslap_yt.log |
| 00:22 / 12:22 | fetch_blog.py | data/blog.json | /tmp/meslap_blog.log |
- 유튜브: 채널 RSS(
UCXUHra_EuT3T2vD8j3BDuJQ) → 최신 15개. API 키 불필요.
- 블로그: 네이버 RSS(
meslap3) → 최신 한글 글의 모바일 본문(se-main-container) 추출 → "당일 예배 말씀".
- 두 스크립트 모두
tmp→os.replace 원자적 쓰기로 읽기 중 깨짐 방지, 4회 재시도.
6 운영 가이드
6.1 최초 셋업
- 관리자 로그인
관리자 / 1234 → 즉시 PIN 변경.
- 요람에서 실제 성도 명단 등록, 역할 지정(목사=
pastor, 집사·부장=officer).
- 주차 지정 운전자 표시(
setdriver).
6.2 일상 운영 — 손댈 것 없음
- 유튜브·블로그는 올리기만 하면 12시간 내 자동 반영.
- 금주 암송구절: 멤버존에서 직접 입력 또는 주보 업로드 후 OCR 초안 확인·저장.
6.3 점검 · 복구 명령 (SSH arm)
# 상태
systemctl status meslap-api
curl -s https://meslap.ecolab-x.com/api/public/verse
# 재시작 / 로그
sudo systemctl restart meslap-api
journalctl -u meslap-api -n 50 --no-pager
# 자동연동 수동 실행·로그
sudo -u ubuntu python3 /opt/meslap/fetch_youtube.py
cat /tmp/meslap_yt.log /tmp/meslap_blog.log
# 백업 (DB + 솔트 + 주보) — 반드시 함께
tar czf meslap-backup-$(date +%F).tgz \
/opt/meslap-api/meslap.db /opt/meslap-api/secret \
/var/www/meslap/data/bulletins
6.4 백업 정책 (권장)
- 최소 주 1회:
meslap.db + secret + bulletins/.
- ⚠️ secret 분실 시 모든 PIN 검증 불가(전원 재설정 필요) → DB와 같은 곳에 보관.
7 보안 점검표
- ✅ API는 localhost 바인딩, 외부는 nginx TLS만 노출
- ✅ PIN 해시 저장(솔트 0600), 평문·로그 노출 없음
- ✅ 업로드 25MB 제한 · 확장자 화이트리스트(pdf/png/jpg)
- ✅ 권한 레벨 가드(need/needLv/needAdmin), 마지막 관리자 보호
- ⚠️ 점검 권장: 세션 30일 TTL 적정성, 주보 디렉터리 직접 접근 범위, OCR 임시파일(
/tmp/bull_*) 정리
8 알려진 한계 / 향후 (2차 이후)
- JesusOn 재정 연동: 현재 수기 요약 + 바로가기. 계정·연동 방식 확보 시 직접 수집 가능.
- 주보 OCR 정확도: 2단 빽빽한 인쇄물 한계 → 사람 확인 단계 유지.
- 확장 후보: 실제 명단·역할 등록, PWA 앱화, 심방·중보기도, 카톡/문자 알림.
9 운영 인프라 의존성
- 와일드카드 SSL:
ecolab-x.com-0001 (수동 갱신 — 만료 2026-09-19, 멧돼지 알림 연동)
- 디스크 모니터: 25GB 임계 알림 → dosung00@hanmail.net
- 서버: 오라클 ARM(168.107.25.230), 06-24 이전 완료·라이브