ELI5 · 쉬운 설명 · 감사 로그

낮에 로그인한 테스트 계정이
저녁 수업 로그에 따라붙는 이유

마지막 업데이트 2026-09-22

감사 로그를 보면 “테스트교육1” 같은 이름이 저녁 수업 시간에 하루 수천 건씩 찍힙니다. 테스트 아동은 그 시간에 아무것도 하지 않았는데도요. 요청을 보내는 게 아니라, 이름표만 따라다니는 것입니다. 그림 6장으로 설명합니다.

2026-09-22조사 범위 2026-09-09~09-21 매일 20:00~22:00ppi-web-prod감사 로그 37,610건

한 줄 결론 — 낮에 진행자가 테스트 아동 계정으로 로그인하면 그 브라우저에 아동 세션 쿠키가 14일 동안 남습니다. 저녁 수업 때 진행자가 보내는 모든 요청에 그 쿠키가 함께 실려 가고, 서버가 두 이름을 같이 기록해서 아동 이름이 찍힙니다. 요청 수가 늘어나는 것도, 테스트 아동이 접속하는 것도 아닙니다.

그림 1착각과 사실

로그만 보면 “테스트 아동이 수업 중에 요청을 보낸다”처럼 보입니다. 실제로는 아닙니다.

착각과 사실 로그에는 테스트 아동 이름이 찍히지만 실제 요청을 보낸 것은 진행자 브라우저 한 곳이다. 착각 테스트 아동 “테스트교육1” 이 접속해서 요청? 서버 로그에 아동 이름 6,109건 사실 진행자 1명 실제 수업 진행 중 요청을 보냄 같은 로그 6,109건 이름표만 잘못 붙음 실제 대상 아동 280명 (전부 진짜 아동) 테스트 아동 대상: 0건 요청 수는 하나도 안 늘어난다

2026-09-21 20:00~22:00 실측 — 태깅 6,109건은 전부 진행자가 보낸 정상 수업 요청.

그림 2쿠키는 “가방에 넣어둔 이름표”

낮에 테스트 계정으로 로그인하면 이름표 한 장이 브라우저 가방에 들어갑니다. 유효기간 14일.

쿠키 발급 아동 로그인 API가 아동 세션 쿠키를 발급하고 브라우저가 14일간 보관한다. 낮 — 기능 점검 진행자가 테스트 아동 계정으로 로그인 POST /api/users/auth childId · childName 저장 토큰도 함께 저장 → 이름표 발급 진행자 브라우저 가방 진행자 이름표 member-session 테스트 아동 이름표 child-session 14일간 유효

이름표는 로그아웃하지 않으면 사라지지 않습니다. 두 장이 나란히 공존합니다.

왜 14일인가childSessionOptions.cookieOptions.maxAge = 60 * 60 * 24 * 14 (apps/web/lib/session-options.ts:41). 진행자용과 값이 같습니다.

그림 3저녁 — 가방을 통째로 내민다

브라우저는 같은 도메인으로 요청을 보낼 때 가방 안 이름표를 전부 자동으로 함께 보냅니다. 골라 보내지 않습니다.

요청 1건에 쿠키 2장 진행자가 보낸 요청 한 건에 진행자 쿠키와 아동 쿠키가 함께 실린다. 저녁 20:00 수업 진행자가 자료를 열고 로그를 올린다 요청 1건 1건 그대로 HTTP 요청 봉투 Cookie: ppi-member-session=… Cookie: ppi-child-session=… ppi-web 접수대 봉투를 열어 이름표 2장을 둘 다 읽는다 proxy.ts 미들웨어

쿠키는 요청을 만들지 않습니다. 이미 가는 요청에 얹혀 갈 뿐입니다.

그림 4접수대가 둘 다 적는다 — multiple

이름표가 두 장이면 감사 로그는 둘 다 적습니다. 그래서 진행자 요청에 아동 이름이 붙습니다.

actor 판정 member와 child가 모두 있으면 actorType은 multiple이 되고 두 이름이 함께 기록된다. 진행자만 있음 → actorType: "member" 아동만 있음 → actorType: "child" 둘 다 있음 ← 지금 상황 → actorType: "multiple" 감사 로그 한 줄에 같이 기록 "actorType": "multiple" "memberName": "화이트" "childName": "테스트교육6" ← 잔존 "path": "/api/lessons/(진짜 아동)/…" 아동별 집계가 틀어진다 path는 맞고 라벨만 틀림

판정 코드는 apps/web/api-audit.js:93if (member && child) return { actorType: "multiple", ...member, ...child }.

그림 5실제로 어떻게 헷갈리는가

2026-09-21 21:49:28, 로그 8줄에 같은 아동 이름이 연달아 찍혔습니다. 같은 요청의 반복처럼 보입니다.

21:49:28.685  childName:"테스트교육6"  GET /api/lessons/4ef1aad0…/2
21:49:28.688  childName:"테스트교육6"  GET /api/lessons/d579d955…/44
21:49:28.696  childName:"테스트교육6"  GET /api/lessons/7fd2922e…/16
21:49:28.704  childName:"테스트교육6"  GET /api/lessons/b81c61c7…/14
21:49:28.710  childName:"테스트교육6"  GET /api/lessons/49099392…/20
21:49:28.720  childName:"테스트교육6"  GET /api/lessons/0f0e940a…/34
21:49:28.729  childName:"테스트교육6"  GET /api/lessons/b7896f37…/26
21:49:28.736  childName:"테스트교육6"  GET /api/lessons/f2ef0613…/22

이름은 8줄 모두 같지만 경로의 아동 ID는 8개 전부 다릅니다. 진행자 화이트가 목록 화면을 한 번 열었고, 화면이 아동 수만큼 한 번씩 조회한 것입니다(N+1). 같은 요청의 반복이 아닙니다.

이 착시가 실제로 조사를 두 번 헛돌게 했습니다. “테스트교육5가 반복 요청” → 실제로는 진행자 로지·조안나였고, “테스트교육6 8연속” → 실제로는 서로 다른 아동 8명이었습니다. 아동 이름으로 필터링해 뭔가를 판단하면 안 됩니다.

그림 6숫자로 본 규모

2026-09-09~09-21, 매일 20:00~22:00 ppi-web-prod 감사 로그 전수.

37,610테스트교육N 태깅 총건수 (12일)
100%actorType = multiple
0actorType = child
(진짜 테스트 아동 요청)
0쿠키 속 테스트 아동이
대상인 요청
14일아동 쿠키 유효기간
0.095ms쿠키 1장 복호 비용
(부하 영향 없음)

날짜별 편차가 큰 이유

하루 31건에서 6,719건까지 40배 넘게 차이 납니다. 테스트 아동의 활동량과는 무관하고, 두 가지가 곱해진 결과입니다.

요인내용
① 그날 수업이 있었나주말은 전체 요청 자체가 300~1,300건뿐09/20(일) 31건 · 09/12(토) 6건
② 어느 진행자가 근무했나이름별로 붙는 진행자가 거의 고정. 그 사람이 쉬면 0건테스트교육3 → 카이아(09/16·18·21에만 등장)
③ 그 진행자의 그날 업무량태깅 건수 = 그 브라우저의 모든 요청09/21 그랜트 1,206건 전부가 태깅
쿠키는 도중에 바뀌기도 합니다. 화이트는 09/10~09/11엔 테스트교육2, 09/16부터 테스트교육6으로 찍힙니다. 다른 테스트 계정으로 다시 로그인한 흔적입니다.

정리무엇이 문제이고 무엇이 아닌가

항목판정근거
요청 수가 늘어난다아니다쿠키는 기존 요청에 얹혀 감. 로그 1줄 = 요청 1건
서버 부하를 만든다아니다쿠키 복호 0.095ms — 요청당 CPU 32.3ms의 0.3%
테스트 아동 데이터가 조회된다아니다핸들러는 경로의 userId로 동작. 09/21 태깅 6,109건 중 테스트 아동 대상 0건
감사 로그가 틀린 아동에 귀속된다그렇다09/21 전체 63,081건 중 9.7%가 잘못된 아동 이름
아동 인증 토큰이 진행자 PC에 상주한다그렇다ChildSessionaccessToken/refreshToken 포함, 최대 14일
그 토큰으로 아동 권한 API가 열리는가미확인토큰 사용처 추적 필요 — 이 문서의 후속 과제
고칠 곳 세 군데
api-audit.js:93 — member가 있으면 child를 actor로 쓰지 말고 staleChildName 같은 별도 필드로 분리
② 진행자 로그인 시 잔존 아동 세션 정리(또는 아동 세션 maxAge를 수업 시간 수준으로 단축)
③ 테스트 아동 계정 사용 후 로그아웃을 점검 절차에 포함

참고코드 위치와 이웃 문서

무엇어디
아동 로그인 · 쿠키 발급apps/web/app/api/users/auth/route.ts:41-43
쿠키 옵션 · maxAge 14일apps/web/lib/session-options.ts:34-43
요청마다 두 세션을 함께 읽음apps/web/proxy.ts:30-33
actor 판정 — multipleapps/web/api-audit.js:93
감사 로그 기록 지점apps/web/proxy.ts:46-57 (started) · apps/web/server.js:77-94 (completed)
이웃 문서
· Auth / 세션 / TURN·ICE 발급 — 코드레벨 동작 흐름 (member·child 세션이 만들어지는 경로)
· 같은 진행자 계정의 다중 탭에서 Waiting for guest 고착 (PPI-1311) (진행자 브라우저 상태 잔존 계열)
조사 방법 — Grafana Loki에서 instance="ppi-web-prod" 로그를 날짜별 20:00~22:00 범위로 내려받아 api_audit_startedactorType·memberName·childName·path를 교차 집계했습니다. 로그 보관 범위가 20:00~22:00이라 쿠키가 발급된 낮 시각 자체는 확인하지 못했고, 해당 창에서 진행자 브라우저의 아동 로그인은 12일 통틀어 373건 중 2건뿐이었습니다 — 발급이 수업 시간 밖에 일어났다는 것은 이 관찰에 근거한 추정입니다.