- DB 020(추가만): projects 종류 · 사업연도 끝 · 설계속도 · 원본 칸 · plan_route_years · plan_route_assignees · 회사 「산림청」 행
- is_forest_email · is_forest_service · /api/auth/session 에 is_forest_service
- require_project_access 한 곳 — 지정 회사 = GET · HEAD 만 · 그 밖 403
- POST /api/d01/project(산림청만 · PLAN · 설계속도 기본 = resolve_design_speed) · GET /api/dashboard/plan-routes/assigned
- GET /api/e01/source-candidates · POST /api/e01/project(B06 완료만 · STABILITY · 원본 칸 · 자료 복사는 528-4)
- 종류별 단계 시드(PLAN 3 · STABILITY 4) · storage 허용 D0x · E0x · B01 목록에 project_kind
- 가입 인증 — 메일 *.go.kr = 회사 산림청 · ACTIVE · 화면 회사 칸 「산림청」 잠금 표시
- 지킴 시험 test_528_project_groups.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- requestLogin 응답 뒤 clearSessionCache — 화면 뜬 뒤 4 s 안 누름도 대시보드
- finish_login = 한 커넥션 · begin 1 · commit 1(users UPDATE · 신뢰 기기 · 세션 · login_logs) · 실패 = rollback
- verify_password = asyncio.to_thread(로그인 · OTP 확인) — 이벤트 루프 안 막음
- 시험 test_309_1_login.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
인증이 걸린 모든 요청이 지나는 자리인데 요청마다 UPDATE + commit 이 나갔음.
DB 가 원격이라 그 둘이 곧 왕복 20ms 임.
실측 — verify_session 34.4ms = SELECT 10.8 + UPDATE 10.4 + commit 9.5.
쓰기를 1분 간격으로 낮춘 뒤 13.6ms(최소 9.4).
last_activity_at 은 유휴 판정에만 쓰는 값이고 그 판정이 4시간 단위라
초 단위 정확도가 필요 없음. 간격은 SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS
(기본 60, .env 로 조정).
화면 한 번 여는 데 API 가 약 180번 나가므로 그만큼 곱해짐.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B03~B07 라우터는 로그인·회사 소속만 확인하고 URL의 project_id가 누구 것인지는 보지
않았다. 프로젝트 id만 알면 남의 회사 자료를 읽고 쓸 수 있었고, B07 도각 저장(PUT)은
그 회사의 공용 양식을 덮어쓴다.
require_project_access를 protected_with_company에 함께 걸어 경로에 project_id가 있는
요청만 한 곳에서 검사한다. 다른 회사면 403, 없는 프로젝트면 404, 시스템 관리자는 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>