저자 조봉수 · 봉수 SSGlobal(주) · ΦΡΥΚΤΩΡΙΑ ΠΛΗΡΟΦΟΡΙΩΝ · 2026-10-23 수업용(2026-10-22 준비)
실습 폴더: lesson05 (서버 server.py · 화면 web/customer.html·web/owner.html · step5_db_pandas.py · 정답 answers/)
AI 이용 고지: 이 교재와 실습 파일은 AI(Claude)와 함께 만들었습니다. 가게·메뉴는 예시입니다. 실습은 대표님 PC 안에서만 돌아가는 연습 서버입니다(인터넷 공개 아님).
목차
- 지난 시간 확인 — 대표님 4강 코드 리뷰
- 오늘의 질문
- 수업 진행표 (약 75분)
- 1단계 — 서버 켜기
- 2단계 — 창 두 개로 '같은 주문' 보기
- 3단계 — 휴대폰으로 주문하기
- 4단계 — 서버를 껐다 켜도 주문이 남는다
- 5단계 — 데이터베이스를 판다스로 읽기 (3강 복습)
- 6단계 — 내 손으로: '배달 완료' 상태 만들기
- 보안 맛보기 — 손님이 가격을 바꿔 보내면?
- 막혔을 때 — 자주 나는 오류
- 면접 대비 / 현업 적용 체크리스트
- 숙제와 다음 강
1. 지난 시간 확인 — 대표님 4강 코드 리뷰 (10분)
대표님이 저장한 lesson04\app_완성본_20261022.html을 함께 봅니다.
| 단계 | 대표님 결과 | 판정 |
|---|---|---|
| 2단계 가격 | 떡볶이 6,500원 | 통과 |
| 3단계 메뉴 추가 | 라면 5,000원(m4) | 통과 |
| 4단계 포장 할인 | 체크칸 + discount 계산, return 하나만 남김 |
통과 |
| 6단계 배달 출발 | ride() 함수, accepted일 때 버튼, riding → "배달 중" |
통과 — 정답을 안 주고 스스로 만듦 |
고칠 점은 두 가지뿐입니다(동작에는 문제 없음).
- 들여쓰기가 줄마다 조금씩 다릅니다(let discount, for (const o of orders)). 동작은 같지만 남이 읽기 어렵습니다 → 줄 맞추기 습관.
- ride() 안 주석이 [5단계]로 복사된 채입니다 → 복사한 뒤 주석도 고치기.
4강 숙제(품절 칸·오늘 매출)는 완성본에 아직 없습니다. '오늘 주문·오늘 매출'은 오늘 사장님 화면에 들어가 있으니 보고 따라 해 볼 수 있고, 품절 칸은 숙제로 그대로 남깁니다.
2. 오늘의 질문
4강 연습판의 주문은 내 브라우저에만 있었습니다. 그래서 휴대폰으로 주문하면 PC의 사장님 화면에 안 보였습니다. 오늘은 가운데에 서버를 하나 세워 이 문제를 풉니다.
손님 화면(휴대폰) ──주문──▶ ┌──────────────┐ ◀──3초마다 읽기── 사장님 화면(PC)
│ server.py │
│ + orders.db │ ──▶ 판다스로 매출 계산(5단계)
└──────────────┘
- 서버 = 주문 접수 창구. 주소(URL)마다 할 일이 정해져 있습니다. 이 약속을 API라고 부릅니다.
- 데이터베이스 = 오래 보관하는 장부. 오늘은 파일 하나짜리 SQLite(
orders.db)를 씁니다. 엑셀 표 한 장과 같습니다.
| 주소(API) | 뜻 |
|---|---|
GET /api/menu |
메뉴 주세요 |
POST /api/orders |
주문 받아 주세요 (장바구니를 보냄) |
GET /api/orders |
주문 목록 주세요 |
POST /api/orders/번호/status |
이 주문 상태를 바꿔 주세요 |
설치할 것이 없습니다. 파이썬에 원래 들어 있는 http.server와 sqlite3만 씁니다(5단계 판다스는 3강에서 이미 설치).
3. 수업 진행표 (약 75분)
| 시간 | 단계 | 할 일 | 확인할 것 |
|---|---|---|---|
| 0~10분 | 리뷰 | 4강 코드 함께 보기 | 위 표 |
| 10~15분 | 1단계 | 서버켜기.bat 더블클릭 |
검은 창에 주소 3줄 |
| 15~25분 | 2단계 | 손님·사장님 창 나란히 | 주문이 3초 안에 사장님 창에 뜸 |
| 25~35분 | 3단계 | 휴대폰으로 주문 | PC 사장님 창에 뜸 |
| 35~40분 | 4단계 | 서버 끄고 다시 켜기 | 주문이 그대로 |
| 40~50분 | 5단계 | python step5_db_pandas.py |
주문 수·매출 합계 |
| 50~65분 | 6단계 | '배달 완료' 직접 만들기 | 배달 중 → 배달 완료 |
| 65~75분 | 보안 | 가격 바꿔 보내기 시험 | 서버가 무시 |
규칙은 같습니다: 한 번에 하나만 바꾸고, 저장 → 확인. 오늘은 고칠 곳이 화면 파일이면 F5, server.py면 서버를 껐다 켜야 반영됩니다(검은 창에서 Ctrl+C → 서버켜기.bat 다시).
4. 1단계 — 서버 켜기
lesson05\서버켜기.bat더블클릭. 검은 창에 이렇게 나오면 성공입니다.
동네주문 서버가 켜졌습니다 (끄려면 이 창에서 Ctrl+C)
이 PC 손님 화면 : http://localhost:8000/customer.html
이 PC 사장님 화면 : http://localhost:8000/owner.html
휴대폰(같은 와이파이): http://192.168.x.x:8000/customer.html
- 처음 켤 때 Windows 방화벽 창이 뜨면 '개인 네트워크'만 체크하고 허용합니다(공용은 체크하지 않음).
- 검은 창은 닫지 않습니다. 창을 닫으면 서버가 꺼집니다.
5. 2단계 — 창 두 개로 '같은 주문' 보기
- 크롬에서
http://localhost:8000/customer.html(손님), 새 창에서http://localhost:8000/owner.html(사장님)을 열어 좌우로 놓습니다. - 손님 창에서 원조 김밥 1 + 떡볶이 1 → 주문하기.
- 손님 창:
주문 #… 접수! 서버가 계산한 금액 12,500원- 검은 창:[주문] #… 원조 김밥×1, 떡볶이×1 = 12,500원- 사장님 창: 3초 안에접수 대기줄이 생기고, '오늘 주문 1건 · 오늘 매출 12,500원' - 사장님 창에서 '접수' → '배달 출발'. 3초 뒤 손님 창 ③에 '조리 중' → '배달 중'이 따라 바뀝니다.
4강과 달라진 점은 단 하나: 주문 한 줄을 브라우저가 아니라 서버의 orders.db에 넣는다는 것. 그래서 두 창이 같은 줄을 봅니다.
6. 3단계 — 휴대폰으로 주문하기
- 휴대폰을 PC와 같은 와이파이에 연결합니다.
- 검은 창 세 번째 줄 주소(
http://192.168.…:8000/customer.html)를 휴대폰 브라우저에 그대로 칩니다. - 휴대폰에서 주문 → PC 사장님 창에 뜨면 성공. 이것이 플랫폼입니다: 앱 여러 개 + 가운데 서버 하나.
- 안 열리면 11절 '휴대폰이 안 열릴 때'를 봅니다. 회사·카페 와이파이는 기기끼리 막아 둔 경우가 많아 집 와이파이가 쉽습니다.
- 실제 수업(2026-10-25, 카페)에서 일어난 일: 서버가 알려 준 주소(
172.29.48.6)는ipconfig로 확인하니 진짜 와이파이 주소가 맞았지만 휴대폰에서 열리지 않았습니다(시험 1). 휴대폰 핫스팟에 PC를 붙이고 서버를 다시 켜자 새 주소172.20.10.7로 바로 열렸습니다(시험 2). 한 번에 하나만 바꿔 원인을 지우는 것 — 0교시 검증 습관 그대로입니다.
7. 4단계 — 서버를 껐다 켜도 주문이 남는다
- 검은 창에서 Ctrl+C(끄기) → 사장님 창이 더 이상 새로 받지 못합니다.
서버켜기.bat다시 → 사장님 창 F5 → 주문이 그대로 있습니다.- 탐색기에서
lesson05\orders.db파일이 생긴 것을 확인합니다. 주문 장부가 이 파일 하나에 들어 있습니다. - 4강 연습판은 브라우저 기록을 지우면 주문이 사라졌습니다. 데이터베이스는 파일이라 남습니다. (지우고 싶으면 서버를 끄고orders.db를 지우면 처음부터.)
8. 5단계 — 데이터베이스를 판다스로 읽기 (3강 복습)
lesson05에서 명령 프롬프트를 열고:
python step5_db_pandas.py
코드는 3줄이 핵심입니다.
df = pd.read_sql("SELECT * FROM orders", sqlite3.connect(DB)) # DB → 표
print("주문 수:", len(df), "건 · 매출 합계:", f"{df['total'].sum():,}원")
print(df.groupby("status")["total"].agg(["count", "sum"])) # 상태별 건수·금액
- 사장님 창의 '오늘 매출'과 숫자가 같은지 확인합니다. 다르면 데이터부터 봅니다 — 3강 원칙 그대로.
- 실제 수업(2026-10-25)에서 판다스가 찾은 것: 장부 7건·87,500원 중 6건이 어제 20초 사이(13:55:52~13:56:11) 들어온 똑같은 주문(김밥1+떡볶이1)이었고, 같은 초에 2건이 들어간 곳이 두 번 있었습니다. 화면이 늦게 바뀌어 버튼을 여러 번 누른 흔적입니다. 실제 서비스라면 카드 6번 결제, 김밥 6번 조리 — 그래서 6강에서 중복 주문 방지를 배웁니다.
| 시각(10-24) | 13:55:52 | 13:55:55 | 13:55:55 | 13:55:56 | 13:55:56 | 13:56:11 |
|---|---|---|---|---|---|---|
| 금액 | 12,500 | 12,500 | 12,500 | 12,500 | 12,500 | 12,500 |
| - 금융 데이터 일도 같습니다: 시스템(서버)이 쌓은 DB를 분석가가 판다스로 읽어 숫자를 만듭니다. |
9. 6단계 — 내 손으로: '배달 완료' 상태 만들기
지금은 '배달 중'에서 끝납니다. 배달 중 → 배달 완료(done)를 만듭니다. 이번에는 두 곳을 고칩니다.
1. 서버(server.py) — 허용 상태 목록에 "done"을 더합니다.
ALLOWED = ["new", "accepted", "riding", "done"]
저장 → 서버 껐다 켜기.
2. 사장님 화면(web/owner.html) — 다음 상태 표에 한 줄을 더합니다.
const NEXT = { new: ["accepted", "접수"], accepted: ["riding", "배달 출발"], riding: ["done", "배달 완료"] };
저장 → 사장님 창 F5.
- 서버만 고치고 화면을 안 고치면? 버튼이 안 생깁니다. 화면만 고치고 서버를 안 고치면? 버튼을 눌러도 아래에 서버 답: 허용되지 않은 상태: done이 나옵니다. 둘 다 해 보면 "규칙은 서버가 정한다"가 몸으로 이해됩니다.
- 막히면 answers\server_answer.py, answers\owner_answer.html과 비교합니다(정답 파일은 비교용 — answers 폴더 안에서 직접 실행하지 않습니다).
10. 보안 맛보기 — 손님이 가격을 바꿔 보내면?
손님 창에서 F12 → 콘솔에 붙여 넣습니다.
fetch("/api/orders", {method:"POST", headers:{"Content-Type":"application/json"},
body: JSON.stringify({cart:{m1:1}, total:1})}).then(r => r.json()).then(console.log)
'김밥 1개를 1원에 주문'하려는 시도입니다. 결과는 {no: …, total: 6000} — 서버가 메뉴표로 다시 계산해서 1원은 무시됩니다(김밥 4,000 + 배달팁 2,000).
- 손님 화면의 금액은 '예상'일 뿐입니다. 화면 코드는 누구나 F12로 바꿀 수 있으니 돈 계산과 규칙(허용 상태)은 서버 한 곳에만 둡니다. 4강 "돈 계산은 한 함수에만"의 다음 단계입니다.
- 3부 3-6강(보안)에서 로그인·권한까지 이어집니다. 지금 서버는 누구나 '접수'를 누를 수 있습니다 → 다음 강(로그인)이 필요한 이유.
11. 막혔을 때 — 자주 나는 오류
| 증상 | 원인 | 해결 |
|---|---|---|
검은 창이 바로 닫힘 / python을 찾을 수 없음 |
파이썬 경로 | 3강 step0_check.py가 되던 명령 프롬프트에서 python server.py 직접 실행 |
OSError: [Errno 98]·[WinError 10048] |
8000번을 이미 씀(서버가 두 번 켜짐) | 다른 검은 창을 닫고 다시. 그래도 안 되면 server.py의 PORT = 8000을 8001로 |
| 브라우저에 '사이트에 연결할 수 없음' | 서버가 꺼짐 | 검은 창이 떠 있는지 확인 |
| 휴대폰이 안 열릴 때 | 다른 와이파이, 방화벽, 공유기 기기 간 차단 | 같은 와이파이 확인 → 방화벽 '개인 네트워크 허용' → 집 와이파이로 |
| 주소는 맞는데 휴대폰에 '네트워크 서버에 연결할 수 없음' (카페) | 카페·회사 와이파이의 기기 간 차단(손님 기기끼리 못 보게 막는 보안 장치) | 휴대폰 개인용 핫스팟을 켜고 PC를 거기에 연결 → 서버 끄고 다시 켜기 → 새 주소(보통 172.20.10.…)로 접속. 2026-10-25 수업에서 실제로 이렇게 해결 |
빨간 KeyboardInterrupt 와 Terminate batch job (Y/N)? |
Ctrl+C로 서버를 끈 것(오류 아님) | Y → 엔터, 다시 켤 때는 서버켜기.bat |
| 판다스 표에 같은 주문이 여러 줄 | 화면이 늦게 바뀌어 주문 버튼을 여러 번 누름 | 지금은 사장님 창에서 확인. 막는 방법(중복 주문 방지)은 6강 |
| 사장님 창이 안 바뀜 | 화면 파일을 고치고 F5를 안 함 / server.py를 고치고 서버를 안 껐다 켬 |
고친 파일이 어느 쪽인지 확인 |
검은 창에 빨간 SyntaxError |
server.py 쉼표·따옴표 |
오류 줄 번호(line 27)로 가서 확인 |
12. 면접 대비 / 현업 적용 체크리스트
면접 대비
- "프론트엔드와 백엔드의 역할을 나눠 보세요."
- 답: 프론트는 보여 주고 입력을 받는 곳, 백엔드는 규칙·계산·저장을 책임지는 곳입니다. 가격 계산과 상태 규칙은 백엔드에 둬야 위조된 요청을 막을 수 있습니다.
- "REST API를 예로 설명해 보세요."
- 답: 주소와 동작으로 할 일을 정합니다. GET /api/orders는 목록 조회, POST /api/orders는 생성, POST /api/orders/{no}/status는 상태 변경입니다.
- "사장님 화면은 새 주문을 어떻게 압니까? 더 나은 방법은?"
- 답: 지금은 3초마다 묻는 폴링(polling)입니다. 주문이 많아지면 서버가 먼저 알려 주는 웹소켓이나 푸시 알림(2-4강)을 씁니다.
현업 체크리스트
- [ ] 금액·할인은 서버에서 다시 계산하는가
- [ ] 서버가 허용하는 상태 값이 목록으로 정해져 있는가
- [ ] 주문 한 줄에 번호·금액·상태·시각이 다 있는가
- [ ] DB 파일 백업을 하는가 (orders.db 복사)
- [ ] 실제 손님 이름·전화·주소는 연습 서버에 넣지 않았는가
13. 숙제와 다음 강
- 손님 화면에 '주문 취소' 버튼 만들기 — 단, 접수 대기(new)일 때만 취소되게 서버에서 막기(
cancel상태 추가, 서버에서 현재 상태가new인지 확인). step5_db_pandas.py에 메뉴별 판매 개수 세기 추가(items칸을 쪼개서 세기).- 다음 강 예고: 2-3강 로그인과 결제 — 사장님만 '접수'를 누를 수 있게, 그리고 테스트 결제 붙이기(정보장터와 같은 방식).
수업 기록(2026-10-25, 대표님 PC·아이폰): 1~5단계 통과 — 카페 와이파이 기기 간 차단은 핫스팟으로 해결, 판다스로 중복 주문 6건 발견. 6단계·보안은 다음 시간.
확인 기록(2026-10-22, 버디가 클라우드에서 실제 실행): 서버 켜기 → 손님 주문 김밥1+떡볶이1 = 12,500원, 포장 = 9,500원(서버 계산과 화면 예상 일치) → 사장님 창 3초 안에 2건·22,000원 표시 → 접수·배달 출발 후 손님 창 '배달 중' 반영 → 가격 위조(total:1) 요청은 6,000원으로 다시 계산, 허용 안 된 상태(free)는 400 거절 → 서버 재시작 후 주문 3건 유지 → 판다스 3건·28,000원 → 정답판 '배달 완료' 전환 확인. 화면 스크립트 오류 0.

