- 목록에서 슬라이드 워밍(최대 24건) 후 coverImageUrl 전달 - 카드 상단 풀너비 이미지+스크림, 무이미지 시 다층 그라데이션 Made-with: Cursor
Web Platform (학습센터)
유튜브 링크와 PowerPoint(.pptx) 강의를 등록하고, 목록에서 클릭해 바로 시청할 수 있는 사내 학습센터 예제입니다.
접속 방법
브라우저에서 열기 전에 반드시 터미널에서 서버를 실행해야 합니다. (npm start 미실행 상태에서는 http://localhost:8030에 연결되지 않습니다.)
서버 실행 후 아래 주소로 접속합니다.
| 환경 | URL |
|---|---|
| 로컬 기본 | http://localhost:8030 |
| 포트 변경 시 | http://localhost:{PORT} (예: PORT=4000 npm start → http://localhost:4000) |
- 메인 페이지 (
/): 학습센터 뷰어 (강의 목록) - 학습센터 뷰어 (
/learning): 강의 검색/필터 + 카드 목록 (일반 사용자) - 관리자 (
/admin): 강의 등록(YouTube/PPT/웹 링크 등), 썸네일·AI 추가 등 통합 관리 - 강의 상세: 카드 클릭 시 유튜브 재생 또는 PPT 뷰어
- 기타 메뉴: 채팅(
/chat), AI(/ai-explore), 프롬프트 라이브러리(/ai-explore/prompts), AI 성공 사례(/ai-cases), AX 과제 신청(/ax-apply) - 관리자 이벤트 로그:
http://localhost:8030/admin/thumbnail-events?token={ADMIN_TOKEN}
접속이 안 될 때 (트러블슈팅)
- 서버가 떠 있는지 확인
프로젝트 루트에서npm start를 실행하고, 터미널에Server started: http://localhost:8030같은 로그가 나오는지 확인합니다. - 포트 번호 확인
.env에PORT=...가 있으면 그 포트로 접속합니다. (기본값은8030) - 부팅 실패
터미널에Failed to bootstrap:이 나오면 프로세스가 종료되며 HTTP 서버가 뜨지 않습니다. 메시지를 확인한 뒤data/쓰기 권한, 디스크 여유, DB 설정 등을 점검합니다. - 포트 충돌
다른 프로그램이 8030을 쓰는 경우PORT=8031 npm start처럼 바꿔 실행하거나, 이미 떠 있는 Node 서버 프로세스를 종료합니다. 구체적인 명령은 아래 실행 방법 절의 기존 서버 프로세스 종료 항목을 참고하세요. - 바인드 주소
기본은 모든 네트워크 인터페이스(0.0.0.0)에서 수신합니다. 로컬 루프백만 쓰려면HOST=127.0.0.1 npm start를 사용할 수 있습니다.
핵심 기능
- 학습센터 UI (좌측 메뉴 + 상단 헤더 + 강의 카드 레이아웃)
- AI 탐색 (
/ai-explore): 전체 너비 레이아웃, AI 서비스 카드(프롬프트·회의록 등). 검색창에 **「프롬프트」**가 포함된 채 검색(Enter) 시 프롬프트 라이브러리로 이동 - 프롬프트 라이브러리 (
/ai-explore/prompts): 업무별 기본 프롬프트 카드 선택·미리보기·클립보드 복사 (data/company-prompts.json). 좌측 메뉴(채팅·AI·AI 성공 사례·학습센터·AX 과제 신청)는 관리자 여부와 관계없이 접근 가능(강의 삭제·관리자 대시보드 등 일부 기능은 관리자 모드에서만) - 검색/필터/페이지네이션
- 검색어(
q) 기반 제목/설명/태그 필터 - 타입(
YouTube,PPT) 필터 - 태그 필터 + 페이지네이션
- 검색어(
- 유튜브 강의 등록/시청
- 유튜브 URL 입력 후 목록에 추가
- 강의 상세에서 iframe 임베드로 재생
- PPT 강의 등록/시청
.pptx파일 업로드- 상세에서 슬라이드 텍스트 기반 뷰어 제공
- 목록 카드에 PPT 프리뷰(첫 슬라이드 제목 + 장수) 표시
- macOS 환경에서는
qlmanage기반 실제 썸네일(첫 장 이미지) 자동 생성
- 썸네일 백그라운드 큐
- 썸네일 생성은 비동기 큐에서 처리
- 상태값:
pending/processing/ready/failed - 실패 시 자동 재시도 정책 적용(최대 횟수 이후
failed고정) - 큐 스냅샷을
data/thumbnail-jobs.json에 저장해 재시작 후 복구 - 작업 이벤트를
data/thumbnail-events.json에 기록
- 관리자 삭제
- 관리자 토큰으로 강의 삭제 가능
- 초기 샘플 데이터 시드
resources/lecture에 있는.pptx를 최초 실행 시 자동 등록
- 관리자 인증·바로가기(UI)
- 좌측 메뉴 하단
관리자/관리자 off: 운영(OPS)에서 이메일 인증으로 로그인한 임직원에게도 표시됩니다. **관리자**는 모달에서ADMIN_TOKEN을 입력해 검증한 뒤/admin으로 이동합니다(POST /api/admin/validate-token). **관리자 off**는 관리자 쿠키를 지우고 학습센터 목록(/learning)으로 돌아갑니다(GET /admin/logout). 이메일 미로그인 환경에서도 동일합니다. 이미 관리자 세션이면 중복이므로관리자항목은 숨기고, 사용자 현황관리 → 구분선 → 관리자 off →(OPS일 때 구분선)→ 로그아웃 순으로 표시됩니다. - 학습센터 (
/learning): 관리자 쿠키가 있을 때 상단 오른쪽 학습 등록으로 통합 관리 화면(/admin)에 들어갈 수 있습니다. 이메일(OPS) 로그인과 동시에 있어도 버튼이 숨겨지지 않습니다. - AI 성공 사례 (
/ai-cases): 관리자일 때 상단 사례 등록·관리로 편집 화면(/ai-cases/write)에 진입합니다(동일하게 OPS 로그인 중에도 표시).
- 좌측 메뉴 하단
프로젝트 구조
ai_platform/
├─ server.js # Express 서버 진입점 (라우팅, 업로드, 썸네일 큐, DB 연동)
├─ package.json # 의존성 및 npm 스크립트
├─ .env # 환경 변수 (실제 값, .gitignore 대상)
├─ .env.example # 환경 변수 예시 템플릿
├─ db/
│ └─ schema.sql # PostgreSQL lectures 테이블 스키마 (서버 기동 시 자동 적용)
├─ scripts/
│ └─ apply-schema.js # 수동 스키마 적용 스크립트 (npm run db:schema)
├─ public/
│ └─ styles.css # 전역 스타일
├─ views/
│ ├─ partials/
│ │ ├─ nav.ejs # 좌측 공통 네비게이션(하단 관리자·토큰 모달 연동)
│ │ └─ admin-token-modal.ejs # 관리자 토큰 입력 모달(`openAdminTokenModal`)
│ ├─ learning-viewer.ejs # 학습센터 뷰어 (일반 사용자)
│ ├─ learning-admin.ejs # 학습센터 관리 (업로드·삭제·썸네일)
│ ├─ chat.ejs # 채팅
│ ├─ ai-explore.ejs # AI 탐색 (전체 너비, 프롬프트 카드·검색)
│ ├─ ai-prompts.ejs # 프롬프트 라이브러리 (카드·미리보기·복사)
│ ├─ ai-cases.ejs # AI 성공 사례 목록(카드)
│ ├─ ai-case-detail.ejs # AI 성공 사례 상세(마크다운)
│ ├─ ai-cases-write.ejs # AI 성공 사례 관리자 등록·편집
│ ├─ ax-apply.ejs # AX 과제 신청
│ ├─ lecture-youtube.ejs # 유튜브 강의 상세 (iframe 임베드)
│ ├─ lecture-ppt.ejs # PPT 강의 상세 (슬라이드 텍스트 뷰어)
│ └─ admin-thumbnail-events.ejs # 썸네일 이벤트 로그 관리자 페이지
├─ data/
│ ├─ lectures.json # 강의 메타데이터 (ENABLE_POSTGRES=0 또는 DB 폴백 시)
│ ├─ company-prompts.json # AI 프롬프트 라이브러리 템플릿 (제목·설명·본문)
│ ├─ thumbnail-jobs.json # 썸네일 큐 스냅샷 (재시작 후 복구용)
│ └─ thumbnail-events.json # 썸네일 작업 이벤트 로그
├─ uploads/ # 업로드된 .pptx 파일 저장
│ └─ thumbnails/ # 생성된 썸네일 이미지
└─ resources/
└─ lecture/ # 초기 시드용 샘플 PPT (최초 실행 시 자동 등록)
구조 설명
| 구분 | 설명 |
|---|---|
| 서버 | server.js가 Express 앱, 라우트, Multer 업로드, 썸네일 백그라운드 워커, PostgreSQL 연동을 모두 담당 |
| 데이터 저장소 | ENABLE_POSTGRES=1이면 PostgreSQL lectures 테이블이 단일 소스, 0이면 data/lectures.json 사용 |
| 썸네일 | 비동기 큐 처리, data/thumbnail-jobs.json으로 영속화, data/thumbnail-events.json에 이벤트 기록 |
| 뷰 | EJS 템플릿으로 메인/유튜브/PPT/관리자 페이지 렌더링 |
서버 배포 (새 머신·처음부터)
아래는 저장소를 처음 받아 운영 서버에 올리는 경우를 가정한 절차입니다. macOS(개발용·소규모 호스팅)와 Linux(일반적인 VPS·온프레미스 서버)를 구분했습니다.
공통 사전 요구사항
| 항목 | 설명 |
|---|---|
| Node.js | v18 이상 권장 (node -v로 확인) |
| npm | Node와 함께 설치 |
| Git | 저장소 클론용 |
| PostgreSQL | ENABLE_POSTGRES=1 사용 시 접속 가능한 DB(로컬 설치 또는 원격) |
| 환경 변수 | .env.example을 복사해 .env 작성(비밀번호·토큰은 반드시 변경) |
PPT 썸네일·슬라이드 이미지는 macOS에서는 qlmanage가 우선 사용되고, 그 외에는 LibreOffice·poppler(pdftoppm) 조합이 필요합니다. 도구가 없으면 텍스트 프리뷰로 동작합니다.
macOS에서 배포 (새 머신)
-
도구 설치
- Node.js: nodejs.org LTS 설치, 또는
brew install node@20등 - Git: Xcode Command Line Tools(
xcode-select --install) 또는brew install git - PostgreSQL(로컬 DB를 쓸 때):
brew install postgresql@16후 서비스 기동, 또는 원격 DB만 사용 - PPT 변환 강화(선택):
brew install --cask libreoffice,brew install poppler
- Node.js: nodejs.org LTS 설치, 또는
-
코드 받기
mkdir -p ~/workspace && cd ~/workspace git clone <저장소 URL> ai_platform cd ai_platform(이미 클론한 경우 예:
cd /Users/dsyoon/workspace/ai_platform) -
의존성·환경
npm install cp .env.example .env # 편집기로 .env 수정: PORT, ADMIN_TOKEN, DB_*, ENABLE_POSTGRES 등 -
DB 스키마 (
ENABLE_POSTGRES=1일 때)npm run db:schema -
실행 방식 선택
- 포그라운드(테스트):
npm start→ 터미널에Server started: http://localhost:8030확인 후 브라우저 접속 - 백그라운드(PM2): 아래 「PM2로 실행」 절 참고 (
pm2 start … --name ai_platform)
- 포그라운드(테스트):
-
접속
같은 Mac에서:http://127.0.0.1:8030(또는.env의PORT). 다른 기기에서 접속하려면HOST=0.0.0.0이 기본이므로, macOS 방화벽에서 Node 허용 여부를 확인합니다.
Linux에서 배포 (새 서버)
배포 경로는 예시로 /var/www/ai_platform을 둡니다. 배포 사용자·그룹(www-data 등)은 배포 정책에 맞게 조정하세요.
-
시스템 패키지 (Ubuntu/Debian 예시)
sudo apt update sudo apt install -y git build-essential- Node.js: 배포판 기본 패키지가 오래된 경우가 많으므로 NodeSource 또는 nvm으로 v18+ 설치를 권장합니다.
- PostgreSQL 클라이언트/서버: 원격 DB만 쓰면 클라이언트 라이브러리만으로도 되고, 로컬 DB면
postgresql패키지 설치 후 DB·사용자 생성. - PPT 변환(선택):
sudo apt install -y libreoffice poppler-utils
-
코드 배치
sudo mkdir -p /var/www cd /var/www sudo git clone <저장소 URL> ai_platform cd ai_platform sudo chown -R "$USER:$USER" /var/www/ai_platform # 이후 작업 사용자에 맞게 조정 -
의존성·환경
npm install --production cp .env.example .env nano .env # 또는 vim — PORT, ADMIN_TOKEN, DB_*, ENABLE_POSTGRES 등 -
DB 스키마 (
ENABLE_POSTGRES=1일 때)npm run db:schema -
프로세스 관리 (PM2 권장)
sudo npm install -g pm2 cd /var/www/ai_platform pm2 start server.js --name ai_platform pm2 save pm2 startup # 부팅 시 자동 기동(출력되는 sudo 명령 실행) -
방화벽·리버스 프록시
- 외부에 직접
8030을 열지 않고 Nginx/Apache로 TLS·프록시하는 구성이 일반적입니다. - Apache2 예시(모듈·VirtualHost)는 docs/DEPLOYMENT-xavis.ncue.net.md를 참고하세요.
ufw사용 시:sudo ufw allow 80,443/tcp후 앱은 로컬에서만 듣게 하거나, 프록시 뒤에 둡니다.
- 외부에 직접
-
데이터 디렉터리 권한
data/,uploads/등에 앱 실행 사용자(예:pm2로 띄운 사용자, 또는www-data)가 쓰기 가능해야 합니다. 실패 시 로그에Failed to bootstrap또는 권한 오류가 납니다.
배포 후 확인
- 터미널 또는
pm2 logs ai_platform에서 에러 없이Server started로그 확인 - 브라우저로 메인·
/learning·관리자(토큰)까지 동작 확인 - PostgreSQL 사용 시
npm run db:schema는 최초 1회(또는 스키마 변경 시); 백업·마이그레이션 정책은 운영 환경에 맞게 별도 수립
실행 방법
로컬에서 빠르게 띄우기는 아래 순서면 됩니다. 새 서버에 맞춰 처음부터 배포할 때는 위 「서버 배포 (새 머신·처음부터)」의 macOS 또는 Linux 절을 따르세요.
1) 의존성 설치
npm install
2) PostgreSQL 스키마 적용
npm run db:schema
3) 서버 실행
프로젝트 루트에서:
npm start
정상 기동 시 터미널에 Server started: http://localhost:8030 (또는 설정한 PORT)가 출력됩니다. 이 상태에서만 브라우저로 접속할 수 있습니다.
PM2로 실행
프로젝트 루트에서 실행해야 server.js가 같은 디렉터리의 .env를 읽습니다( dotenv 기준).
1) PM2 설치 (전역, 한 번)
npm install -g pm2
2) 프로젝트 디렉터리로 이동 후 의존성
cd /Users/dsyoon/workspace/ai_platform
npm install
cp .env.example .env # 최초 1회 — 값 편집
3) 앱 기동
pm2 start server.js --name ai_platform
npm start와 동일하게 server.js를 띄웁니다. 이름만 PM2에서 ai_platform으로 관리합니다.
4) 재부팅 후에도 유지 (선택)
pm2 save
pm2 startup
pm2 startup이 출력하는 sudo env PATH=... 한 줄을 그대로 실행한 뒤, 다시 pm2 save를 하면 부팅 시 자동 기동에 맞춰집니다.
5) 자주 쓰는 명령
| 목적 | 명령 |
|---|---|
| 상태 확인 | pm2 list |
| 로그(실시간) | pm2 logs ai_platform |
| 재시작 | pm2 restart ai_platform |
| 중지 | pm2 stop ai_platform |
| 목록에서 제거 | pm2 delete ai_platform |
환경 변수: 포트·DB 등은 프로젝트 루트의 .env에 두고, 변경 후 pm2 restart ai_platform으로 반영합니다. 별도 경로에 두었다면 해당 디렉터리에서 pm2 start 하거나, ecosystem 설정으로 cwd를 지정하세요.
운영/배포 환경에서 이미 PM2로 띄운 경우 재시작 예:
pm2 restart ai_platform
로컬에서 포그라운드로만 확인할 때:
node server.js
- 기본 포트:
8030 - 접속 URL: http://localhost:8030
포트·수신 주소 변경
PORT=8030 npm start
# 로컬 루프백만 (외부 네트워크 인터페이스에 바인딩하지 않음)
HOST=127.0.0.1 npm start
서버는 기본적으로 HOST=0.0.0.0으로 바인딩합니다(동일 기기의 localhost 접속에 사용).
기존 서버 프로세스 종료
터미널을 닫았는데도 이전에 실행한 node server.js가 남아 있거나, **포트가 이미 사용 중(EADDRINUSE)**이라 새로 npm start가 실패할 때, 기존 프로세스를 먼저 종료합니다.
포트로 PID 확인 후 종료 (macOS / Linux, 기본 포트 8030 예시)
lsof -i :8030
출력의 PID 열 값을 확인한 뒤:
kill PID
응답이 없으면 kill -9 PID로 강제 종료할 수 있으나, 다른 Node 작업이 같은 포트를 쓰는지 확인한 뒤 사용하세요.
프로젝트 진입점만 대상으로 종료 (다른 node 작업에 영향을 줄 수 있으니 주의)
pkill -f "node server.js"
PM2로 띄운 경우
pm2 list
pm2 stop ai_platform
# 완전히 제거하려면
pm2 delete ai_platform
Windows에서는 작업 관리자에서 Node.js 프로세스를 종료하거나, PowerShell에서 Get-NetTCPConnection -LocalPort 8030 등으로 점유 프로세스를 확인한 뒤 해당 PID를 종료합니다.
관리자 토큰/페이지 크기 설정(선택)
ADMIN_TOKEN=my-secret PAGE_SIZE=12 npm start
ADMIN_TOKEN미지정 시 기본값:xavis-adminPAGE_SIZE미지정 시 기본값:8.env파일이 있으면dotenv로 자동 로드- 브라우저에서는 좌측 메뉴 하단 관리자 → 모달에 위 토큰을 입력해 세션 쿠키를 발급받는 방식으로
/admin에 진입할 수 있습니다(임직원 이메일 로그인 여부와 동일한 흐름).
PostgreSQL 연결 설정
ENABLE_POSTGRES=1일 때: PostgreSQL이 단일 소스로 사용됩니다.data/lectures.json은 사용하지 않습니다.ENABLE_POSTGRES=0일 때:data/lectures.json만 사용합니다.- DB 연결 실패 시 자동으로
data/lectures.json기반 파일 저장소로 폴백합니다. - 필수 변수:
DB_HOST,DB_PORT,DB_DATABASE,DB_USERNAME,DB_PASSWORD
채팅 기능 (OpenAI API)
.env에OPENAI_API_KEY를 넣은 뒤 서버를 재시작하면 채팅 메뉴(/chat)에서 OpenAI와 실제 대화가 이루어집니다.- API 키 발급: OpenAI Platform
- 키 값 앞뒤 공백은 자동으로 제거합니다.
- 화면의 모델 선택(
gpt-5.4,gpt-5-mini)은 내부적으로 OpenAI에 전달할 실제 모델 ID로 매핑됩니다. 기본값은 각각gpt-4o,gpt-4o-mini이며, 필요하면.env에서OPENAI_MODEL_DEFAULT,OPENAI_MODEL_MINI로 바꿀 수 있습니다. - 웹 검색(기본 활성):
OPENAI_WEB_SEARCH가0이 아니면 OpenAI Responses API와 내장web_search도구로 질의에 맞게 웹을 검색한 뒤 답변합니다. 끄려면OPENAI_WEB_SEARCH=0으로 두면 이전과 같이 Chat Completions만 사용합니다. 선택적으로OPENAI_WEB_SEARCH_COUNTRY(기본KR),OPENAI_WEB_SEARCH_CITY,OPENAI_WEB_SEARCH_REGION,OPENAI_WEB_SEARCH_TIMEZONE(기본Asia/Seoul)로 검색 맥락을 줄 수 있습니다. GET /api/chat/config는{ configured, webSearch }를 반환합니다(webSearch는 위 플래그와 동일).- 스트리밍(
POST /api/chat/stream)은 SSE로data: {JSON}줄을 보냅니다. 타입 예:delta(본문 조각),status(예:phase: "web_search"— UI에서 «웹 검색 중…» 표시),sources(인용 URL·제목 목록),done,error. 비스트리밍POST /api/chat은 필요 시 응답 JSON에sources배열을 포함할 수 있습니다. - 키가 비어 있으면
POST /api/chat·POST /api/chat/stream은 503을 반환하고, 채팅 화면 상단에 안내 배너가 표시됩니다.
PPT 썸네일 및 슬라이드 이미지 생성 제어(선택)
ENABLE_PPT_THUMBNAIL=1 npm start
- 기본값:
1(활성) ENABLE_PPT_THUMBNAIL=0이면 썸네일·슬라이드 이미지 생성 비활성화- 우선순위: macOS
qlmanage→ LibreOffice(soffice/libreoffice) +pdftoppm - 도구 미설치 또는 변환 실패 시 텍스트 프리뷰로 자동 폴백
PPT 슬라이드 이미지(뷰어용): PPTX 파일은 LibreOffice로 PDF 변환 후 pdftoppm으로 이미지 생성.
- PPTX: LibreOffice 필수. macOS:
brew install --cask libreoffice - PDF:
pdftoppm만 있으면 동작 (poppler 패키지)
.env 예시
PORT=8030
HOST=0.0.0.0
ADMIN_TOKEN=xavis-admin
PAGE_SIZE=8
ENABLE_POSTGRES=1
DB_HOST=your-db-host
DB_PORT=5432
DB_DATABASE=your_database
DB_USERNAME=your_user
DB_PASSWORD=your_password
ENABLE_PPT_THUMBNAIL=1
THUMBNAIL_WIDTH=1000
THUMBNAIL_MAX_RETRY=2
THUMBNAIL_RETRY_DELAY_MS=5000
THUMBNAIL_EVENT_KEEP=200
THUMBNAIL_EVENT_PAGE_SIZE=50
# 채팅 기능 (OpenAI API 키)
OPENAI_API_KEY=
# OPENAI_MODEL_DEFAULT=gpt-4o
# OPENAI_MODEL_MINI=gpt-4o-mini
사용 방법
- 메인 페이지에서 강의 등록
- 유튜브 강의 등록: 제목 + 유튜브 링크 (+설명)
- PowerPoint 강의 등록: 제목 +
.pptx파일 (+설명) - 두 등록 폼 모두 태그(쉼표 구분) 입력 가능
- 하단 등록된 강의 카드에서 항목 클릭
- 강의 상세 화면에서 시청
- 유튜브: 동영상 재생
- PPT: 슬라이드 텍스트 목록 확인
검색/필터
- 검색어, 타입, 태그를 조합해서 목록을 조회할 수 있습니다.
- 결과 목록은 페이지 단위로 분할되어 이동 가능합니다.
관리자 삭제
- 화면의 관리자 모드에서 토큰 입력 후 활성화
- 강의 카드의
삭제버튼으로 즉시 삭제 - PPT 강의 삭제 시 업로드 파일도 함께 제거 시도
썸네일 재생성(관리자)
- 관리자 모드에서 PPT 카드의
썸네일 재생성버튼으로 수동 재생성 가능 실패 썸네일 일괄 재시도버튼으로 실패 건을 큐에 일괄 재등록 가능이벤트 로그 페이지에서 기간/유형/강의ID/사유 필터 조회 가능- 이벤트 로그는 CSV 다운로드 지원
주요 라우트
메뉴별 화면
| 경로 | 설명 |
|---|---|
GET / |
학습센터 뷰어 (강의 목록) |
GET /learning |
학습센터 뷰어 (검색/필터/페이지네이션) |
GET /admin |
관리자 대시보드 (강의·썸네일·AI 등) |
GET /chat |
채팅 |
GET /ai-explore |
AI 탐색 (프롬프트·회의록 등 카드, 전체 너비 레이아웃) |
GET /ai-explore/prompts |
프롬프트 라이브러리 (업무 시나리오별 기본 프롬프트) |
GET /ai-cases |
AI 성공 사례 목록(검색·태그 필터, 카드) |
GET /ai-cases/:slug |
AI 성공 사례 상세 |
GET /ai-cases/write |
AI 성공 사례 관리(관리자 토큰 필요) |
POST/PUT/DELETE /api/ai-success-stories |
사례 CRUD(관리자) · 본문은 data/ai-success-stories/*.md |
GET /ax-apply |
AX 과제 신청 |
GET /lectures/:id |
강의 상세 뷰어 (유튜브/PPT) |
API
-
GET /api/chat/config
채팅용 OpenAI 키 설정 여부{ configured: boolean }(키 문자열은 노출하지 않음) -
POST /api/chat
JSON{ model, messages }— OpenAI Chat Completions 연동(비스트리밍).OPENAI_API_KEY필수. -
POST /api/chat/stream
동일 본문으로 SSE(text/event-stream) 스트리밍 응답. 이벤트:data: {"type":"delta","text":"..."}조각, 마지막{"type":"done"}. 오류 시{"type":"error","error":"..."}. 채팅 UI는 이 엔드포인트를 사용합니다. -
POST /lectures/youtube
유튜브 강의 등록 -
POST /lectures/ppt
PPT 강의 등록 (multipart/form-data) -
POST /lectures/:id/delete
관리자 토큰 기반 강의 삭제 -
POST /lectures/:id/thumbnail/regenerate
관리자 토큰 기반 PPT 썸네일 재생성 -
POST /thumbnails/retry-failed
관리자 토큰 기반 실패 썸네일 일괄 재시도 큐 등록 -
GET /api/queue/metrics?token=...
관리자 토큰 기반 큐/상태 메트릭 JSON 조회 -
GET /api/queue/events-summary?token=...&hours=24
최근 시간대 요약 KPI/시간대별 처리량 JSON 조회 -
GET /admin/thumbnail-events?token=...
관리자 이벤트 로그 페이지 (필터/페이지네이션) -
GET /admin/thumbnail-events.csv?token=...
필터 기준 이벤트 로그 CSV 다운로드
최근 업데이트 (요약)
- AI 탐색 (
/ai-explore): 메인 콘텐츠를 뷰포트 전체 너비로 사용, 프롬프트 서비스 카드를 첫 번째에 배치, 검색어에 **「프롬프트」**가 포함된 채 검색(Enter) 시 프롬프트 라이브러리로 이동. 좌측 전체 메뉴는 관리자 여부와 관계없이 동일하게 표시·접근 가능 - 프롬프트 라이브러리 (
/ai-explore/prompts): 시나리오 카드·미리보기·복사 UI, 템플릿 데이터는data/company-prompts.json에서 로드 - 서버 수신 주소: 기본
HOST=0.0.0.0(로컬localhost접속에 사용). 필요 시HOST=127.0.0.1로 제한 가능 - 문서:
localhost접속 불가 시 확인할 항목을 아래 「접속이 안 될 때 (트러블슈팅)」 절에 정리
기술 스택
- Node.js
- Express
- EJS
- PostgreSQL (
pg) - Multer (파일 업로드)
- JSZip (
.pptx내부 XML 파싱) - UUID
구현 참고/제약
- PPT 뷰어는 원본 슬라이드 디자인 렌더링이 아닌,
.pptx내부 텍스트를 추출해 보여주는 방식입니다. - PPT 썸네일은 시스템 도구 상태에 따라 생성 실패할 수 있으며, 이 경우 이미지 없이 텍스트 프리뷰만 표시됩니다.
- 썸네일 큐는 단일 프로세스 워커 기준으로 동작합니다(다중 인스턴스 분산 락은 미구현).
- 폰트/도형/애니메이션까지 완전 동일 렌더링이 필요하면 별도 문서 렌더러(예: LibreOffice/PDF 변환 파이프라인) 연동이 필요합니다.
- 이벤트 로그 페이지의 실시간 그래프는 클라이언트 폴링 기반이며, 다수 접속 시 폴링 주기 조정이 필요할 수 있습니다.