chore(요구): 요구 403 · 404 조사 — 동시 프로젝트 · 검증 프로젝트 목록
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
# 요구 403-4 — 동시에 여는 프로젝트 수 제한 검토
|
||||
|
||||
읽기 전용 조사 · 구현 없음 · 근거 = 파일:줄 · 앞 조사 = `docs/raw/요구_1025/_분석_400_세션_비우기.md` · `_분석_401_프로젝트_따로.md`(겹치는 표는 거기 그대로).
|
||||
|
||||
## 0. 결론
|
||||
|
||||
- **프로젝트를 열어 두기만 하면 서버 비용 ≈ 0** — 서버가 쥐고 있는 연결 · 폴링 · 상주 메모리 없음. 비용은 ① 열 때 한 번(요청 묶음) ② **무거운 일감**(해석 · 전처리 · 체인)에서 남.
|
||||
- 무거운 일감은 **화면을 떠나도 계속 돎** · 일감끼리 **전역 상한 없음** — E03 · E04 일감 하나가 코어-2 개 프로세스를 띄움 → 둘이 겹치면 CPU 두 배 초과.
|
||||
- → 「한 사람 2개까지」는 서버를 거의 못 지킴(X 에서 E02 해석 시작 → 떠남 → Y 시작 → Z 시작 = 열린 화면 하나로 일감 셋 · 사용자 수만큼 곱해짐).
|
||||
- 추천 — **서버 보호 = 무거운 일감 자리 수(전역 대기열)** · 「2개 제한」은 정책으로 원하면 서버 등록부(가벼움 · 약 300줄)로 · 둘은 따로 고를 수 있음.
|
||||
|
||||
## 1. 서버 비용 — 열린 화면 대 일감
|
||||
|
||||
### 1-1 열어 두기만 한 화면
|
||||
|
||||
| 항목 | 지금 | 근거 |
|
||||
| --- | --- | --- |
|
||||
| 서버 프로세스 | 하나(uvicorn workers 없음) · 모든 메모리 캐시 = 이 프로세스 공용 | `main.py:575-583` |
|
||||
| 상시 연결 | 없음(WebSocket · SSE 0) | Python 전수 grep `WebSocket|EventSourceResponse|StreamingResponse` 0 |
|
||||
| 폴링 | 일감이 돌 때만(`if (p.running) void poll()`) · 단계 이동 덮개 동안만 1 s | `E02_StabGround_UI_Page.ts:395` · `E04_Stab3D_UI_Page.ts:484` · `E07_StabArea_UI_Page.ts:491` · `D03_PlanAnalysis_UI_Page.ts:63` · `B11_Status_UI_Loading.ts:32` · `b_workflow_nav.ts:128-170` |
|
||||
| DB 연결 | 풀 5~20 전역 · 요청마다 잠깐 빌림 · 열린 화면은 0 개 쥠 | `config/config_system.py:66-67` · `config/config_db.py:30-44` |
|
||||
| 세션 | DB `sessions` 한 줄 · 프로젝트 칸 없음 | `db_management/002_auth_security.sql:21-31` |
|
||||
|
||||
→ 열어 둔 화면 수는 서버 메모리 · CPU · 연결에 **안 걸림**.
|
||||
|
||||
### 1-2 열 때 한 번
|
||||
|
||||
- 요청 묶음 — B05 열기 /api 22~23 번 · 7.5 s(386-0 측정 · 401 비용 표) · 요청마다 `verify_session` SELECT(+1 분에 한 번 UPDATE · `common_util_auth.py:122-126`) + `require_project_access` SELECT(`:183-226`).
|
||||
- 파일 읽기 → 아래 1-3 캐시에 올림 · 3D 미리보기 glb 8~19 MB 는 `_derived` 파일 그대로 보냄(셈 없음).
|
||||
|
||||
### 1-3 메모리 캐시 — 전역 상한 · 프로젝트 수와 거의 무관
|
||||
|
||||
| 캐시 | 자리 | 상한 | 한 벌 크기 |
|
||||
| --- | --- | --- | --- |
|
||||
| DTM 표본기 | `common_util_surface_sampler.py:131-136` | lru 4 | 표본 프로젝트 배열 9.5 MB(1030×1836 · 실측) · 주석 약 17 MB |
|
||||
| 노선 비용면 · 계류 | `B05_Profile_Engine_RouteInitial.py:130-131 · 194-196` | 4 | 비용면 격자(어림 수십 MB) |
|
||||
| 노선 후보 묶음 | 같은 파일 `:127-128 · 467-470` | 4 | 어림 수십 MB |
|
||||
| 배수 상세 | `B04_PreProcess_Router_Basins.py:142-143` | 4 | — |
|
||||
| 도엽 · 등고선 묶음 | `B04_PreProcess_Router_Watershed.py:133-141` · `_Engine_Watershed_Grid.py:147-173` · `_Engine_Watershed_Descent.py:79-117` | 2 · 2 · 2 | 등고선 수만 점 |
|
||||
| B06 [저장] Node 결과 | `B06_Section_Server_Calc_Prebuild.py:82-127` | 8 | — |
|
||||
| 유토 배분 | `B06_Section_Router_HaulPlan.py:50-63` | 32 | 작음 |
|
||||
| B07 겹 · 유역 선 | `B07_DesignDetail_Router_Support_Overlay.py:35-87` · `_Support_Basin.py:192` | 8 · lru 8 | 수 MB |
|
||||
| E03 벽 · 3D 띠 | `E03_StabSection_Router.py:147 · 520` | lru 4 · 2 | — |
|
||||
| 배수 길 · 지문 | `common_util_drainage_detail.py:265-301` · `_drainage_pipes.py:222-230` | 1(clear 후 넣음) | — |
|
||||
|
||||
- 합 어림 0.3~0.6 GB 천장(측정 없음) — 프로젝트가 많으면 **늘지 않고 밀려남**(디스크 다시 읽기 0.1~0.5 s).
|
||||
- **상한 없는 것** — ① `B04_PreProcess_Router_Inflow.py:37 · 68` 유입 배열(열쇠 = 프로젝트 경로 · 표본 road_slot + path_length + road_chainage ≈ 11 MB · 서버 켠 뒤 B04 유입을 본 프로젝트마다 쌓임) ② `B04_PreProcess_Engine_MvtHelper.py:22 · 58` GeoDataFrame(열쇠 `{pid}_{겹}` · 부르는 화면 0 = 잠듦 · `/tiles/…pbf` TS 호출 0) ③ 일감 진행 표 `_JOBS`(프로젝트마다 KB).
|
||||
- → 프로젝트 수에 비례하는 것은 ① 하나 — 화면 제한이 아니라 상한 한 줄(4 벌)로 고칠 몫.
|
||||
|
||||
### 1-4 무거운 일감 — 진짜 비용
|
||||
|
||||
| 일감 | 시작 자리 | 같은 프로젝트 겹침 | 자원 | 시간 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| B03 업로드 뒤 자동 설계 체인(WF1 → B05 → B06) | `B03_FileInput_Router_Helpers.py:312-327` · `_Service_Chain.py:157` | 업로드 단계 | 스레드 + Node · 점구름(표본 `structured.npz` 841 MB 압축) | 분 단위 |
|
||||
| B04 지표면 확정 → 재설계 체인 | `B04_PreProcess_Router.py:265-272` | 없음 | 위와 같음 | 분 단위 |
|
||||
| B04 지표면 모델 빌드 | `B04_PreProcess_Engine_Pipeline.py:40 · 363-384` | 같은 폴더면 취소 | 점구름 · 격자(어림 수 GB) | 분 단위 |
|
||||
| D03 지형 받기 · 분석 | `D03_PlanAnalysis_Router.py:37 · 76 · 93` | 409 | WFS 스레드 4(`D03_PlanAnalysis_Layers.py:49 · 173`) · 외부망 | 분 단위 |
|
||||
| E02 한 번에 해석 | `E02_StabGround_Chain.py:41-43 · 278-293` | `busy` | 2D → 3D 건기 · 우기 → 암반 → 광역 → 보고서 | 1.2 km 3D 약 25 분(`:26-32`) |
|
||||
| E03 2D | `E03_StabSection_Router.py:362 · 379` | 409 | 프로세스 코어-2(`:281` · `E03_StabSection_Engine_Station.py:107-113`) | 1~3 분 |
|
||||
| E03 확률 | `E03_StabSection_Router_Prob.py:353 · 385` | 409 | 프로세스 코어-2(`:271` · `E03_StabSection_Worker.py:67`) | 표본 수 비례 |
|
||||
| E04 3D | `E04_Stab3D_Router.py:136 · 159` | 409 | 프로세스 min(12, 코어-2) · 일꾼마다 지층 사본(`E04_Stab3D_Engine_Search.py:253-263 · 421-425`) | 건기 · 우기 약 25 분 |
|
||||
| E07 광역 | `E07_StabArea_Router.py:314 · 331` | 409 | 스레드 | — |
|
||||
| B06 [저장] · 계산 창구 | `common_util_calc_runner.py:97-149` | — | **늘 떠 있는 Node 하나 · 잠금 하나**(`:126`) → 모든 사용자 직렬 | 요청당 |
|
||||
|
||||
- 같은 프로젝트 겹침만 막음(409) · **프로젝트끼리 · 사용자끼리 상한 0**(전수 grep `Semaphore` 0).
|
||||
- 떠나도 돎 — 「사용자가 화면에 없어도 서버가 이어서」(`B03_FileInput_Service_Chain.py:3-6`) · E02 · E03 · E04 · E07 · D03 은 `asyncio.create_task` 로 화면과 무관.
|
||||
- 프로세스 풀은 일감마다 따로 열림 → 16 코어 기계에서 E04 둘 = 일꾼 12 × 2 = 24(코어보다 많음) · 메모리 두 배.
|
||||
|
||||
### 1-5 판정
|
||||
|
||||
- 열린 **화면** 제한 = 서버 효과 거의 없음(1-1 · 1-3) · 일감을 못 묶음(1-4).
|
||||
- 효과 있는 것 = **일감 자리 수**(전역 동시 N 개 · 나머지 대기) + 풀 일꾼을 자리 수로 나눔.
|
||||
- 화면 제한의 실제 값어치 = 정책(좌석 · 사용 규칙) · 사용자 PC 메모리(3D 탭) · 일감 버튼을 누를 화면 수를 간접으로 줄임 — 서버 보호 근거로는 약함.
|
||||
|
||||
## 2. 「열린 프로젝트」 세는 법
|
||||
|
||||
| 갈래 | 방식 | 장점 | 단점 |
|
||||
| --- | --- | --- | --- |
|
||||
| (가) 브라우저만 | BroadcastChannel · localStorage 명부 + 박동 | 서버 손질 0 | 다른 브라우저 · PC 못 셈 · 우회 쉬움 · 탭 꺼짐 정리 어려움 |
|
||||
| **(나) 서버 등록부** | 들어갈 때 (user, project, tab) 등록 · 박동 30 s · 만료 150 s · 셋째 다른 프로젝트 거절 | 모든 PC · 브라우저 · 서버 재시작도 박동으로 되채움 | 서버 파일 4~5 · 박동 요청(탭당 분 2 번 · SELECT 2) |
|
||||
| (다) 섞음 | (나) + 같은 브라우저 탭끼리 BroadcastChannel 즉시 알림 | 닫힘 즉시 반영 | 더 늘 뿐 · (나) 만으로 충분(YAGNI) |
|
||||
|
||||
검사 자리:
|
||||
|
||||
- **클라 문 하나** — `router.ts:224-234` 「프로젝트 화면」 문(`PROJECT_ROUTES :108-117` + 초안 길 `project: true`) · B · D · E 프로젝트 화면이 모두 지남 · `dropGoneProject` 바로 뒤에 `openProject` 한 줄.
|
||||
- **서버 새 창구** — `POST /api/projects/{project_id}/open`(들어감 · 박동) · `POST …/close`(떠남 · 탭 닫음 · 남의 자리 닫기) · `protected_with_company` 에 걸어 접근 검사는 기존 `require_project_access`(`common_util_auth.py:183-226`)가 함.
|
||||
- `require_project_access` 안에 넣지 않음 — 모든 요청마다 등록부를 보면 B03 조각 올림 · 일감 폴링 · 서버 안 부름까지 엉킴 · 우회 막기 목적이 아니라 규칙이라 문 + 박동으로 충분.
|
||||
- `b_project_switch.ts` `enterProject` 는 이동 길(`goToWorkflowStage`)에서만 돎 · 새로고침 · 주소 직접 · D · E 단계 이동을 놓침 → 문은 `router.ts` 쪽.
|
||||
- 떠남 = `main.ts:89-100` hashchange(가드 뒤) · 탭 닫음 = `pagehide` + `navigator.sendBeacon`(API 같은 출처 `/api` · `config_frontend.ts:14` → 쿠키 실림) · 로그아웃 = 서버 `A06_Login_Router.py:182-189`.
|
||||
|
||||
셈 규칙:
|
||||
|
||||
- 같은 프로젝트를 탭 여럿 = **하나**(서로 다른 프로젝트 수만 셈).
|
||||
- 사용자 단위(user_id) — 다른 PC · 브라우저 합산.
|
||||
- 예외 후보 — 시스템 관리자(`role == SYSTEM_ADMIN` · 지원 · 점검) · 산림청(`is_forest_service` `common_util_auth.py:156`) · 지정 회사 보기만(GET 만 · `:205-220`) → 결정 4.
|
||||
|
||||
## 3. 한 설계 — 탭 id · 등록부 · 떠남 비움 · 공용 물음
|
||||
|
||||
| 때 | 탭 id | 현재 프로젝트(결정 1) | 등록부(결정 4) | 세션 · 3D(결정 2) | 물음(결정 3) |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 들어감(`router.ts` 문) | 문서 열릴 때 `crypto.randomUUID()` 메모리 하나 · sessionStorage 에 안 둠(탭 복제 때 세션이 복사돼 같은 id 가 둘 됨) | 탭 세션 `aislo:entered-project` 먼저 · 없으면 localStorage(새 탭 = 마지막 프로젝트) | `open` → 200 통과 · 409 막힘 화면 · 403/404 기존 「없어진 프로젝트」 | 다른 프로젝트면 남의 칸 비움 + 새로고침(401 규칙 4) · 3D 는 「이 세션 다른 탭이 연 프로젝트」를 남김(`open` 답에 목록) | — |
|
||||
| 머묾 | — | — | 박동 30 s(같은 `open` · 머리표 `X-Aislo-Beat: 1`) · 박동은 **거절 안 함**(되채움) · 닫힘 표시면 410 | — | — |
|
||||
| 떠남(`main.ts` hashchange) | — | 남김(뒤로 가기용) | 가드 통과 뒤 `close`(fetch keepalive) · 박동 멈춤 | 그 프로젝트 세션 칸 · `frd_preloaded_signature` · 3D 몫 지움 · 단 `close` 답 「이 세션 다른 탭이 아직 엶」이면 3D 는 남김(보관함은 탭 공용) | 공용 [취소][폐기][저장] 먼저 · 취소 = 아무것도 안 함 |
|
||||
| 탭 닫음 · 새로고침 | 다음 로드 = 새 id | — | `pagehide` sendBeacon `close` · 빠지면 150 s 만료 | 세션은 탭과 사라짐 · 3D 는 다음 들어감 그물 | `beforeunload` 브라우저 물음(고침 있을 때) |
|
||||
| 로그아웃 | — | 지움(기존) | 서버 logout 이 그 세션 줄 지움 · 다른 PC 줄 남김 | 전부(기존 `wipeAccountCache`) | 가드 먼저(기존 `app_shell.ts:53-73`) |
|
||||
|
||||
- 차례 = 물음 → 비움 → `close` → 다음 화면 → (프로젝트 화면이면) `open`. 한 탭으로 X → 대시보드 → Y 는 X 를 먼저 풀어 **절대 안 막힘**.
|
||||
- 등록부 꼴(서버 메모리) — `{user_id: {project_id: {tab_id: (마지막 박동, session_id)}}}` + 닫힘 표시 `{(user_id, project_id): 때}`.
|
||||
|
||||
## 4. 제안
|
||||
|
||||
### 4-1 추천
|
||||
|
||||
1. **일감 자리 수(서버 보호 · 추천)** — `common_util_job_slots.py` 하나(전역 `asyncio.Semaphore(HEAVY_JOB_SLOTS)` · 대기 중이면 진행 표 글 「대기 중 — 앞 n 개」) · 1-4 시작 자리 8 곳의 `work()` 를 `async with slot(...)` 으로 감쌈 · 풀 일꾼 = (코어-2) ÷ 자리 수(`E03_StabSection_Router_Prob.py:271` · `E03_StabSection_Router.py:281` · `E03_StabSection_Engine_Station.py:107` · `E04_Stab3D_Engine_Search.py:421-422`). E02 체인은 자리 하나를 끝까지 쥠 · 안에서 부르는 페이지 함수는 시작 자리(`create_task`)가 아니라 다시 안 잡음(구현 때 확인).
|
||||
2. **화면 2개 제한(정책 · 사용자가 원하면)** — 2장 (나) 서버 등록부 · 3장 흐름.
|
||||
3. **덤** — 유입 캐시 상한 4(`B04_PreProcess_Router_Inflow.py:37` · `_DETAIL_CACHE` 꼴).
|
||||
|
||||
### 4-2 제한 규칙(2 를 고를 때)
|
||||
|
||||
- 서로 다른 프로젝트 **2 개**까지 · 같은 프로젝트 탭 여럿 = 하나 · 사용자 단위.
|
||||
- 상한은 `config_system.py` 환경값 `MAX_OPEN_PROJECTS`(기본 2 · 0 = 끔) · 만료 150 s.
|
||||
- 박동은 세션 유휴를 늘리지 않음 — `verify_session` 이 요청마다 `last_activity_at` 갱신(`common_util_auth.py:122-126`) → `X-Aislo-Beat` 면 건너뜀(안 그러면 4 시간 유휴 끊김이 영영 안 걸림).
|
||||
|
||||
### 4-3 막혔을 때 화면
|
||||
|
||||
- 프로젝트 화면 자리에 안내(`renderProjectGone` 꼴 · `b_page_scaffold.ts:76`) — 「동시에 열 수 있는 프로젝트는 2 개」.
|
||||
- 열린 목록 — 프로젝트 이름 · 「이 브라우저」 / 「다른 곳」 · 탭 수 · 마지막 활동 n 초 전 · 줄마다 [닫고 여기서 열기].
|
||||
- 아래 [다시 시도] · [대시보드로] · 단추는 부품 상자 `createButton`.
|
||||
- [닫고 여기서 열기] = `close {all}` → 닫힘 표시 → 이 탭 `open` · 쫓긴 탭은 다음 박동 410 → 덮개 「다른 곳에서 이 프로젝트를 닫음 — 저장 안 한 고침은 이 탭에 남음」 [다시 열기] [대시보드로].
|
||||
|
||||
### 4-4 가장자리
|
||||
|
||||
- 비정상 종료 · 절전 · 망 끊김 — 150 s 뒤 자리 풀림 · 깨어난 탭 박동은 되채움(잠깐 3 개 가능 · 허용).
|
||||
- 숨은 탭 타이머 늦춤 — Chrome 은 5 분 넘게 숨은 탭 타이머를 1 분에 한 번 → 박동 30 s 가 60 s → 만료 150 s 가 버팀.
|
||||
- bfcache 되살림 — `pageshow` persisted 면 `open` 다시.
|
||||
- 서버 재시작 · 개발 리로드(`main.py:579` reload=DEBUG) — 메모리 등록부 비워짐 → 다음 박동(≤ 30 s)으로 되채움 · 박동은 거절 안 해 쫓기는 탭 없음 · 첫 30 s 셋째가 열릴 틈 = 허용 · 닫힘 표시도 사라짐(허용).
|
||||
- 서버 여러 프로세스 — 지금 하나 · 늘면 DB 표로(`ponytail:` 주석 · `common_util_save_guard.py:48` 꼴).
|
||||
- 세션 만료 — 박동 401 → 기존 로그인 길 · 등록부 줄은 만료로.
|
||||
- 새 프로젝트 등록(B02 · D01 · E01) — 등록 뒤 첫 단계가 같은 문을 지남 → 다른 탭 2 개면 막힘 화면(등록은 남음).
|
||||
- 일감 도는 중 떠남 — 일감 계속 · 화면 수에 안 셈.
|
||||
- 같은 프로젝트 두 탭 고침 — 지금과 같음(나중 저장이 이김) · 이번 범위 밖.
|
||||
|
||||
### 4-5 고칠 파일 · 창 나눔(파일 겹침 없음)
|
||||
|
||||
| 창 | 파일 | 일 |
|
||||
| --- | --- | --- |
|
||||
| 창1 클라 공용(먼저 커밋) | `A00_Common/b_project_switch.ts` | `currentProjectId` · `setCurrentProject` · `leaveProject` · `guardProjectLeave({dirty, save, discard})`(`design_leave.ts:102-128` 일반화) · 다른 프로젝트 들 때 새로고침 |
|
||||
| 창1 | 새 `A00_Common/b_project_open.ts` | 탭 id · `openProject` · 박동 · `closeProject` · `pagehide` sendBeacon · `pageshow` |
|
||||
| 창1 | `A00_Common/b_asset_cache.ts` | `purgeProject(pid)` · `purgeOtherProjects(keep)` |
|
||||
| 창1 | `A00_Common/b_page_state.ts` | 등록표 D02 · E 7 줄(400 그대로) |
|
||||
| 창1 | `A00_Common/router.ts` | 문에 `openProject` · `isProjectRoute` 내보냄 |
|
||||
| 창1 | `A00_Common/b_page_scaffold.ts` · `ui_template/ui_template_locale_b1.ts` | 막힘 화면 · 쫓김 덮개 · 문구 |
|
||||
| 창1 | `A00_Common/group_workflow.ts` · `b_workflow_nav.ts` · `b_page_scaffold.ts` · `design/design_leave.ts` · `design/design_store.ts` · `design/design_page.ts` · `design/design_view_profile.ts` · `ui_template/ui_template_overlay.ts` | helper 로 · `beforeLeave` → `{dirty, save}` · `guardDesignLeave` = 공용 위 얇은 껍질 · `createGroupProject`(`group_workflow.ts:117`) → `setCurrentProject` |
|
||||
| 창1(마지막) | `A00_Common/main.ts` | `renderAll` 떠남이면 `leaveProject` + `closeProject` — 창3 가드 합친 뒤 |
|
||||
| 창2 서버 | 새 `common_util/common_util_open_projects.py` | 등록부(순수 · 메모리 · `touch` · `release` · `close_project` · `drop_session` · `listing`) |
|
||||
| 창2 | 새 `B01_Dashboard/B01_Dashboard_Router_Open.py` | `open` · `close` 창구 · 409 목록에 이름(SELECT 한 번) |
|
||||
| 창2 | `main.py` | 라우터 한 줄(`protected_with_company`) |
|
||||
| 창2 | `common_util/common_util_auth.py` | `X-Aislo-Beat` 면 활동 갱신 건너뜀 |
|
||||
| 창2 | `A06_Login/A06_Login_Router.py` | logout → `drop_session` |
|
||||
| 창2 | `config/config_system.py` | `MAX_OPEN_PROJECTS` · `OPEN_PROJECT_TTL_S`(· 고르면 `HEAVY_JOB_SLOTS`) |
|
||||
| 창2(4-1 ① 고르면) | 새 `common_util/common_util_job_slots.py` · `E02_StabGround_Chain.py` · `E03_StabSection_Router.py` · `_Router_Prob.py` · `_Engine_Station.py` · `E04_Stab3D_Router.py` · `_Engine_Search.py` · `E07_StabArea_Router.py` · `D03_PlanAnalysis_Router.py` · `B03_FileInput_Router_Helpers.py` · `B04_PreProcess_Router.py` · `B04_PreProcess_Router_Inflow.py` | 자리 감쌈 · 일꾼 나눔 · 유입 상한 |
|
||||
| 창3 페이지 | `B03_FileInput_UI_Page.ts` · `_Page_Flow.ts` · `_PlanImport.ts` · `B04_PreProcess_UI_Page.ts`(675 줄 · 늘면 쪼갬) · `B07_DesignDetail_UI_Page.ts` · `B08_Quantity_UI_Page.ts` · `B09_Estimation_UI_Shell.ts` · `_Tabs_Bill_Link.ts` · `_Tabs_Base_Quote.ts` · `_Haul_Modal.ts` · `draft/B09_Draft_Print_Page.ts` · `B11_Status_UI_Loading.ts` · `B02_ProjRegister_UI_Page.ts` | helper 로 · 누를 때 id = 그릴 때 id · 가드 B04(`_Basins.ts:166 · 310` dirty) · B07(`_UI_Page.ts:222-223`) · B08 · B09 · 3D 지우기 두 곳 뺌 |
|
||||
| 창3 | `B06_Section_UI_Page_Pipe_Options.ts` | `soilSent` 열쇠에 pid · 노선(401) |
|
||||
| 창3 | `D02` · `D03` · `D04` · `E02` · `E03`(629 줄) · `E04` · `E05` · `E06` · `E07` `_UI_Page.ts` | helper · 세션 직접 → 등록표 · 가드 새로 D04 · E03 · E05 · E06 · 말없이 저장 → 공용 물음 D02 · D03 · E02 |
|
||||
|
||||
차례 = 창1 공용 · 창2 서버 병행 → 창3 페이지 → 창1 `main.ts` 떠남 연결. 떠남 연결이 가드보다 먼저면 B08 · B09 · D04 · E03 · E05 · E06 고침이 말없이 사라짐(400 4장).
|
||||
|
||||
### 4-6 시험(`resources/tester` · 번호 겹침 피해 이름으로)
|
||||
|
||||
- `test_open_projects_registry.py` — 순수 등록부: 다른 프로젝트 2 통과 · 셋째 거절 + 목록 · 같은 프로젝트 두 탭 = 하나 · 한 탭 풀어도 다른 탭이 쥐면 남음 · 150 s 지나면 풀림 · 박동은 넘쳐도 받음 · 닫힘 표시 뒤 박동 = 410 · `drop_session` 은 그 세션만 · 상한 0 = 끔 · (고르면) 시스템 관리자 예외.
|
||||
- 같은 파일 소스 대조 — `main.py` 가 새 라우터를 `protected_with_company` 로 · `verify_session` 에 `X-Aislo-Beat` · logout 이 `drop_session`.
|
||||
- `test_project_leave_clear.py` + `helper_project_leave_clear.cjs`(`helper_290_1_project_purge.cjs` 꼴) — 두 탭 흉내(세션 둘 · localStorage 하나) · `leaveProject` 프로젝트 칸 0 · 밖 칸 그대로 · 탭 id 가 sessionStorage 에 없음 · `router.ts` 문이 `dropGoneProject` 뒤 `openProject` · `main.ts` 가드 뒤 `leaveProject` · `closeProject` · `pagehide` sendBeacon.
|
||||
- `test_560_4_leave_save.py` 넓힘 — B04 · B07 · B08 · B09 · D02~D04 · E02 · E03 · E05 · E06 가드.
|
||||
- `test_290_1_project_purge.py` · `test_384_1_session_keys.py` 넓힘(400 그대로).
|
||||
- (일감 자리 고르면) `test_job_slots.py` — 자리 1 이면 둘째 대기 · 끝나면 들어감 · 끊기면 자리 반납 · 일꾼 수 = (코어-2) ÷ 자리.
|
||||
- 화면(ORCA 탭 하나) — 다른 두 프로젝트를 `eval` fetch 로 가짜 탭 id 등록 → 셋째 진입 = 막힘 화면 · [닫고 여기서 열기] 통과 · 대시보드로 떠나면 `close` · 150 s 기다린 만료.
|
||||
|
||||
## 갈래 갈리는 결정
|
||||
|
||||
1. **무엇을 막나** — 일감 자리 수(서버 보호 · 추천) / 화면 2 개(정책) / 둘 다.
|
||||
2. **일감 자리 수** — 전역 1(가장 안전 · 기다림 김 · E02 25 분이면 뒤 사람 25 분 대기) / 전역 2(일꾼 반씩) · 사람마다 1 개 상한 더할지.
|
||||
3. **화면 제한 고르면 셈 단위** — 사용자 단위(모든 PC 합산 · 제안) / 브라우저 단위(서버 손질 0 · 다른 PC 못 셈).
|
||||
4. **예외** — 시스템 관리자 빼기(제안) / 모두 같음 · 산림청 · 지정 회사 보기만도 셀지.
|
||||
5. **남의 자리 닫기** — [닫고 여기서 열기] 허용(제안 · 다른 PC 에 켜 둔 탭 풀기) / 목록만 보이고 기다림(만료 150 s · 켜 둔 탭은 영영 안 풀림).
|
||||
6. **만료 시간** — 150 s(제안 · 숨은 탭 늦춤 견딤) / 90 s(빨리 풀림 · 숨은 탭이 잘못 풀릴 수 있음).
|
||||
@@ -0,0 +1,123 @@
|
||||
# 요구 404 — 검증 프로젝트 목록 · 고정안 · 지움 후보
|
||||
|
||||
읽기만(DB SELECT · 폴더 크기). 지운 것 없음. 기준 시각 2026-10-28.
|
||||
|
||||
## 1. 한눈에
|
||||
|
||||
| 갈래 | 개수 | 크기(MB) |
|
||||
| --- | --- | --- |
|
||||
| (a) OWNERS 표 13 (B 임도설계) | 13 | 40,962 |
|
||||
| (b) 창이 만든 검증 프로젝트 | 17 | 10,268 |
|
||||
| (c) 사용자 프로젝트 | 1 | 189 |
|
||||
| 합 | 31 | 51,419 |
|
||||
|
||||
- `projects` 31 행 · `deleted_at` 있는 행 0 · 종류 칸 = `project_kind`(ROAD · PLAN · STABILITY).
|
||||
- DB 행인데 폴더 없음 = 0 · 폴더인데 DB 행 없음 = 1(아래 4절).
|
||||
- 표 13 은 모두 `created_at` 2026-10-17 22:28 같은 시각(일괄 재생성 흔적) · 각 3.0~3.5 GB.
|
||||
- 종류별 — ROAD 17 · PLAN 7 · STABILITY 7(아래 표의 D·E).
|
||||
|
||||
## 2. (b) 창이 만든 검증 프로젝트 17
|
||||
|
||||
| id | 이름 | 종류 | 만든 창(이름 힌트) | 회사/사용자 | MB | 가이드 참조 | 상태 · 비고 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 7c34ad71 | 검증_브레인232 | B | 브레인(랩탑메인) | 1/엄상돈 | 3,456.4 | — | B03~B07 · 노선 20 · 횡단 1,158 · 표 밖 B |
|
||||
| 1a988dd2 | 검증_sub2b | B | sub2 | 1/엄상돈 | 3,038.5 | ✅ road | 가이드 임도설계 프로젝트 · 표 밖 B |
|
||||
| a59b04f5 | 검증_sub5_E | E | sub5 | 1/엄상돈 | 872.9 | — | 6 단계 COMPLETE · 원본 검증_sub5 |
|
||||
| 088e173d | 검증_sub7_E | E | sub7 | 1/엄상돈 | 868.7 | ✅ stab · E03 _scenes | 6 단계 COMPLETE · 원본 검증_sub7 |
|
||||
| 577224de | 검증_sub8_E | E | sub8 | 1/엄상돈 | 570.6 | — | 단계 행 5(STAB_AREA 없음 · 옛 생성) · 원본 검증_sub7 |
|
||||
| 7c5add34 | 검증_sub3_E | E | sub3 | 1/엄상돈 | 318.3 | — | E04 · E05 결과 있음 · 원본 검증_브레인232 |
|
||||
| 0b98c139 | 검증_sub6_E | E | sub6 | 1/엄상돈 | 298.5 | — | E04 일부 · 원본 검증_sub5 |
|
||||
| 3d250041 | 검증_브레인232 안정성평가 | E | 브레인 | 1/엄상돈 | 298.5 | — | E05 2.2 MB · 원본 검증_브레인232 |
|
||||
| a05e37a3 | 검증_sub1_D | D | sub1 | 1/엄상돈 | 142.5 | — | 지형 135 MB · _derived 7.4 |
|
||||
| 35cfc2ec | 검증_sub4_D | D | sub4 | **4/산림청검증** | 142.3 | — | 지형 134 MB · _derived 8.0 |
|
||||
| b8bc6cf3 | 검증_sub3_D | D | sub3 | **4/산림청검증** | 80.3 | — | 지형 79 MB · 노선분석 실호출 기록(plan 560-567) |
|
||||
| 1719997d | 검증_sub2_D | D | sub2 | 1/엄상돈 | 73.3 | — | 지형 73 MB · _derived 0 |
|
||||
| 87d47800 | 검증_sub7_D | D | sub7 | 1/엄상돈 | 67.6 | ✅ plan | 가이드 예정노선 프로젝트 |
|
||||
| a6cbeae2 | 검증_sub1_E | E | sub1 | 1/엄상돈 | 18.8 | — | E01 만 · 단계 모두 NOT_STARTED · 원본 검증_sub7 |
|
||||
| e6cc9463 | 검증_sub2_D 2026 | B | sub2(D04 확정 → B 넘김 시험) | **3/브레인관리자** | 10.3 | — | 빈 B · 원본 1719997d |
|
||||
| 24311f6d | 검증_sub2_D 2026 | B | sub2(위와 같은 이름 · 2 분 뒤 중복) | **3/브레인관리자** | 10.3 | — | 빈 B · 원본 1719997d |
|
||||
| b2eb210e | 검증_sub7_D2 | D | sub7 | 1/엄상돈 | 0.0 | — | 빈 껍데기(파일 0) |
|
||||
|
||||
- D 단계 행은 모두 NOT_STARTED(진척 기록 안 씀) — 완성도는 지형(B04_PreProcess) · `_derived` · `plan_base_json` 로 판단.
|
||||
- E 는 등록 때 원본 B 를 복사 — 등록 뒤 원본 B 를 읽지 않음(E02~E07 에 `source_project_id` 읽기 없음) · 원본 B 를 지워도 E 영향 없음.
|
||||
- D04 넘김 B(e6cc9463 · 24311f6d)는 원본 D 와 연결(`D04_PlanConfirm_Link`) — 1719997d 를 남기면 둘만 지워도 됨.
|
||||
- 회사 1 이 아닌 계정(회사 3 브레인관리자 · 회사 4 산림청검증)으로 만든 것 4 개 — 고정 시 계정 통일 검토.
|
||||
|
||||
## 3. (c) 사용자 프로젝트
|
||||
|
||||
| id | 이름 | 종류 | 회사/사용자 | MB | 비고 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 4250c7bc | 2026~2030 테스트 지역 간선임도 | D | 1/엄상돈 | 189.1 | 이름에 「테스트」 · 요구 389 실패 재현 원본 · 시험 `test_561_1` 머리글에 인용 — 판단 안 함 |
|
||||
|
||||
- 엄상준_검증(81339cc8) · 박동철_검증(eb717394)은 표 13 에 포함.
|
||||
|
||||
## 4. 고아 · 프로젝트 아닌 폴더
|
||||
|
||||
| 경로 | MB | 비고 |
|
||||
| --- | --- | --- |
|
||||
| `storage/3/15/d5fb1632-509f-4c15-9538-12bb54305c99` | 0.0 | DB 행 없음 · `initial_snapshot` 파일 1 개 — 지움 후보 |
|
||||
| `storage/4/16/` | 0.0 | 빈 사용자 폴더 |
|
||||
| `storage/1/{1,3,9,10}/templates` · `storage/3/{14,15}/templates` · `storage/1/templates` · `storage/1/assets` · `storage/1/3/library` | 약 20 | 개인·회사 양식 — 프로젝트 아님 · 손대지 않음 |
|
||||
|
||||
## 5. 큰 프로젝트 15
|
||||
|
||||
| 차례 | id | 이름 | 갈래 | MB |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | 12953f5a | 검증_sub3 | a | 3,462.3 |
|
||||
| 2 | 7c34ad71 | 검증_브레인232 | b | 3,456.4 |
|
||||
| 3 | 81339cc8 | 엄상준_검증 | a | 3,421.9 |
|
||||
| 4 | cb15892a | 검증_sub2 | a | 3,262.2 |
|
||||
| 5 | 916ea58c | 검증_sub1 | a | 3,219.0 |
|
||||
| 6 | c725d747 | 검증_sub4 | a | 3,119.6 |
|
||||
| 7 | dbf9f6d0 | 검증_sub5 | a | 3,099.4 |
|
||||
| 8 | 8b98ca75 | 검증_sub6 | a | 3,094.6 |
|
||||
| 9 | 9872e9a7 | 검증_sub8 | a | 3,076.2 |
|
||||
| 10 | 99fd7005 | 검증_sub7 | a | 3,060.0 |
|
||||
| 11 | dad81824 | 검증_랩탑메인 | a | 3,039.1 |
|
||||
| 12 | 1a988dd2 | 검증_sub2b | b(가이드) | 3,038.5 |
|
||||
| 13 | 38ebe4d8 | 검증_데스크탑서브 | a | 3,038.5 |
|
||||
| 14 | b69d9ffa | 검증_데스크탑메인 | a | 3,034.6 |
|
||||
| 15 | eb717394 | 박동철_검증 | a | 3,034.6 |
|
||||
|
||||
## 6. 고정안 — 창마다 B 1 · D 1 · E 1 + 가이드 1 벌
|
||||
|
||||
가이드 세트(`A05_EduDetail/guide/_projects.json`)는 창 검증과 따로 — 고치면 가이드 그림이 어긋남. 기본안 = 가이드 전용으로 묶고 이름을 `가이드_*` 로 바꿈.
|
||||
|
||||
| 가이드 | id | 지금 이름 | 제안 이름 |
|
||||
| --- | --- | --- | --- |
|
||||
| road | 1a988dd2 | 검증_sub2b | 가이드_임도설계 |
|
||||
| plan | 87d47800 | 검증_sub7_D | 가이드_예정노선 |
|
||||
| stab | 088e173d | 검증_sub7_E | 가이드_안정성평가 |
|
||||
|
||||
| 창 | B(표 그대로) | D 고정 | E 고정 |
|
||||
| --- | --- | --- | --- |
|
||||
| laptop-main | dad81824 | 새로 만듦 필요 | 3d250041(검증_브레인232 안정성평가 → 검증_랩탑메인_E) |
|
||||
| sub1 | 916ea58c | a05e37a3 검증_sub1_D | a6cbeae2 검증_sub1_E(E01 만 · 해석 전) |
|
||||
| sub2 | cb15892a | 1719997d 검증_sub2_D | 새로 만듦 필요 |
|
||||
| sub3 | 12953f5a | b8bc6cf3 검증_sub3_D(회사 4) | 7c5add34 검증_sub3_E |
|
||||
| sub4 | c725d747 | 35cfc2ec 검증_sub4_D(회사 4) | 새로 만듦 필요 |
|
||||
| sub5 | dbf9f6d0 | 새로 만듦 필요 | a59b04f5 검증_sub5_E(6 단계 완료) |
|
||||
| sub6 | 8b98ca75 | 새로 만듦 필요 | 0b98c139 검증_sub6_E |
|
||||
| sub7 | 99fd7005 | b2eb210e 검증_sub7_D2(빈 껍데기 → 검증_sub7_D 로 · 지형 다시 받음) | 새로 만듦 필요(옛 sub7_E 는 가이드로) |
|
||||
| sub8 | 9872e9a7 | 새로 만듦 필요 | 577224de 검증_sub8_E(⚠ STAB_AREA 단계 행 없음 → 새로 만듦이 나음) |
|
||||
| desktop-main | b69d9ffa | 새로 만듦 필요 | 새로 만듦 필요 |
|
||||
| desktop-sub | 38ebe4d8 | 새로 만듦 필요 | 새로 만듦 필요 |
|
||||
|
||||
- 새로 만듦 필요 — D 6(laptop-main · sub5 · sub6 · sub8 · desktop 둘) · E 5(sub2 · sub4 · sub7 · desktop 둘 · sub8 다시 만들면 6).
|
||||
- 다른 안(가이드 분리 안 함) — sub7 이 87d47800 · 088e173d 를 그대로 쓰고 b2eb210e 지움 · 대신 sub7 검증 때마다 가이드 그림 어긋남 위험.
|
||||
- 고정 뒤 OWNERS 표에 D · E 두 칸 더함(사용자 몫).
|
||||
|
||||
## 7. 지움 후보(지우지 않았음)
|
||||
|
||||
| id | 이름 | MB | 까닭 |
|
||||
| --- | --- | --- | --- |
|
||||
| 7c34ad71 | 검증_브레인232 | 3,456.4 | 표 밖 B · 랩탑메인은 dad81824 있음 · E 사본 둘은 원본 안 읽음 · 브레인 확인 뒤 |
|
||||
| e6cc9463 | 검증_sub2_D 2026 | 10.3 | D04 넘김 시험 B · 빈 B |
|
||||
| 24311f6d | 검증_sub2_D 2026 | 10.3 | 위와 같은 이름 중복 |
|
||||
| 577224de | 검증_sub8_E | 570.6 | sub8 E 를 새로 만들 때만(단계 행 모자람) |
|
||||
| b2eb210e | 검증_sub7_D2 | 0.0 | 가이드 분리 안 하는 안일 때만 |
|
||||
| (폴더) | `storage/3/15/d5fb1632…` | 0.0 | DB 행 없는 고아 |
|
||||
|
||||
- 확정 지움(위 셋 + 고아) = 약 3,477 MB · 조건부 둘 더하면 약 4,048 MB.
|
||||
- 지우는 길 = `common_util/common_util_project_delete.py` `hard_delete_project`(DB 행 연쇄 삭제 + 폴더) · storage 는 Synology 로 데스크탑에도 번짐 — 데스크탑 검증 사용자 쉴 때.
|
||||
- 가장 큰 덩어리는 표 13 의 B(약 41 GB · 각 3 GB) — 이번 범위 밖.
|
||||
Reference in New Issue
Block a user