미르 · IT팀
IT 포탈 매뉴얼
직원이 쓰는 법(1부)과 담당자가 운영하는 법(2부)을 한 문서에 담았습니다. 화면 사진은 실제로 돌고 있는 포탈에서 그대로 찍은 것입니다.
1부
직원용 — 쓰는 법
계정을 받은 날부터 필요한 것만 모았습니다. 앞에서부터 읽으셔도 되고, 왼쪽 목차에서 필요한 곳만 보셔도 됩니다.
1.1처음 들어가기
포탈은 회원가입이 없습니다. IT 담당자가 계정을 만들어 아이디와 초기 비밀번호를 전달합니다.
- 브라우저에서
portal.mir.example.com을 엽니다. - 받은 아이디 와 초기 비밀번호 를 넣고 로그인.
- 처음 로그인하면 비밀번호 변경 화면으로 넘어갑니다. 여기서는 건너뛸 수 없습니다.
초기 비밀번호는 담당자가 정해서 메신저로 보냅니다. 그러니까 그 비밀번호는 이미 두 사람이 알고, 메신저 기록에도 남아 있습니다. 초기 비밀번호를 편하게 줄 수 있는 이유가 바로 이것입니다 — 오래 남지 않기 때문입니다.
로그인은 12시간 유지됩니다. 아침에 로그인하면 퇴근까지 갑니다. 그 뒤에는 다시 로그인 화면이 뜨는데, 고장이 아닙니다.
비밀번호를 잊으면 스스로 찾을 수 없습니다. IT 담당자에게 초기화 를 요청하세요. 나중에 바꾸고 싶을 때는 오른쪽 위 톱니 → 비밀번호 변경.
1.2첫 화면 보는 법
로그인하면 바로 챗 화면이 열립니다. 가운데에 내가 쓸 수 있는 앱 이 카드로 깔립니다.
| 자리 | 무엇 |
|---|---|
| 왼쪽 세로줄 | 지난 대화 목록. 오늘 / 어제 / 지난 7일 / 지난 30일 로 묶여 있습니다. 맨 위 + 새 대화 로 새로 시작합니다. |
| 가운데 칩 | 예시 질문. 눌러 보시면 챗이 어떻게 답하는지 감이 옵니다. 내가 쓸 수 있는 앱에 맞춰 바뀝니다. |
| 앱 카드 | 앱 이름과 설명. 누르면 그 앱 화면이 열립니다. |
| 오른쪽 위 앱 | 전체 앱 목록. 이름으로 검색할 수 있습니다. |
| 오른쪽 위 톱니 | 비밀번호 변경. (관리자면 관리자 페이지도 보입니다) |
| 왼쪽 아래 | 내 이름 · 부서. 오른쪽 아이콘이 로그아웃입니다. |
카드를 내 마음대로 정리하기
앱 카드에 마우스를 올리면 두 가지가 나타납니다.
- 별(★) — 맨 앞에 고정합니다. 자주 쓰는 것을 위로 올려 두세요.
- × — 첫 화면에서 안 보이게 합니다. 권한이 없어지는 게 아니라 내 화면에서만 숨는 것 입니다. 숨긴 것이 있으면 목록 오른쪽에 숨긴 앱 N개 가 생기고, 거기서 되돌릴 수 있습니다.
보이는 앱은 사람마다 다릅니다. 부서와 개인별로 열어 준 것만 보입니다. 필요한 앱이 안 보이면 IT 담당자에게 말씀해 주세요 — 고장이 아니라 아직 안 열어 준 것입니다.
1.3챗으로 물어보기
앱을 하나씩 열지 않아도, 아래 입력창에 우리말로 물어보면 챗이 알아서 해당 앱에 물어보고 답합니다.
| 화면에 뜨는 것 | 뜻 |
|---|---|
| 생각하는 중 | 질문을 읽고 무엇을 할지 고르는 중입니다. |
| ✓ 자산 현황 조회 | 자산관리 앱에 실제로 물어봤다는 뜻입니다. 기능 이름이 한글로 나옵니다. |
| ↗ 바로가기 | 그 내용을 자세히 볼 수 있는 화면으로 바로 갑니다. 물어본 내용에 맞는 화면 이 열립니다 — 자리를 물었으면 자리 배치가 열립니다. |
| 사용한 기능: … | 어떤 기능과 어떤 AI 모델을 썼는지. 답이 이상할 때 담당자에게 알려주시면 좋습니다. |
파일 올려서 물어보기
입력창 왼쪽 클립 을 누르거나, 화면 아무 데나 파일을 끌어다 놓으면 첨부됩니다.
- 되는 것 —
pdfdocxxlsxcsvtxt와 사진 - 안 되는 것 — 한글(.hwp), 옛날 오피스(
.doc.xls.ppt) - 같은 파일을 두 번 올리면 새로 저장하지 않고 앞의 것을 씁니다.
첨부한 파일의 내용은 AI 공급자로 넘어갑니다. 사진도 마찬가지입니다 — 명함, 신분증, 화이트보드 사진이 그대로 넘어간다는 뜻입니다. 곤란한 자료는 전용 앱(사업계획 등)을 쓰시거나 담당자와 상의해 주세요.
기억해 두라고 하기
「앞으로 답변 짧게 해줘, 기억해둬」 처럼 말하면 저장해 두고 다음 대화에도 씁니다. 확인은 「내가 뭐 기억해달라고 했었지?」, 지우기는 「그거 잊어줘」.
「기억해줘」 라고 말했을 때만 저장합니다. 챗이 알아서 판단해 쌓기 시작하면, 한 번 잘못 저장된 내용이 계속 되풀이해서 쓰이고, 왜 그렇게 답했는지 나중에 찾기가 어려워집니다.
대화 지우기
왼쪽 목록에서 대화에 마우스를 올리면 × 가 나옵니다. 지우면 그 대화의 질문과 답이 모두 사라지고 되돌릴 수 없습니다.
1.4이렇게 물어보세요
실제로 되는 질문만 모았습니다. 똑같이 안 쓰셔도 되고, 비슷하게 말씀하시면 알아듣습니다. 권한이 없는 앱의 질문은 답하지 않습니다.
| 무엇을 | 이렇게 |
|---|---|
| 내 계정·시각 | 「지금 몇 시야?」 · 「내 부서 뭐야?」 · 「나 관리자 권한 있어?」 |
| 쓸 수 있는 앱 | 「무슨 앱 쓸 수 있어?」 · 「어디서 신청해?」 · 「자산 관련 앱 어디야?」 |
| 업무 시스템 사용법 | 「샘플 ERP 접속 어떻게 해?」 · 「그룹웨어 사용법 어디 나와 있어?」 · 「무슨 매뉴얼 있어?」 |
| IT 운영 업무 | 「이번 달 뭐 해야 해?」 · 「분기 업무 알려줘」 · 「유지보수 업체 연락처 알려줘」 |
| 내 장비·자산 | 「내 장비 알려줘」 · 「지금 자산 몇 대야?」 · 「보관 중인 노트북 뭐 있어?」 |
| 사람 찾기 | 「강주진 어디 앉아?」 · 「내 옆자리 누구야?」 · 「3층에 누가 앉아?」 |
| IP · 내선 | 「서채희 IP 뭐야?」 · 「신윤성 내선번호 알려줘」 · 「전체 IP 사용 현황 알려줘」 |
| 라이선스 | 「곧 만료되는 라이선스 있어?」 · 「우리 무슨 소프트웨어 쓰고 있어?」 |
| AI 사용량 | 「이번 달 AI 비용 얼마야?」 · 「누가 AI 제일 많이 썼어?」 · 「5월 AI 사용량 좀」 |
| 온라인 교육 | 「나 교육 다 들었어?」 · 「아직 안 들은 사람 누구야?」 |
| 사업계획 손익 | (파일 2개 첨부 후) 「예상손익 뽑아줘」 · 「채널별 손익 어떻게 나와?」 |
| 사내앱 만들기 | 「사내앱 만들 때 내가 신경 써야 할 게 뭐야?」 · 「MCP가 뭐야?」 |
| 아무 문서나 | (파일 첨부 후) 「이 파일 요약해줘」 · 「이 사진에 뭐라고 적혀 있어?」 |
챗은 답변 본문에 /it-asset/ 같은 주소를 적지 않습니다.
대부분은 그 주소를 봐도 무엇을 해야 할지 모르고,
오히려 답이 잘못 나온 것처럼 보이기 때문입니다.
대신 답 아래에 바로가기 버튼이 붙습니다.
1.5앱 하나씩 보기
지금 붙어 있는 앱입니다. 권한을 받은 것만 보입니다. 목록에 없는 앱은 담당자에게 요청하세요.
IT 자산 관리
/it-asset/IT팀회사 장비·직원·IP·내선·소프트웨어·라이선스·자리 배치를 한곳에서 관리합니다. 왼쪽 메뉴가 대시보드 · 직원별 현황 · 자리 배치 · 자산 등록 · 직원 명단 · IP 관리 · 내선 관리 · 소프트웨어 · 렌탈 · 권한 으로 나뉩니다.
신규 입사자가 오면 — 입사 처리
직원 등록부터 장비·IP·내선·라이선스까지 한 창에서 끝납니다. 직원 명단 또는 직원별 현황 툴바의 + 입사 처리 를 누르세요.
IP 와 소프트웨어는 「고른 자산」에 붙습니다. 2번에서 자산을 안 고르면 3번 IP 와 6번 소프트웨어는 건너뜁니다. 나중에 줄 것은 직원별 현황에서 그 사람을 눌러 이어서 하시면 됩니다.
퇴사할 때는 반대로, 직원별 현황에서 그 사람을 눌러 퇴사 처리 하나면 보유 자산·IP·라이선스가 모두 회수 됩니다.
IT 매뉴얼
/manual/전 직원ERP · NAS · 그룹웨어 · M365 · 카스퍼스키 등 업무 시스템 사용법을 화면 사진과 함께 단계별로 봅니다. 챗에서 「ERP 접속 어떻게 해?」 라고 물으면 그 항목으로 바로 갑니다.
IT 운영 체크리스트
/checklist/전 직원수시 · 매일 · 월간 · 분기 · 연간으로 나눈 IT 운영 업무와 유지보수 항목입니다.
ITO 비용처리
/ito-cost/IT팀월별 유지보수·이용료 정산 항목을 업체별로 확인하고 체크합니다.
바이브코딩 프롬프트 생성기
/prompt/전 직원AI 로 사내 프로그램을 만들 때 쓰는 문장을 빈칸만 채워 완성해 줍니다. 회사 표준 규칙이 이미 들어 있어서, 완성된 문장을 복사해 붙여넣기만 하면 됩니다.
AI 리포트
/ai-report/IT팀AI 사용량 엑셀을 올리면 월별 요금·사용 인원·사용자 순위를 보여 줍니다.
사업계획 예상손익
/biz-plan/경영지원팀 · 재무팀마스터 양식과 매출목표·비용 파일 두 개를 올리면 예상손익을 계산합니다. 파일은 저장하지 않고 계산이 끝나면 바로 버립니다.
매출목표의 채널 이름 과 마스터의 고객그룹 이름 이 한 글자라도 어긋나면 그 채널 매출이 통째로 빠집니다. 그래서 이 앱은 이름이 안 맞으면 숫자를 아예 안 보여 주고 무엇이 안 맞는지 먼저 알려 줍니다. 표가 안 나오면 고장이 아니라 걸러진 것 입니다.
연차 이상감지
/leave-anomaly/인사총무팀연차 사용·발생 엑셀로 고립연차 · 저사용(쌓아두기) · 급증 세 가지를 함께 봅니다.
온라인 교육
/edu/전 직원지정된 영상을 보면 진도가 기록되고 자동으로 이수 처리됩니다. 담당자는 같은 화면의 담당자 화면 에서 전사 이수 현황을 봅니다.
매뉴얼 가져오기
/manual-import/담당자 전용PowerPoint 로 만든 자료를 올리면 IT 매뉴얼로 바꿔 줍니다.
앱 입고
/intake/전 직원 · 승인은 담당자만든 앱을 올리면 사내 표준 규칙에 맞는지 켜기 전에 검사하고, 통과하면 담당자에게 검토 요청이 갑니다. 담당자는 원본을 받아 승인하거나 반려합니다. ✗ 가 하나라도 있으면 요청 버튼이 열리지 않고, 대신 무엇을 어떻게 고치면 되는지를 그대로 붙여넣을 수 있는 글로 만들어 줍니다. 자세한 것은 2.7 새 앱 붙이기.
사내앱 규칙
/rules/전 직원사내 웹앱을 만들 때 지켜야 할 규칙을 한눈에 봅니다. 빨간색으로 표시된 것만 사람이 판단해야 하고, 나머지는 프롬프트 생성기가 알아서 넣어 줍니다.
AI 참고자료
/ai-ref/전 직원AI 용어 · 프롬프트 예시 · 바이브코딩 입문을 한 곳에서 찾습니다.
1.6안 될 때
| 이런 일이 생기면 | 이렇게 하세요 |
|---|---|
| 「이 서비스를 이용할 권한이 없습니다」 | 아직 안 열어 준 앱입니다. IT 담당자에게 앱 이름 과 왜 필요한지 를 알려주세요. |
| 갑자기 로그인 화면으로 나감 | 로그인이 12시간 지나 풀린 것입니다. 다시 로그인하시면 됩니다. 지난 대화는 그대로 있습니다. |
| 비밀번호를 잊음 | 스스로 찾을 수 없습니다. IT 담당자에게 초기화를 요청하세요. 새 비밀번호는 첫 로그인 때 본인이 바꿉니다. |
| 파일이 안 올라감 | 확장자를 먼저 보세요 — 한글(.hwp) 과 옛날 오피스는 안 됩니다. 용량이 크면 시간이 걸립니다. |
| 답이 이상하거나 엉뚱함 | 답 아래 사용한 기능 이름과 질문을 그대로 담당자에게 알려주세요. 그 기능의 설명을 고치면 다음부터 정확해집니다. |
| 화면이 옛날 그대로 | Ctrl + Shift + R 로 새로고침해 보세요. |
| 앱 카드가 사라짐 | 실수로 × 를 눌러 숨겼을 수 있습니다. 앱 목록 오른쪽 숨긴 앱 N개 에서 되돌리세요. |
| 전부 안 열림 · 502 | 서버 문제일 수 있습니다. IT 담당자에게 알려주세요. |
2부
담당자용 — 운영하는 법
구조 · 권한 · 배포 · 새 앱 붙이기 · 장애 대응. 인수인계 때 이 부분만 넘겨도 되도록 썼습니다.
2부의 화면 사진에는 전 직원의 계정 목록 · 개인별 AI 사용량 · 직원이 챗에 물어본 내용 이 그대로 들어 있습니다. 이 문서를 포탈에 올릴 때 전 직원 공개로 두지 마세요. 1부만 공개하시려면 2부를 잘라 낸 사본을 따로 올리시는 편이 안전합니다.
2.1전체가 어떻게 물려 있나
앱마다 폴더와 컨테이너가 따로 있고, 앞에 nginx 하나가 서서 주소 하나로 묶습니다. 권한 판정은 언제나 포탈 한 곳이 합니다.
하나의 큰 compose 로 묶으면 앱 하나를 고칠 때마다 전부 재시작하게 됩니다.
대신 모두 같은 도커 네트워크(demo-net)에 붙어 서로 이름으로 부릅니다.
2.2권한이 정해지는 법
화면 목록, 앱 런처, 챗 도구 노출, 도구 실행 — 전부 같은 함수 하나 를 거칩니다. 판정이 여러 군데로 흩어지면 「화면엔 보이는데 챗에선 안 된다」 가 생기고, 그게 가장 위험합니다.
쓸 수 있나 (can_use) — 위에서부터 순서대로
| 순서 | 조건 | 결과 |
|---|---|---|
| 1 | 허용 IP 가 정해져 있는데 다른 IP 에서 들어옴 | 불가 · 관리자도 |
| 2 | 서비스가 중지 상태 | 불가 · 관리자도 |
| 3 | 포탈 관리자 | 가능 |
| 4 | 제외 명단에 있음 | 불가 · 부서가 허용이어도 |
| 5 | 접근 범위가 전 직원 | 가능 |
| 6 | 개인 허용 명단에 있음 | 가능 |
| 7 | 내 부서가 허용 부서에 있음 | 가능 |
| 8 | 그 외 | 불가 |
IP 제한 과 사용 중지 두 가지는 관리자도 못 뚫습니다. 관리자 계정으로 열었는데 「권한이 없습니다」 가 뜬다면 그 둘 중 하나입니다.
관리할 수 있나 (담당자)
「쓸 수 있다」와 「관리할 수 있다」는 다릅니다. 부서 전체가 리포트를 볼 수 있어도, 남이 올린 파일을 지우는 것은 담당자만 합니다.
- 포탈 관리자는 명단에 없어도 항상 담당자 로 봅니다 — 담당자가 퇴사했을 때 아무도 손댈 수 없게 되는 상황을 막습니다.
- 그 밖에는 그 서비스의 담당자 명단에 있는 사람만.
로그인 토큰 안의 값만 믿으면, 관리자 권한을 회수해도·부서를 바꿔도·퇴사 처리를 해도 토큰이 만료되는 12시간 동안 예전 권한이 그대로 삽니다. 그래서 매번 다시 조회합니다.
2.3관리자 화면
오른쪽 위 톱니 → 관리자 페이지 또는 /admin. 탭 다섯 개입니다.
서비스 관리
- 「설정 필요」 — 앱이 뜨면서 스스로 등록만 해 둔 상태입니다. 아직 아무에게도 안 보입니다. 접근 범위 정하고 켜기 를 누르면 범위를 정하면서 그대로 켜집니다.
- 「아무도 못 봄」 — 켜져 있는데 볼 수 있는 사람이 없는 상태입니다. 관리자에게는 범위와 상관없이 보이기 때문에 눈으로는 절대 못 잡습니다. 그래서 이름표를 붙였습니다.
- 접힌 줄에도 접근 범위 요약이 함께 나옵니다 — 그것 때문에 펴는 일이 제일 많아서입니다.
| 칸 | 뜻 |
|---|---|
| 전 직원 | 계정이 있으면 누구나. |
| 부서 · 개인 선택 | 팀 전체면 팀을 체크. 몇 명만이면 명 수 를 눌러 펼치고 그 사람만 체크. 팀을 체크한 뒤 한 사람만 체크를 풀면 그 사람만 제외됩니다. |
| 개인 지정 | 위에서 체크한 사람이 모입니다. 다른 부서 사람은 여기서 이름으로 찾아 넣습니다. |
| 허용 IP | 비우면 제한 없음. 넣으면 관리자도 그 IP 밖에서는 못 씁니다. |
| 담당자 | 파일 삭제 등 되돌릴 수 없는 동작. 접근 범위와는 별개라, 전 직원 공개 앱에도 담당자를 둘 수 있습니다. |
포탈 관리자에게는 이 설정과 상관없이 모든 앱이 보입니다. 체크를 풀어도 그대로 보이므로, 관리자가 아닌 계정으로 확인하셔야 합니다.
사용자 명부
부서 관리
이력
합쳐서 한 표로 그리면 직원이 무엇을 물었는지가 관리자 눈에 그대로 들어옵니다. 봐야 할 이유가 있을 때만 들어가도록 자리를 나눴습니다.
AI 사용량
금액은 .env 의 USAGE_PRICES 로 계산한 값입니다.
공급자 청구서와 다르면 단가부터 확인하세요. 단가를 안 적으면 토큰 수만 나옵니다.
그림 읽기 입니다. 엑셀 하나를 열었을 뿐인데 안에 붙은 캡처 다섯 장이 통째로 넘어갑니다. 사용량이 갑자기 튀면 여기부터 보세요.
2.4계정 관리
한 명 만들기
- 부서 관리 에서 부서가 있는지 먼저 봅니다. 없으면 만듭니다.
- 사용자 명부 → + 사용자 추가. 아이디·이름·부서를 넣고 비밀번호는 자동 을 쓰세요.
- 만들어진 초기 비밀번호를 그 자리에서 복사해 전달합니다. 이 화면을 닫으면 다시 볼 수 없습니다.
「영업1팀」과 「영업 1팀」이 갈라지기 때문입니다. 부서 이름은 접근 범위 판정의 기준이라, 표기가 하나 갈라지면 그 순간 권한이 둘로 쪼개집니다.
여러 명 한 번에
사용자 명부 → 한 번에 등록. 양식을 내려받아 채운 뒤 올리면 검사 결과를 먼저 보여 주고, 한 번 더 눌러야 실제로 만들어집니다. 최대 2000명.
- 명부에는 있는데 포탈에 없는 부서는 자동으로 만들지 않습니다. 함께 만들기 를 체크해야 만듭니다.
- 등록이 끝나면 초기 비밀번호를 CSV 로 내려받을 수 있습니다. 그 화면에서만 볼 수 있습니다.
초기화 · 중지 · 삭제
| 무엇 | 언제 | 일어나는 일 |
|---|---|---|
| 비밀번호 초기화 | 비밀번호를 잊었을 때 | 새 초기 비밀번호가 나옵니다. 첫 로그인 때 본인이 반드시 바꾸게 됩니다. |
| 중지 | 휴직 · 장기 출장 | 로그인만 막힙니다. 계정·대화·파일은 그대로 있고 언제든 되살립니다. |
| 삭제 | 퇴사 | 되돌릴 수 없습니다. 대화·파일·기억까지 지울지는 별도 체크박스로 고릅니다. |
계정을 지우면 접근 범위와 담당자 명단에서도 함께 빠집니다. 이건 청소가 아니라 보안 문제입니다 — 안 빼면 나중에 같은 아이디로 계정을 다시 만들었을 때 그 사람이 앞사람 권한을 그대로 물려받습니다. (포탈이 자동으로 처리하지만, 다른 앱에도 명단이 있으면 그쪽은 직접 확인하셔야 합니다)
안전장치로 마지막 관리자 는 권한 회수·삭제·중지가 안 되고, 본인 계정 은 스스로 삭제·중지할 수 없습니다.
2.5배포하기
내 PC 에서 먼저 띄워 확인하고 → 깃에 올리고 → 서버가 당겨서 띄웁니다.
윈도우는 .ps1, 서버는 .sh 로 이름과 쓰는 법이 같습니다.
내 PC (PowerShell)
.\deploy.ps1 전부 띄우기
.\deploy.ps1 it-asset 하나만
.\deploy.ps1 portal proxy 여럿
.\demo.ps1 데모 자료까지 만들어 넣고 띄우기
.\demo.ps1 -Reseed 자료만 다시 만들어 넣기
.py · .js · .html 을 고쳤으면 반드시 .\deploy.ps1 <앱> 를 돌려야 합니다.
앱들은 소스를 이미지 안에 구워 넣습니다(Dockerfile 의 COPY app ./app).
파일만 고치고 컨테이너를 그대로 두면 아무 일도 일어나지 않습니다.
씨앗을 고쳤을 때
*/seed_demo.py, tools/*.py 처럼 처음 화면을 만드는 코드 를 고쳤을 때만 해당합니다.
docker exec -i demo-edu python -m app.seed_demo --force
빌드를 먼저, 씨앗을 나중에. 반대로 하면 컨테이너 안의 옛 코드가 돌아서
고친 것이 반영되지 않습니다. --force 를 안 붙이면
「이미 자료가 있습니다」 하고 그냥 나갑니다.
올리기 전에 스스로 거는 검사
.githooks/pre-push 가 git push 때 자동으로 돕니다.
한 번만 git config core.hooksPath .githooks 를 해 두면 PC 를 바꿔도 따라옵니다.
| 검사 | 무엇을 잡나 |
|---|---|
tools/check_workflow.py | 워크플로 YAML 문법, 잡 이름이 ASCII 인지, ${{ }} 가 짝이 맞는지. GitHub 은 run: 안의 주석까지 파싱합니다 — 주석에 ${{ }} 를 적으면 파일 전체가 거부됩니다. |
tools/check_secrets.sh --strict | 실명·사내 고유명사가 섞여 들어갔는지. .secretwords 가 없으면 통과가 아니라 실패 로 봅니다. |
tools/company.py --check | 바꾸기 전 회사 이름이 어딘가 남아 있는지. |
tools/check_demo.py | 체험판 잠금이 제대로 걸려 있는지. |
깃에 올리기
git status 무엇이 바뀌었는지 먼저
git add -A
git commit -m "무엇을 왜 고쳤는지"
git push
git add 가 조용히 실패하면 git commit 은 상태만 찍고 아무것도 안 만듭니다.
그 상태로 git push 하면 바로 앞 커밋만 올라갑니다.
commit 출력에 해시 줄이 있는지 눈으로 보세요.
서버 (/srv/portal)
깃에 올라가면 서버는 두 가지 중 하나로 받습니다.
| 방식 | 어떻게 | 언제 씀 |
|---|---|---|
| 밀기 · GitHub Actions | push 하면 워크플로가 검사(check)를 먼저 돌리고, 통과하면 SSH 로 서버의 배포를 부릅니다. 서버 키는 authorized_keys 에 강제 명령으로 묶여 있어 셸을 열지 못합니다. | 기본. 밀어 넣은 지 1분 안에 반영 |
| 당기기 · systemd 타이머 | autodeploy.sh 가 5분마다 깨어 git fetch 로 바뀐 게 있는지만 봅니다. 있으면 받고 띄우고, 실패하면 앞 커밋으로 되돌립니다. | 깃허브에서 서버로 들어올 수 없을 때 |
./preflight.sh 받을 준비가 됐는지. 아무것도 바꾸지 않는다
./deploy.sh 당기고 + 다시 만들고 + 띄운다
./demo.sh --behind 자료가 비었을 때. --behind 를 빼면 포트 설정이 덮어써져 502
autodeploy.sh 가 git pull 로 자기 자신을 받아도,
이미 읽어 둔 옛 바이트로 계속 돕니다. 그래서 고친 것이 영영 반영되지 않습니다.
받은 뒤 자기 해시가 바뀌었으면 exec 로 새 것을 다시 띄우게 했습니다.
(환경변수 하나로 되풀이를 막습니다)
제대로 떴는지
docker ps 상태 보기
curl -s localhost:8081/health {"ok":true} 가 나와야 정상
docker exec demo-proxy nginx -t nginx 설정 문법
docker logs demo-asset-api --tail 40 그 앱 로그
docker ps 의 PORTS 칸에 값이 있는 것은 demo-proxy 하나뿐이어야 합니다.
다른 앱에 포트가 열려 있으면 포탈의 권한 검사를 건너뛰고 바로 들어올 수 있는 길이 생긴 것입니다.
주인 전용 입구
공개용 입구(80)에는 체험판 잠금이 걸려 있어 내용을 고칠 수 없습니다.
고칠 때는 루프백에만 열린 8082 로 들어갑니다.
ssh -L 8082:127.0.0.1:8082 <계정>@<서버주소>
# → 브라우저에서 http://127.0.0.1:8082/
비밀번호를 하나 더 두면 그 비밀번호를 어딘가에 적어 두게 됩니다.
127.0.0.1:8082 는 바깥 랜카드에 아예 붙지 않아서,
서버에 SSH 로 들어올 수 있는 사람만 지나갈 수 있습니다.
이미 있는 열쇠 하나를 다시 쓰는 것이라 관리할 비밀이 늘지 않습니다.
2.6.env 항목
portal/.env 의 주요 항목입니다. 깃에 올라가지 않으므로 서버 값은 서버에서 직접 고칩니다.
고친 뒤에는 ./deploy.sh portal 로 컨테이너를 다시 만들어야 반영됩니다.
| 항목 | 무엇 |
|---|---|
OPENAI_API_KEYOPENAI_BASE_URLMODEL | AI 공급자 연결. 키를 바꿀 일이 제일 잦습니다. |
MAX_TOKENS | 답변 최대 길이. 작으면 답변이 비어서 옵니다 — gpt-5 계열은 추론에 쓰는 몫까지 이 한도를 나눠 씁니다. |
JWT_SECRET | 로그인 서명키. 유출되면 누구나 로그인할 수 있습니다. 서버와 로컬은 반드시 다른 값이어야 합니다. |
JWT_EXPIRE_HOURS | 로그인 유지 시간. 기본 12시간. |
AUDIT_TOKEN | 옆 앱들이 포탈에 이력을 보낼 때 쓰는 공용 열쇠. 모든 앱이 같은 값이어야 합니다 — setup 이 맞춰 줍니다. |
COOKIE_SECURE | https 면 1, http 면 0. http 에서 1 로 두면 쿠키가 저장되지 않아 로그인이 계속 풀립니다. |
CHAT_LOG_TEXT | on 이면 질문·답변 원문까지 이력에 남깁니다(관리자만 열람). off 면 누가·언제·어떤 기능만. |
CHAT_LOG_DAYS / CHAT_KEEP_DAYS | 사용 기록 90일 / 대화 내역 365일. 0 이면 무기한. |
UPLOAD_MAX_MB | 첨부 최대 용량. 지금 120 입니다(코드 기본값은 20 이라, 이 줄이 비면 20MB 로 떨어집니다). nginx 쪽 한도도 같이 올려야 합니다 — 한쪽만 올리면 413. |
VISION | 사진·스캔 PDF 읽기. 켜면 사진이 통째로 AI 공급자로 나갑니다. 곤란하면 off. |
USAGE_PRICES | 모델별 100만 토큰당 단가(원). 적어야 관리자 화면에 금액이 나옵니다. |
DEMO_MODE | 체험판 잠금. 1 이면 쓰기 동작이 막히고 체험판 표시가 붙습니다. 주인 전용 입구(8082)로 들어오면 헤더 하나로 통과합니다. |
*_API / *_URL | 각 앱의 안쪽 주소와 직원용 주소. 안쪽은 컨테이너 이름(demo-asset-api), 바깥은 경로(/it-asset/)입니다. |
2.7새 앱 붙이기
다른 팀이 만들어 보낸 앱을 포탈에 붙이는 전체 순서입니다.
- 켜기 전에 점검합니다. 앱 입고 화면에 zip 을 올리면
브라우저 저장만 쓰는지, 절대경로로 부르는지, 삭제 코드가 있는지,
.env가 딸려 왔는지를 봅니다. 아무것도 바꾸지 않습니다. ✗ 가 하나라도 있으면 요청 버튼이 안 열립니다 - 만든 팀이 고칠 내용 프롬프트 를 받아 고쳐서 다시 올립니다. △ 는 켜되 만든 팀에 알립니다. - 검토 요청을 받습니다. 통과한 것만 담당자 화면(
/intake/admin)에 줄을 섭니다. 포탈 첫 화면의 앱 카드에도 기다리는 건수가 빨간 숫자로 붙습니다. 원본 zip 을 받고, 서비스 ID 가 포탈에 이미 있는 것인지(다시 배포면 그대로, 새 앱이면 등록·권한·nginx 까지) 확인한 뒤 승인하거나 반려합니다. - 폴더를 넣습니다.
portfolio/<서비스ID>/.docker-compose.yml에container_name이 있고demo-net에 붙어 있고ports는 없는지 확인합니다. - 로컬에서 띄웁니다.
.\deploy.ps1 <서비스ID> - 주소를 냅니다.
cd proxy→.\new-app.ps1 <서비스ID>가apps/<서비스ID>.conf를 만들어 줍니다. 안쪽 포트는 보통8080, nginx 로 화면만 주는 앱은80입니다. 틀리면 502. 그리고.\deploy.ps1 proxy. - 확인합니다.
http://localhost:8090/<서비스ID>/ - 깃에 올립니다. 서버는 알아서 받습니다.
- 관리자 화면에서 켭니다. 앱은 뜨면서 스스로 등록만 하고 스스로 켜지지는 않습니다. 접근 범위 정하고 켜기 로 범위를 정하면서 켭니다.
- (선택) 챗에서도 쓰게 합니다. 다음 절 참고.
앱의 AUDIT_TOKEN 이 포탈과 한 글자라도 다르면 자기 등록이 403 으로 막힙니다.
화면에는 아무 단서도 안 남고, 그냥 관리자 화면에 안 뜰 뿐입니다.
./setup.sh 를 한 번 돌리고 다시 배포하세요.
2.8챗 도구 추가
앱 화면만 붙이면 직원이 직접 들어가야 합니다. 챗에서도 물어보게 하려면 도구 파일 하나 를 더 만듭니다.
portal/app/tools/_파일도구_본보기.py.txt를portal/app/tools/<서비스ID>.py로 복사합니다.- 파일 안 ■ 표시 다섯 곳 을 고칩니다 — 앱 API 주소, 직원이 갈 화면 주소,
도구 이름(영문), 설명,
serviceid. portal/app/main.py의from .tools import ...줄에 새 모듈을 넣습니다..env에 그 앱의 API 주소를 넣고./deploy.sh portal.
service id 는 관리자 화면에 등록된 서비스 ID 와 반드시 같아야 합니다.
이 값이 곧 그 도구의 권한 범위가 됩니다. 관리자 화면에서 접근 범위를 바꾸면
챗 도구 노출도 즉시 함께 바뀝니다.
description 이 정확도를 가장 크게 좌우합니다.
무엇을 조회하는지 · 사용자가 어떤 표현으로 물을 때 쓰는지(동의어 포함) ·
언제 쓰면 안 되는지 까지 적으세요.
직원이 실제로 어떻게 묻는지는 관리자 화면 이력 → 채팅 이력 에서 봅니다.
예전에 포탈이 엑셀을 직접 읽어 계산하게 짜 놓고 보니, 대시보드 화면과 챗이 서로 다른 금액을 말하고 있었습니다. 앱이 자기 숫자를 책임지고 포탈은 전달만 하면 이 문제가 생기지 않습니다. 새 앱을 붙이는 일도 「API 하나 부르는 도구 파일 하나 추가」로 끝납니다.
확장자가 .py.txt 인 이유가 있습니다 — app/tools/ 안의 .py 는
자동으로 진짜 도구로 등록되기 때문에, 본보기가 그대로 섞이면
존재하지 않는 서비스를 챗이 부르게 됩니다.
2.9자주 나는 문제
| 증상 | 원인과 해결 |
|---|---|
| 앱이 관리자 화면에 안 뜬다 | 그 앱의 AUDIT_TOKEN 이 포탈과 다릅니다. 화면에 단서가 안 남습니다. ./setup.sh → ./deploy.sh. |
| 코드를 고쳤는데 화면이 그대로 | 그 앱은 코드가 이미지 안에 구워져 있습니다. restart 가 아니라 ./deploy.sh <앱> 로 다시 빌드해야 합니다. |
| 씨앗을 고쳤는데 옛 내용이 다시 살아난다 | 빌드 없이 씨앗만 다시 심었습니다. 컨테이너 안의 옛 코드가 돈 것입니다. 빌드 먼저. |
| 화면에서 지웠는데 서버엔 그대로 | data/ 는 .gitignore 에 있어 DB 가 깃에 안 올라갑니다. 씨앗 코드를 고쳐야 서버까지 갑니다. |
.env 를 고쳤는데 안 바뀐다 | 환경변수는 컨테이너를 만들 때 박힙니다. docker restart 로는 안 바뀝니다. ./deploy.sh. |
| nginx 설정을 고쳤는데 반영이 안 된다 | 문법 오류가 있으면 nginx 가 옛 설정을 그대로 물고 정상인 척합니다. docker exec demo-proxy nginx -t 로 확인하세요. |
| 502 | 컨테이너가 안 떴나 → demo-net 에 안 붙었나 → 포트가 어긋났나 → nginx 가 설정을 다시 안 읽었나, 순서대로 짚습니다. |
| 404 인데 파일은 분명히 있다 | nginx 는 뜰 때 설정을 한 번만 읽습니다. ./deploy.sh proxy 가 다시 읽혀 줍니다. |
| 413 · 파일이 너무 큼 | 한도가 앱과 nginx 양쪽에 걸려 있습니다. 앱별 conf 가 공통 설정을 이깁니다. proxy/apps/<앱>.conf 의 client_max_body_size 를 보세요. |
| healthcheck 가 계속 unhealthy | 컨테이너 안에서 localhost 는 IPv6 로 먼저 풀리는데 앱이 IPv4 로만 듣는 경우입니다. 127.0.0.1 로 바꾸세요. |
| 로그인은 되는데 새로고침하면 풀린다 | COOKIE_SECURE=1 인데 http 로 접속 중입니다. http 인 동안은 0. |
| 서버에서만 죽고 내 PC 에서는 멀쩡하다 | 깃에 안 올라간 파일을 main.py 가 부르고 있을 수 있습니다. docker logs demo-portal --tail 40 으로 ImportError 를 확인하세요. |
서버 git pull 이 local changes 로 막힌다 | 서버에서 파일을 직접 고쳤다는 뜻입니다. 서버는 받기만 하는 곳입니다. git checkout -- <그 파일> 로 되돌리고 다시 배포하세요. |
| 배포가 계속 되돌려진다(rollback) | 건강 확인 주소가 틀렸을 수 있습니다. autodeploy.sh 의 로그에 실제로 두드린 주소가 찍힙니다 — 포트가 두 번 붙어 있지 않은지 보세요. |
| 워크플로가 「An expression was expected」로 거부된다 | run: 블록 안의 주석에 ${{ }} 를 적었습니다. GitHub 은 주석도 파싱합니다. tools/check_workflow.py 가 올리기 전에 잡아 줍니다. |
| 「Internal Server Error」 만 뜬다 | 앱이 예외를 그대로 흘린 것입니다. docker logs <컨테이너> --tail 40 에 스택트레이스가 남아 있습니다. 로그부터 보세요. |
| 관리자 계정으로 못 들어감 | 서버 SSH 로만 복구됩니다. sqlite3 로 DB 를 직접 고치지 마세요 — 비밀번호 해시 방식이 어긋나 영영 못 들어갑니다. 앱의 관리 명령을 쓰세요. |
2.10백업과 보관 기간
portal/data/ 이 폴더 하나입니다. 사라지면 계정이 전부 사라집니다.
(앱별 데이터는 각 앱의 data/ 에 따로 있습니다 —
특히 it-asset/data/app.db 는 자산·직원 명부입니다.)
| 무엇 | 어디 |
|---|---|
| 계정 | portal/data/users.db |
| 부서 · 서비스 · 접근 범위 | portal/data/portal.db |
| 대화 · 기억 · 이력 · 사용량 | portal/data/memory.db |
| 챗 첨부파일 | portal/data/uploads/YYYYMM/ |
| 자산 · 직원 · 자리 | it-asset/data/app.db |
| 교육 과정 · 진도 | edu/data/app.db |
| 매뉴얼 원고 · 그림 | it-guide/web/manuals/ |
스스로 지워지는 것
| 무엇 | 기간 | 설정 |
|---|---|---|
| 챗 사용 기록 (질문·답변 원문) | 90일 | CHAT_LOG_DAYS |
| 대화 내역 | 365일 | CHAT_KEEP_DAYS |
| AI 사용량 | 180일 | USAGE_KEEP_DAYS |
| 포탈에 남은 첨부 사본 | 30일 | UPLOAD_KEEP_DAYS |
첨부 사본만 30일인 이유는, 앱 쪽 사본은 이 규칙과 무관 하기 때문입니다. 그 앱의 담당자는 그 앱 화면에서 전부 볼 수 있고, 그건 그 앱의 접근 범위가 정합니다.
A앱 · 주소 · 컨테이너
| 앱 | 주소 | 컨테이너 | 데이터 |
|---|---|---|---|
| 포탈 | / | demo-portal | portal/data/ |
| 프록시 | — | demo-proxy | — |
| IT 자산 관리 | /it-asset/ | demo-asset-api · demo-asset-web | it-asset/data/app.db |
| IT 매뉴얼 | /manual/ | demo-guide-web | 파일 자체 |
| IT 운영 체크리스트 | /checklist/ | demo-guide-web | 파일 자체 |
| ITO 비용처리 | /ito-cost/ | demo-guide-web | 파일 자체 |
| 바이브코딩 프롬프트 | /prompt/ | demo-guide-web | 파일 자체 |
| 사내앱 규칙 | /rules/ | demo-guide-web | 파일 자체 |
| AI 참고자료 | /ai-ref/ | demo-guide-web | 파일 자체 |
| AI 리포트 | /ai-report/ | demo-aireport | ai-report/data/ |
| 사업계획 예상손익 | /biz-plan/ | demo-biz-plan | 저장 안 함 |
| 연차 이상감지 | /leave-anomaly/ | demo-leave-anomaly | leave-anomaly/data/ |
| 매뉴얼 가져오기 | /manual-import/ | demo-manual-import | it-guide 폴더를 직접 씀 |
| 온라인 교육 | /edu/ | demo-edu | edu/data/ |
| 앱 입고 | /intake/ | demo-intake | 컨테이너 안에만 (다시 띄우면 사라짐) |
여기 나오는 회사 · 사람 · 부서 · 자산번호 · 금액은 전부 지어낸 것입니다.
기준은 tools/company.py 한 곳에 있어서, 그 파일 한 줄을 바꾸면
화면과 데이터 전체가 함께 따라옵니다.
화면이 바뀌면 이 문서도 함께 고쳐 주세요. 안 맞는 매뉴얼은 없는 것보다 나쁩니다.